<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://powershell.com/cs/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">Dreaming in PowerShell</title><subtitle type="html" /><id>http://powershell.com/cs/blogs/tobias/atom.aspx</id><link rel="alternate" type="text/html" href="http://powershell.com/cs/blogs/tobias/default.aspx" /><link rel="self" type="application/atom+xml" href="http://powershell.com/cs/blogs/tobias/atom.aspx" /><generator uri="http://communityserver.org" version="4.1.30929.2835">Community Server</generator><updated>2011-03-01T18:54:00Z</updated><entry><title>Regular Expressions Are Your Friend (Part 3)</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/12/02/regular-expressions-are-your-friend-part-3.aspx" /><id>/cs/blogs/tobias/archive/2011/12/02/regular-expressions-are-your-friend-part-3.aspx</id><published>2011-12-02T12:27:00Z</published><updated>2011-12-02T12:27:00Z</updated><content type="html">&lt;p&gt;In &lt;a target="_blank" href="http://powershell.com/cs/blogs/tobias/archive/2011/10/27/regular-expressions-are-your-friend-part-1.aspx"&gt;Part 1&lt;/a&gt;, you lerned how Regular Expressions can extract useful information from noise text. In &lt;a target="_blank" href="http://powershell.com/cs/blogs/tobias/archive/2011/11/14/regular-expressions-are-your-friend-part-2.aspx"&gt;Part 2&lt;/a&gt;, we looked at using Regular Expressions to split text, yet another powerful technique to extract the pieces of information you may need. Today, we conclude our little excurse and use Regular Expressions to &lt;strong&gt;replace text&lt;/strong&gt;. Fasten your seat belts, please!&lt;/p&gt;
&lt;h3&gt;Replacing Old Text With New Stuff&lt;/h3&gt;
&lt;p&gt;Replacing some information inside a text with some other information seems to be pretty straight-forward: simply use &lt;strong&gt;-replace&lt;/strong&gt; and tell the operator which text you would like to replace with other text:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;#39;Hello World!&amp;#39; -replace &amp;#39;World&amp;#39;, &amp;#39;PowerShell&amp;#39;&lt;br /&gt;Hello PowerShell!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is not obvious at first that &lt;strong&gt;-replace&lt;/strong&gt; in reality takes a Regular Expression. You may notice accidentally when you try and use characters that have a special meaning, like here:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;#39;Hello.&amp;#39; -replace &amp;#39;.&amp;#39;, &amp;#39;!&amp;#39;&lt;br /&gt;!!!!!!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Huh? Well, &amp;quot;.&amp;quot; is a special RegEx placeholder and represents any character, so the result is right. If you must use &lt;strong&gt;special characters&lt;/strong&gt;, they &lt;strong&gt;need to be escaped&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;#39;Hello.&amp;#39; -replace &amp;#39;\.&amp;#39;, &amp;#39;!&amp;#39;&lt;br /&gt;Hello!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Remember the trick from our previous parts? If you aren&amp;#39;t sure which characters need to be escaped, ask PowerShell!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; [RegEx]::Escape(&amp;#39;Hello.&amp;#39;)&lt;br /&gt;Hello\.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Eliminating Duplicates&lt;/h3&gt;
&lt;p&gt;Being able to use Regular Expressions does add the burden of escaping, but at the same time it adds incredible power. Let&amp;#39;s assume you want to &lt;strong&gt;get rid of excessive whitespace&lt;/strong&gt; and replace multiple whitespace with just one space. Here is the solution:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;Too&amp;nbsp;&amp;nbsp; many&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; blank&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; characters&amp;#39;&lt;br /&gt;PS&amp;gt; $text -replace &amp;#39;\s{2,}&amp;#39;, &amp;#39; &amp;#39;&lt;br /&gt;Too many blank characters&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here, &lt;strong&gt;-replace&lt;/strong&gt; was looking for any whitespace (placeholder: &lt;strong&gt;\s&lt;/strong&gt;) that occurs at least 2 times (quantifier: &lt;strong&gt;{2,}&lt;/strong&gt;). It then replaces these instances with a single space. Done.&lt;/p&gt;
&lt;h3&gt;Using The Match&lt;/h3&gt;
&lt;p&gt;Your new replacement text does not need to be static. It can &lt;strong&gt;reference the original match&lt;/strong&gt;. Have a look:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;The problem was described in KB123456. Look it up.&amp;#39;&lt;br /&gt;PS&amp;gt; $pattern = &amp;#39;KB\d{6,8}&amp;#39;&lt;br /&gt;PS&amp;gt; $text -replace $pattern, &amp;#39;a KB-Article ($0 to be precise)&amp;#39;&lt;br /&gt;The problem was described in a KB-Article (KB123456 to be precise). Look it up.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here, we define a pattern for KB article numbers. The replacement string contains a placeholder (&lt;strong&gt;$0&lt;/strong&gt;). This placeholder &lt;strong&gt;seems to be a PowerShell variable&lt;/strong&gt;, but it is not. It &lt;strong&gt;just looks like one&lt;/strong&gt;, which is why you &lt;strong&gt;must&lt;/strong&gt; use single quotes or else PowerShell would also interpret this as a variable and resolve it.&lt;/p&gt;
&lt;p&gt;What exactly is &lt;strong&gt;$0&lt;/strong&gt;? To explain this, take a look at the result returned by &lt;strong&gt;-match&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;The problem was described in KB123456. Look it up.&amp;#39;&lt;br /&gt;PS&amp;gt; $pattern = &amp;#39;KB\d{6,8}&amp;#39;&lt;br /&gt;PS&amp;gt; $text -match $pattern&lt;br /&gt;True&lt;br /&gt;PS&amp;gt; $matches&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Value&lt;br /&gt;----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----&lt;br /&gt;0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; KB123456&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As it turns out,&lt;strong&gt; $matches&lt;/strong&gt; returns a match with the name &amp;quot;0&amp;quot;, so this match is what &lt;strong&gt;$0&lt;/strong&gt; represents. &lt;/p&gt;
&lt;p&gt;If you use &lt;strong&gt;grouping&lt;/strong&gt; in your pattern (place parts of it in brackets), then you have even more choices:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;The problem was described in KB123456. Look it up.&amp;#39;&lt;br /&gt;PS&amp;gt; $pattern = &amp;#39;KB(\d{6,8})&amp;#39;&lt;br /&gt;PS&amp;gt; $text -match $pattern&lt;br /&gt;True&lt;br /&gt;PS&amp;gt; $matches&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Value&lt;br /&gt;----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 123456&lt;br /&gt;0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; KB123456&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, &lt;strong&gt;-replace&lt;/strong&gt; would support both the placeholders &lt;strong&gt;$0&lt;/strong&gt; and &lt;strong&gt;$1&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;The problem was described in KB123456. Look it up.&amp;#39;&lt;br /&gt;PS&amp;gt; $pattern = &amp;#39;KB(\d{6,8})&amp;#39;&lt;br /&gt;PS&amp;gt; $text -replace $pattern, &amp;#39;a KB-Article (with number $1 to be precise)&amp;#39;&lt;br /&gt;The problem was described in a KB-Article (with number 123456 to be precise). Look it up.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Using Backreferences&lt;/h3&gt;
&lt;p&gt;What you have just seen is often called &amp;quot;backreference&amp;quot;: your new replacement text is &lt;strong&gt;backreferencing the original text&lt;/strong&gt;. That technique can be extremely versatile. Let&amp;#39;s say you want to make sure &lt;strong&gt;each comma in a text is followed by a space&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Here is a solution that uses backreferences:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;After each comma,I want a whitespace,but only if there was no whitespace in the first place, of course.&amp;#39;&lt;br /&gt;PS&amp;gt; $text -replace&amp;nbsp; &amp;#39;,(\S)&amp;#39;, &amp;#39;, $1&amp;#39;&lt;br /&gt;After each comma, I want a whitespace, but only if there was no whitespace in the first place, of course.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The pattern looks for a comma that is immediately followed by a non-whitespace (placeholder: &lt;strong&gt;/S&lt;/strong&gt; - watch out, placeholders are &lt;strong&gt;case-sensitive&lt;/strong&gt;!). If that was found, it is replaced by a comma, a space and then the backreference (which is the character that previously immediately followed the comma). Mission accomplished. Thank you, backreferences!&lt;/p&gt;
&lt;h3&gt;Finding Duplicates - Backreferences In Your Pattern&lt;/h3&gt;
&lt;p&gt;You can even find and eliminate unwanted duplicates. Here is some sample code for you:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;this text text contains duplicate words words following each other&amp;#39;&lt;br /&gt;PS&amp;gt; $text -replace &amp;#39;\b(\w+)(\s+\1){1,}\b&amp;#39;, &amp;#39;$1&amp;#39;&lt;br /&gt;this text contains duplicate words following each other&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this case, &lt;strong&gt;the original pattern&lt;/strong&gt; itself uses backreferences, too. It looks for a word boundary (placeholder: &lt;strong&gt;\b&lt;/strong&gt;) and then for a word (&lt;strong&gt;\w+&lt;/strong&gt;). Note that the word pattern is in brackets, so it is the first group with the index &lt;strong&gt;1&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Then, it looks for at least one space and the same word again (placeholder: &lt;strong&gt;\1&lt;/strong&gt;). So it is backreferencing the first group match. The quantifier (&lt;strong&gt;{1,}&lt;/strong&gt;) tells RegEx that we are looking for one or more duplicate words. &lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;-replace&lt;/strong&gt; operator then replaces all of this with the backreference to the first word, thus eliminating all the duplicate words.&lt;/p&gt;
&lt;p&gt;So if you want to backreference matches in your replacement text, you prefix the group number with a &lt;strong&gt;$&lt;/strong&gt;. If you want to backreference matches in your pattern, prefix the index with &lt;strong&gt;\&lt;/strong&gt; instead.&lt;/p&gt;
&lt;h3&gt;Capitalizing First Letter in a Word&lt;/h3&gt;
&lt;p&gt;Every now and then, even Regular Expressions can&amp;#39;t do the job, so PowerShell scriptblocks can assist. Let&amp;#39;s assume you want to &lt;strong&gt;capitalize every first letter in every word&lt;/strong&gt;. Identifying the first letter is easy, but &lt;strong&gt;Regular Expressions cannot capitalize characters&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;That&amp;#39;s why you can &lt;strong&gt;submit a PowerShell script block&lt;/strong&gt; that tells RegEx what to do with the match. Here is a sample:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;i want to capitalize every word in this sentence.&amp;#39;&lt;br /&gt;PS&amp;gt; $pattern = &amp;#39;\b(\w)&amp;#39;&lt;br /&gt;PS&amp;gt; [RegEx]::Replace($text, $pattern, { param($letter) $letter.Value.toUpper() })&lt;br /&gt;I Want To Capitalize Every Word In This Sentence.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since &lt;strong&gt;-replace&lt;/strong&gt; cannot process PowerShell script blocks, you need to use .NET directly here. The pattern describes a word boundary (placeholder: &lt;strong&gt;\b&lt;/strong&gt;) and then the immediately following first character (placeholder: &lt;strong&gt;\w&lt;/strong&gt;). Note that this placeholder is placed in brackets, so it is the first group.&lt;/p&gt;
&lt;p&gt;Next, this sample uses the .NET class &lt;strong&gt;[RegEx]&lt;/strong&gt; and its &lt;strong&gt;Replace()&lt;/strong&gt; method which is the same dog food &lt;strong&gt;-replace&lt;/strong&gt; uses internally, too. This time, though, a script block is submitted as replacement text. &lt;/p&gt;
&lt;p&gt;This script block is often called a &amp;quot;&lt;strong&gt;delegate&lt;/strong&gt;&amp;quot; because it is called for each match and determines the replacement dynamically. It receives the match through a &lt;strong&gt;param()&lt;/strong&gt; block and then can use whatever logic you want to return the replacement text. In our case, it simply converts the received letter to uppercase.&lt;/p&gt;
&lt;h3&gt;What&amp;rsquo;s Next?&lt;/h3&gt;
&lt;p&gt;We are done with our tour of PowerShells&amp;#39; RegEx support. Next time, we check out &lt;strong&gt;hashtables&lt;/strong&gt; and the clever things you can do with them. Hashtables are really everywhere in PowerShell, but they are a little shy, so you won&amp;#39;t see them at first. Knowing about hashtables, how they work and what can be done with them&amp;nbsp;will get you a lot more control over PowerShell. I am sure you&amp;#39;ll be surprised! Stay tuned...&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=13446" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Replace" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Replace/default.aspx" /><category term="-replace" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/-replace/default.aspx" /><category term="Regular Expression" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Regular+Expression/default.aspx" /><category term="RegEx" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/RegEx/default.aspx" /><category term="delegate" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/delegate/default.aspx" /></entry><entry><title>Regular Expressions Are Your Friend (Part 2)</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/11/14/regular-expressions-are-your-friend-part-2.aspx" /><id>/cs/blogs/tobias/archive/2011/11/14/regular-expressions-are-your-friend-part-2.aspx</id><published>2011-11-14T10:37:00Z</published><updated>2011-11-14T10:37:00Z</updated><content type="html">&lt;p&gt;In &lt;a target="_blank" href="http://powershell.com/cs/blogs/tobias/archive/2011/10/27/regular-expressions-are-your-friend-part-1.aspx"&gt;Part 1&lt;/a&gt;, we used &lt;strong&gt;Regular Expressions&lt;/strong&gt; to extract useful information from noise text. That was pretty cool, and we used the operator &lt;strong&gt;-match&lt;/strong&gt;, the automatic PowerShell variable &lt;strong&gt;$matches&lt;/strong&gt; and the powerful &lt;strong&gt;Get-Matches&lt;/strong&gt; function.&lt;/p&gt;
&lt;p&gt;Today, we&amp;#39;ll use Regular Expressions again, but this time they are used&amp;nbsp;to split text. &lt;/p&gt;
&lt;h3&gt;Chopping Text Into Pieces&lt;/h3&gt;
&lt;p&gt;Regular Expressions can be your &lt;strong&gt;butchers&amp;#39; knife to split text&lt;/strong&gt; into pieces. Why on earth would you like do that, though? &lt;/p&gt;
&lt;p&gt;For example, to process a comma-separated list of values. Have a look:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;#39;comma,separated,list&amp;#39; -split &amp;#39;,&amp;#39;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here, the operator &lt;strong&gt;-split&lt;/strong&gt; takes the text on its left side and chops the text up at each comma it finds. Yes, Regular Expressions do not need to be monsters. They can be very small. In this case, our Regular Expression simply is the comma - and represents a comma. It is - uh - a placeholder for - a comma. Easy enough. &lt;/p&gt;
&lt;p&gt;You now could pipe the results to &lt;strong&gt;Foreach-Object&lt;/strong&gt; and do stuff for all the elements in your comma-separated list:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;$computers = &amp;#39;pc1,pc2,server12,serverAB&amp;#39;&lt;br /&gt;$computers -split &amp;#39;,&amp;#39; | Foreach-Object { &amp;quot;I am doing something with $_&amp;quot; }&lt;br /&gt;I am doing something with pc1&lt;br /&gt;I am doing something with pc2&lt;br /&gt;I am doing something with server12&lt;br /&gt;I am doing something with serverAB&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;$computers -split &amp;#39;,&amp;#39; | Foreach-Object {&amp;nbsp;Get-WMIObject Win32_BIOS -computername $_&amp;nbsp;}&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can also use splitting to take apart &lt;strong&gt;path names&lt;/strong&gt;. Here, the pattern is the backslash (if you want the parts of the path) or a dot (if you are after the &lt;strong&gt;file extension&lt;/strong&gt;). This time, however, the pattern to use is not as straight-forward. Both the backslash and the dot are &lt;strong&gt;special characters in Regular Expressions&lt;/strong&gt;. So if you really mean a backslash or a dot, you need to &lt;strong&gt;escape them&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;#39;c:\windows\file.txt&amp;#39; -split &amp;#39;\.&amp;#39;&lt;br /&gt;c:\windows\file&lt;br /&gt;txt&lt;br /&gt;PS&amp;gt; (&amp;#39;c:\windows\file.txt&amp;#39; -split &amp;#39;\.&amp;#39;)[-1]&lt;br /&gt;txt&lt;br /&gt;PS&amp;gt; &amp;#39;c:\windows\file.txt&amp;#39; -split &amp;#39;\\&amp;#39;&lt;br /&gt;c:&lt;br /&gt;windows&lt;br /&gt;file.txt&lt;br /&gt;PS&amp;gt; (&amp;#39;c:\windows\file.txt&amp;#39; -split &amp;#39;\\&amp;#39;)[-1]&lt;br /&gt;file.txt&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Escaping Regular Expressions&lt;/h3&gt;
&lt;p&gt;As you have just discovered, sometimes it is necessary to escape characters in Regular Expressions so they are taken literally. &lt;/p&gt;
&lt;p&gt;Fortunately, there is a way to &lt;strong&gt;automatically escape characters&lt;/strong&gt;. If you aren&amp;#39;t sure if something you mean literally should indeed be escaped or not, try using this trick:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; [Regex]::Escape(&amp;#39;c:\folder\file.txt&amp;#39;)&lt;br /&gt;c:\\folder\\file\.txt&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It takes the text you provide and returns it in escaped form so Regular Expressions wouldn&amp;#39;t treat anything in that text as special characters.&lt;/p&gt;
&lt;h3&gt;Splitting Without Consuming&lt;/h3&gt;
&lt;p&gt;By default, when you chop up text using &lt;strong&gt;-split&lt;/strong&gt;, the split character(s) are &amp;quot;consumed&amp;quot;, so they are gone after the split. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;This text gets splitted, and the delimiter is by default consumed, as you can see&amp;#39;&lt;br /&gt;PS&amp;gt; $text -split &amp;#39;,&amp;#39;&lt;br /&gt;This text gets splitted&lt;br /&gt;&amp;nbsp;and the delimiter is by default consumed&lt;br /&gt;&amp;nbsp;as you can see&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With look-behind expressions, you can make sure that the splitting pattern is not consumed:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text -split &amp;#39;(?&amp;lt;=, )&amp;#39;&lt;br /&gt;This text gets splitted,&lt;br /&gt;and the delimiter is by default consumed,&lt;br /&gt;as you can see&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Basically, &amp;quot;?&amp;lt;=&amp;quot; tells the RegEx engine to split &lt;em&gt;right after&lt;/em&gt; the splitting character. Splitting without consuming can become important as you&amp;#39;ll see in a second.&lt;/p&gt;
&lt;h3&gt;Separating Hex-Pairs&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s assume you have a long &lt;strong&gt;list of hexadecimal pairs &lt;/strong&gt;and would like to &lt;strong&gt;convert&lt;/strong&gt; that list back to &lt;strong&gt;decimals&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;#39;00AB1CFFAB1034&amp;#39; &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To do that, you would somehow have to split after every second character and without consuming because you do not want to loose any information. Here is how you solve this puzzle:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;#39;00AB1CFFAB1034&amp;#39; -split &amp;#39;(?&amp;lt;=\G[0-9a-f]{2})(?=.)&amp;#39;&lt;br /&gt;00&lt;br /&gt;AB&lt;br /&gt;1C&lt;br /&gt;FF&lt;br /&gt;AB&lt;br /&gt;10&lt;br /&gt;34&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now you can pipe the pairs to &lt;strong&gt;Foreach-Object&lt;/strong&gt; and convert them to decimals or bytes or whatever you may need:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;#39;00AB1CFFAB1034&amp;#39; -split &amp;#39;(?&amp;lt;=\G[0-9a-f]{2})(?=.)&amp;#39; | &lt;br /&gt;&amp;nbsp; Foreach-Object { [System.Convert]::ToInt32($_, 16) }&lt;br /&gt;0&lt;br /&gt;171&lt;br /&gt;28&lt;br /&gt;255&lt;br /&gt;171&lt;br /&gt;16&lt;br /&gt;52&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;#39;00AB1CFFAB1034&amp;#39; -split &amp;#39;(?&amp;lt;=\G[0-9a-f]{2})(?=.)&amp;#39; | &lt;br /&gt;&amp;nbsp; Foreach-Object { [System.Convert]::ToByte($_, 16) }&lt;br /&gt;0&lt;br /&gt;171&lt;br /&gt;28&lt;br /&gt;255&lt;br /&gt;171&lt;br /&gt;16&lt;br /&gt;52&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Whew, wait a minute! This time, the Regular Expression wasn&amp;#39;t as simple anymore. Right. &lt;strong&gt;Regular Expressions aren&amp;#39;t hated without a reason&lt;/strong&gt;. Sometimes they become tricky little monsters with mind-blowing &lt;strong&gt;lookaheads&lt;/strong&gt;, &lt;strong&gt;lookbehinds&lt;/strong&gt; and &lt;strong&gt;lookarounds&lt;/strong&gt;. But is that a reason not to use them? No! We all use microwaves to make popcorn, but do we care about the physics? I don&amp;#39;t.&lt;/p&gt;
&lt;p&gt;So always remember: you do not need to care about Regular Expression mechanics once you have one&amp;nbsp;that does what you&amp;nbsp;want it to do. So once you have a Regular Expression that splits Hex-Pairs, you are good. Simply use it. &lt;/p&gt;
&lt;p&gt;Instead of spending frustrating hours of crafting complex RegEx patterns, think &amp;quot;code reuse&amp;quot; and visit a search engine like google.Look for &amp;quot;RegEx &amp;lt;Pattern&amp;gt;&amp;quot;, for example &amp;quot;RegEx IPAddress&amp;quot;. Chances are someone else has already done the dirty job for you, and all you need to do is &lt;strong&gt;copy and paste the RegEx pattern&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;If you do want to digest patterns and really understand what is going on, there are plenty of &lt;strong&gt;great RegEx tutorial sites&lt;/strong&gt;. This one explains lookbehinds, lookaheads and lookarounds and helps you understand the previous example: &lt;a target="_blank" href="http://www.regular-expressions.info/lookaround.html"&gt;http://www.regular-expressions.info/lookaround.html&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;What&amp;rsquo;s Next?&lt;/h3&gt;
&lt;p&gt;We covered -match and -split, but there&amp;#39;s a third family member: -replace. So next time we&amp;#39;ll continue talking about RegEx and look how you can replace things, update IP lists and more. Meanwhile, if you have spare time, go visit some of the plenty sites that focus on RegEx, and try and refine your understanding of RegEx placeholders, anchors and quantifiers. Stay tuned!&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=13228" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Split" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Split/default.aspx" /><category term="path" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/path/default.aspx" /><category term="Convert" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Convert/default.aspx" /><category term="-match" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/-match/default.aspx" /><category term="Regular Expression" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Regular+Expression/default.aspx" /><category term="RegEx" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/RegEx/default.aspx" /><category term="-split" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/-split/default.aspx" /><category term="splitting" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/splitting/default.aspx" /><category term="hexadecimal" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/hexadecimal/default.aspx" /></entry><entry><title>Regular Expressions Are Your Friend (Part 1)</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/10/27/regular-expressions-are-your-friend-part-1.aspx" /><id>/cs/blogs/tobias/archive/2011/10/27/regular-expressions-are-your-friend-part-1.aspx</id><published>2011-10-27T02:04:00Z</published><updated>2011-10-27T02:04:00Z</updated><content type="html">&lt;p&gt;Yes,&amp;nbsp;&lt;strong&gt;regular expressions&lt;/strong&gt;&amp;nbsp;can be complex but hey no, they do not need to be! You can do amazing things with small and relatively simple regular expressions. So let&amp;rsquo;s take a look at it.&lt;/p&gt;
&lt;h3&gt;Finding Information: -match&lt;/h3&gt;
&lt;p&gt;Often, you need &lt;strong&gt;some piece of information&lt;/strong&gt; that is buried inside of noise text. Let&amp;rsquo;s assume you&amp;rsquo;d like to find the &lt;strong&gt;KB article number&lt;/strong&gt; that is in this text:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text = &amp;#39;The problem was discussed in KB552356 and is solved. KB652534 was not addressed.&amp;#39;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Regular expressions can do this for you. All you need to do is &lt;strong&gt;define the pattern&lt;/strong&gt; you are looking for. Here is a sample pattern that identifies KB article numbers:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $pattern = &amp;#39;KB\d{4,6}&amp;#39;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before we look at the pattern and how it is constructed, let&amp;rsquo;s see results. PowerShell has an operator called &lt;strong&gt;&amp;ndash;match&lt;/strong&gt; that takes regular expressions and returns &lt;strong&gt;$true&lt;/strong&gt; when it found the pattern in the text:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text -match $pattern&lt;br /&gt;True&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If there was a match, you even get back the expression that matched your pattern in the automatic variable &lt;strong&gt;$matches&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $matches&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Value&lt;br /&gt;----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----&lt;br /&gt;0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; KB552356&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; if ($text -match $pattern) { $matches[0] }&lt;br /&gt;KB552356&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;How Patterns Work&lt;/h3&gt;
&lt;p&gt;Regular expression patterns basically contain three things: &lt;strong&gt;anchors, placeholders, and quantifiers&lt;/strong&gt;. In the pattern we used, we had all three elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;KB&amp;rdquo; was an anchor. It expected the pattern to start at the static text &amp;ldquo;KB&amp;rdquo;. &lt;/li&gt;
&lt;li&gt;\d is a placeholder. It represents a digit.&lt;/li&gt;
&lt;li&gt;{4,6} is a quantifier. It expects the placeholder to occur four to six times, so it matches 4 to 6 digits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s not too hard, eh?&lt;/p&gt;
&lt;h3&gt;Creating Groups&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s assume you are just interested in the number of the KB article. To get &lt;strong&gt;just the number&lt;/strong&gt;, you can &lt;strong&gt;create groups&lt;/strong&gt; by using parenthesis.&lt;/p&gt;
&lt;p&gt;Here is the refined pattern:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $pattern = &amp;#39;KB(\d{4,6})&amp;#39;&lt;br /&gt;PS&amp;gt; $text -match $pattern&lt;br /&gt;True&lt;br /&gt;PS&amp;gt; $matches&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Value&lt;br /&gt;----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 552356&lt;br /&gt;0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; KB552356&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here, &lt;strong&gt;$matches returns two results&lt;/strong&gt;. Index 0 holds the complete match, and index 1 holds the match of the first group. It contains just the number of the KB article.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; if ($text -match $pattern) { $matches[1] }&lt;br /&gt;552356&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Finding Multiple Matches&lt;/h3&gt;
&lt;p&gt;Unfortunately, &lt;strong&gt;-match only finds the first match&lt;/strong&gt;. That&amp;rsquo;s why it is called &lt;strong&gt;&amp;ndash;match&lt;/strong&gt; and not &lt;strong&gt;&amp;ndash;matches&lt;/strong&gt;. And this is also why it only found the first KB article number in the sample text, not the second one.&lt;/p&gt;
&lt;p&gt;There is a built-in way in PowerShell to find multiple matches, but it is somewhat hidden. &lt;strong&gt;Select-String&lt;/strong&gt; can find multiple matches:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text | Select-String -AllMatches $pattern&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The problem was discussed in KB552356 and is solved. KB652534 was not addressed.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, the result is the entire text. Only when you poke in the results will you get the individual matches:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text | Select-String -AllMatches $pattern | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value&lt;br /&gt;KB552356&lt;br /&gt;KB652534&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since that&amp;rsquo;s not really beautiful, you can create your own filter and use it to extract multiple matches:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;filter Get-Matches($Pattern) {&lt;br /&gt;$_ | Select-String -AllMatches $pattern | &lt;br /&gt;&amp;nbsp; Select-Object -ExpandProperty Matches | &lt;br /&gt;&amp;nbsp; Select-Object -ExpandProperty Value &lt;br /&gt;}&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text | Get-Matches $pattern&lt;br /&gt;KB552356&lt;br /&gt;KB652534&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Your filter is pretty flexible. You can use it for example to &lt;strong&gt;parse entire log files&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; Get-Content $env:windir\windowsupdate.log -Encoding UTF8 |&lt;br /&gt;&amp;gt;&amp;gt;&amp;nbsp;&amp;nbsp; Get-Matches &amp;#39;successfully installed.*?update:.*&amp;#39;&lt;br /&gt;&amp;gt;&amp;gt;&lt;br /&gt;successfully installed the following update: Microsoft Silverlight (KB979202)&lt;br /&gt;successfully installed the following update: Security Update for Windows 7 for x64-based&lt;br /&gt;Systems (KB2532531)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(...)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Check the pattern used here:&lt;/p&gt;
&lt;p&gt;We have an &lt;strong&gt;anchor&lt;/strong&gt; (&amp;lsquo;successfully installed&amp;rsquo;), then a &lt;strong&gt;placeholder&lt;/strong&gt; (&amp;lsquo;.&amp;rsquo;=anything) with a &lt;strong&gt;quantifier&lt;/strong&gt; (&amp;lsquo;*?&amp;rsquo; = any number, but as short as possible), then another anchor (&amp;lsquo;update&amp;rsquo;), and then again a placeholder (&amp;lsquo;.&amp;rsquo; = anything) with a quantifier (&amp;lsquo;*&amp;rsquo; = any number).&lt;/p&gt;
&lt;p&gt;Essentially, this extracts all lines from the log file where updates were installed.&lt;/p&gt;
&lt;h3&gt;Finding Multiple Matches Fast&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Select-String&lt;/strong&gt; is rather slow, though. To retrieve multiple matches, &lt;strong&gt;using .NET directly&lt;/strong&gt; speeds up things considerably. Here&amp;rsquo;s the &lt;strong&gt;Get-Matches &lt;/strong&gt;function as a .NET implementation:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;function Get-Matches($Pattern) { &lt;br /&gt;&amp;nbsp; begin { $regex = New-Object Regex($pattern) }&lt;br /&gt;&amp;nbsp; process { foreach ($match in ($regex.Matches($_))) { ([Object[]]$match.Groups)[-1].Value } }&lt;br /&gt;}&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; Get-Content $env:windir\windowsupdate.log -Encoding UTF8 | Get-Matches &amp;#39;successfully installed.*?update:.*&amp;#39;&lt;br /&gt;successfully installed the following update: Microsoft Silverlight (KB979202)&lt;br /&gt;successfully installed the following update: Security Update for Windows 7 for&lt;br /&gt;x64-based Systems (KB2532531)&lt;br /&gt;successfully installed the following update: Update for Windows 7 for x64-based&lt;br /&gt;&amp;nbsp;Systems (KB2533623)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(...)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is not just a lot faster, it &lt;strong&gt;also supports grouping&lt;/strong&gt;, so if you just wanted the product name that was installed, place the last placeholder-expression into parenthesis. &lt;strong&gt;Get-Matches&lt;/strong&gt; always returns the last group:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; Get-Content $env:windir\windowsupdate.log -Encoding UTF8 | Get-Matches &amp;#39;successfully installed.*?update: (.*)&amp;#39;&lt;br /&gt;Microsoft Silverlight (KB979202)&lt;br /&gt;Security Update for Windows 7 for x64-based Systems (KB2532531)&lt;br /&gt;Update for Windows 7 for x64-based Systems (KB2533623)&lt;br /&gt;Security Update for Windows 7 for x64-based Systems (KB2507938)&lt;br /&gt;Security Update for Windows 7 for x64-based Systems (KB2555917)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Clever RegEx Matching &lt;/h3&gt;
&lt;p&gt;To make life much easier, here&amp;rsquo;s a function that returns regular expression matches as real PowerShell objects:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;function Get-Matches {&lt;br /&gt;&amp;nbsp; param(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [Parameter(Mandatory=$true)]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Pattern,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [Parameter(ValueFromPipeline=$true)]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $InputObject&lt;br /&gt;&amp;nbsp; )&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;begin {&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;$regex = New-Object Regex($pattern) &lt;br /&gt;&amp;nbsp;&amp;nbsp;} &lt;br /&gt;&amp;nbsp;&amp;nbsp;catch {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Throw &amp;quot;Get-Matches: Pattern not correct. &amp;#39;$Pattern&amp;#39; is no valid regular expression.&amp;quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;$groups = @($regex.GetGroupNames() | &lt;br /&gt;&amp;nbsp;&amp;nbsp;Where-Object { ($_ -as [Int32]) -eq $null } |&lt;br /&gt;&amp;nbsp;&amp;nbsp;ForEach-Object { $_.toString() })&lt;br /&gt;&amp;nbsp;} &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;nbsp;process { &lt;br /&gt;&amp;nbsp;&amp;nbsp;foreach ($line in $InputObject) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;foreach ($match in ($regex.Matches($line))) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ($groups.Count -eq 0) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;([Object[]]$match.Groups)[-1].Value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$rv = 1 | Select-Object -Property $groups&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$groups | ForEach-Object {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$rv.$_ = $match.Groups[$_].Value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$rv&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;/em&gt;&lt;em&gt;&amp;nbsp;}&lt;br /&gt;}&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, if you&amp;rsquo;d like to extract information, you could use it like this:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;quot;KB2786873 good&amp;nbsp; KB27897983&amp;nbsp;&amp;nbsp; bad &amp;quot; | Get-Matches &amp;#39;KB\d{4,8}&amp;#39;&lt;br /&gt;KB2786873&lt;br /&gt;KB27897983&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You could also &lt;strong&gt;create named groups&lt;/strong&gt; which you do by adding &lt;strong&gt;?&amp;lt;Name&amp;gt;&lt;/strong&gt; to your parenthesis. Then, &lt;strong&gt;Get-Matches&lt;/strong&gt; automatically turns these groups into object properties:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; &amp;quot;KB2786873 good&amp;nbsp; KB27897983&amp;nbsp;&amp;nbsp; bad &amp;quot; | Get-Matches &amp;#39;.*?(?&amp;lt;KB&amp;gt;KB\d{4,8}).*?(?&amp;lt;&lt;br /&gt;word&amp;gt;\w+)&amp;#39;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;KB&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;word&lt;br /&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ----&lt;br /&gt;KB2786873&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;good&lt;br /&gt;KB27897983&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bad&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Take a look how easily you now can parse a raw text file and turn it into real PowerShell objects! First read the log file:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;$text = Get-Content $env:windir\windowsupdate.log -Encoding UTF8 -ReadCount 0&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Next,&amp;nbsp; &lt;strong&gt;try a couple of RegEx patterns&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text | Get-Matches &amp;#39;successfully installed.*?update: (.*)&amp;#39;&lt;br /&gt;Microsoft Silverlight (KB979202)&lt;br /&gt;Security Update for Windows 7 for x64-based Systems (KB2532531)&lt;br /&gt;Update for Windows 7 for x64-based Systems (KB2533623)&lt;br /&gt;Security Update for Windows 7 for x64-based Systems (KB2507938)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(...)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text | Get-Matches &amp;#39;successfully installed.*?update: (?&amp;lt;Product&amp;gt;.*)&amp;#39;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Product&lt;br /&gt;-------&lt;br /&gt;Microsoft Silverlight (KB979202)&lt;br /&gt;Security Update for Windows 7 for x64-based Systems (KB2532531)&lt;br /&gt;Update for Windows 7 for x64-based Systems (KB2533623)&lt;br /&gt;Security Update for Windows 7 for x64-based Systems (KB2507938)&lt;br /&gt;Security Update for Windows 7 for x64-based Systems (KB2555917)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(...)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text | Get-Matches &amp;#39;(?&amp;lt;Date&amp;gt;\d{4}-\d{2}-\d{2}).*?(?&amp;lt;Time&amp;gt;\d{2}:\d{2}:\d{2}).*?successfully installed.*?update: (?&amp;lt;Product&amp;gt;.*)&amp;#39;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Date&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Time&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Product&lt;br /&gt;----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -------&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:05:46&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Microsoft Silverlight ...&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update for Wi...&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Update for Windows 7 f...&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update for Wi...&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update for Wi...&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(...)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; $text | Get-Matches &amp;#39;(?&amp;lt;Date&amp;gt;\d{4}-\d{2}-\d{2}).*?(?&amp;lt;Time&amp;gt;\d{2}:\d{2}:\d{2}).*?successfully installed.*?update: (?&amp;lt;Product&amp;gt;.*?) \({0,1}KB(?&amp;lt;KB&amp;gt;\d{5,8})&amp;#39;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Date&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Time&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Product&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; KB&lt;br /&gt;----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -------&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; --&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:05:46&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Microsoft Silver... 979202&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update ... 2532531&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Update for Windo... 2533623&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update ... 2507938&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update ... 2555917&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(...)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS&amp;gt; Get-Content $env:windir\windowsupdate.log -Encoding UTF8 -ReadCount 0 | Get-Matches &amp;#39;(?&amp;lt;Date&amp;gt;\d{4}-\d{2}-\d{2}).*?(?&amp;lt;Time&amp;gt;\d{2}:\d{2}:\d{2}).*?successfullyinstalled.*?update: (?&amp;lt;Product&amp;gt;.*?) \({0,1}KB(?&amp;lt;KB&amp;gt;\d{5,8})&amp;#39;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Date&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Time&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Product&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; KB&lt;br /&gt;----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ----&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -------&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; --&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:05:46&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Microsoft Silver... 979202&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update ... 2532531&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Update for Windo... 2533623&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update ... 2507938&lt;br /&gt;2011-10-17&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 13:59:38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Security Update ... 2555917&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(...)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Using Special Options&lt;/h3&gt;
&lt;p&gt;There are two ways for you to find matches: use the built-in operator &lt;strong&gt;&amp;ndash;match&lt;/strong&gt;, or use the&lt;strong&gt; .NET Framework RegEx&lt;/strong&gt; type. Generally, you want to use the .NET approach whenever you need to find more than just the first match.&lt;/p&gt;
&lt;p&gt;Depending on which method you choose, there are &lt;strong&gt;different default settings&lt;/strong&gt;, though, that you need to know about. The &lt;strong&gt;&amp;ndash;match&lt;/strong&gt; operator always works case-insensitive whereas .NET always works case-sensitive by default. &lt;/p&gt;
&lt;p&gt;The easiest way to make an expression case-insensitive is to use control operators. This pattern for example works case-sensitive with &lt;strong&gt;&amp;ndash;match&lt;/strong&gt; and case-insensitive with&lt;strong&gt; .NET&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;$pattern = &amp;lsquo;KB\d{6,8}&amp;rsquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This pattern always works case-insensitive, regardless of which method you use:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;$pattern = &amp;lsquo;(?i)KB\d{6,8}&amp;rsquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another important control operator turns on single-line-mode. Let&amp;rsquo;s assume you downloaded HTML code from a web page and want to find all instances of a pattern. To find all matches, you need to use .NET. To find the pattern in the entire HTML source code, you need single-line-mode.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;To make this work, your pattern should start with &lt;strong&gt;(?si).&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;What&amp;rsquo;s Next?&lt;/h3&gt;
&lt;p&gt;Next week, I&amp;rsquo;ll keep talking about RegEx and look at &lt;strong&gt;splitting&lt;/strong&gt; and &lt;strong&gt;replacing&lt;/strong&gt;. Meanwhile, if you have spare time, go visit some of the plenty sites that focus on RegEx, and try and refine your understanding of RegEx placeholders, anchors and quantifiers. Stay tuned!&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=12940" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="-match" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/-match/default.aspx" /><category term="Regular Expression" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Regular+Expression/default.aspx" /><category term="RegEx" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/RegEx/default.aspx" /><category term="Get-Matches" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Get-Matches/default.aspx" /><category term="Pattern" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Pattern/default.aspx" /><category term="Parse" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Parse/default.aspx" /></entry><entry><title>Reuse Your Code - Create Modules Automagically!</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/10/14/reuse-your-code-create-modules-automagically.aspx" /><id>/cs/blogs/tobias/archive/2011/10/14/reuse-your-code-create-modules-automagically.aspx</id><published>2011-10-14T16:34:00Z</published><updated>2011-10-14T16:34:00Z</updated><content type="html">&lt;p&gt;When you write scripts, you want to &lt;strong&gt;automate&lt;/strong&gt; things, fair enough. When it comes to writing scripts, a lot of people do not automate, though. They do the same coding over and over again and waste time and consistency.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s look at some simple code-reusing techniques. It&amp;rsquo;s not that hard at all. In fact, after you read this post you can create your own PowerShell modules in seconds.&lt;/p&gt;
&lt;h3&gt;Code Reuse &amp;ndash; Join The Game!&lt;/h3&gt;
&lt;p&gt;Actually, most PowerShell script writers &lt;strong&gt;reuse code all the time without realizing&amp;nbsp;&amp;ndash; they&amp;rsquo;re just not reusing their own code.&lt;/strong&gt; When you run a &lt;strong&gt;cmdlet&lt;/strong&gt;, you are reusing the code someone else put into that cmdlet. You know that&amp;rsquo;s cool because it makes PowerShell scripts much shorter and easier to write. &lt;/p&gt;
&lt;p&gt;If you want to sort stuff, use &lt;strong&gt;Sort-Object&lt;/strong&gt;. That&amp;#39;s code reuse. In the old days of VBScript you had to re-invent and code bubble-sort-algorithms all the time. No more in PowerShell. If you want to manage Active Directory, import the AD &lt;strong&gt;module&lt;/strong&gt; and use &lt;strong&gt;Get-ADUser&lt;/strong&gt; to search for users. Again, no need for coding tricky AD&amp;nbsp;connect and search stuff.&amp;nbsp;It&amp;#39;s done for you so you can focus on your tasks.&amp;nbsp;&lt;strong&gt;Cmdlets are a big old code reuse party&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Most PowerShell scripters happily use cmdlets but eventually find that they need additional stuff because &lt;strong&gt;there aren&amp;rsquo;t predefined cmdlets for everything&lt;/strong&gt;. So they start scripting day and night and produce long and convoluted scripts that are hard to manage and adjust.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stop that.&lt;/strong&gt; When you need to automate something, grab a coffee and &lt;strong&gt;think first&lt;/strong&gt;. What is the &amp;ldquo;vocabulary&amp;rdquo; (cmdlets, functions) you need to address the problem? Do you have all the vocabulary you need for that? What is missing? Which PowerShell module might already provide the needed vocabulary? There are great modules for VMWare, HyperV, AD, Exchange, SQLServer, you name it.&lt;/p&gt;
&lt;p&gt;Chances are, some vocabulary you need&amp;nbsp;is missing. When that occurs, &lt;strong&gt;design the functions that provide the missing vocabulary first&lt;/strong&gt;. Once they are done, continue with your initial job. Does that take more time? No, it saves time. Here&amp;#39;s how.&lt;/p&gt;
&lt;h3&gt;Adding More Vocabulary - Outputting Data to Excel (for example)&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s say as part of your solution you need a way to output information to &lt;strong&gt;Microsoft Excel&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Instead of incorporating this functionality&amp;nbsp;into your overall solution (and producing monster scripts), define a function that just focuses on outputting information to Microsoft Excel. Clean and sweet.&amp;nbsp;It could be as simple as this one:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-ExcelReport&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;$env:temp\report$(Get-Date -format yyyyMMddHHmmss).csv&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;[&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;switch&lt;/span&gt;&lt;/span&gt;]&lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$open&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Input&lt;/span&gt;&lt;/span&gt; | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Export-Csv&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-NoTypeInformation&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-UseCulture&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Encoding&lt;/span&gt;&lt;/span&gt; UTF8&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$open&lt;/span&gt;&lt;/span&gt;) { &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;}&lt;/div&gt;
&lt;p&gt;Once your function is done, test it. Run it like this:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Process&lt;/span&gt;&lt;/span&gt; | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-ExcelReport&lt;/span&gt;&lt;/span&gt; &amp;ndash;open&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;p&gt;Or like this:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Process&lt;/span&gt;&lt;/span&gt; | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Select-Object&lt;/span&gt;&lt;/span&gt; Name, Description, Company, MainWindowTitle | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Where-Object&lt;/span&gt;&lt;/span&gt; { &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MainWindowTitle&lt;/span&gt;&lt;/span&gt; } | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-ExcelReport&lt;/span&gt;&lt;/span&gt; &amp;ndash;open&lt;/div&gt;
&lt;h3 class="pscode"&gt;&lt;br /&gt;Making Your Vocabulary Reusable, Too!&lt;/h3&gt;
&lt;p&gt;Once your new function is working like a charm, you could be tempted to copy and paste&amp;nbsp;the code&amp;nbsp;into your overall solution. &lt;strong&gt;Don&amp;rsquo;t do that!&lt;/strong&gt; Don&amp;#39;t assimilate your great new function into some script. Keep it separate! &lt;strong&gt;Make it reusable!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Any script that wants to export data to Microsoft Excel should import the necessary vocabulary from PowerShell modules. Which raises the question: &lt;strong&gt;how would you turn your function into a module?&lt;/strong&gt; That&amp;rsquo;s done automagically when you download, &lt;a target="_blank" href="http://powershell.com/cs/media/p/12823.aspx"&gt;unpack and import this helper module:&lt;/a&gt; &lt;a target="_blank" href="http://powershell.com/cs/media/p/12823.aspx"&gt;http://powershell.com/cs/media/p/12823.aspx&lt;/a&gt;. Simply import it like this:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Import-Module&lt;/span&gt;&lt;/span&gt; c:\pathtomodulefolder\ModuleHelper&lt;/div&gt;
&lt;p&gt;Make sure you specify the path to the unzipped folder named &amp;quot;ModuleHelper&amp;quot; &lt;strong&gt;inside the ZIP&lt;/strong&gt; (due to zipping, there are two nested folders, take the one inside the other), and also note that as a general prerequisite, your PowerShell execution policy should of course allow scripts to run.&lt;/p&gt;
&lt;p&gt;Now, to save your brand new function &lt;strong&gt;Out-ExcelReport&lt;/strong&gt; to a new module of your choice, use the new command &lt;strong&gt;Out-Module&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-Module&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Module&lt;/span&gt;&lt;/span&gt; ReportingStuff &amp;ndash;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;Function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-ExcelReport&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p class="pscode"&gt;That&amp;rsquo;s it! You may have noticed that there was no module &amp;ldquo;ReportingStuff&amp;rdquo; before, but there is now:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Module&lt;/span&gt;&lt;/span&gt; &amp;ndash;ListAvailable&lt;/div&gt;
&lt;p class="pscode"&gt;&lt;br /&gt;So when you import this new module, you load your function &lt;strong&gt;Out-ExcelReport&lt;/strong&gt;. Essentially, you created the same great code reuse mechanism that you enjoyed from other vendors to run AD or Exchange cmdlets. Open a new PowerShell console, and try this:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Import-Module&lt;/span&gt;&lt;/span&gt; ReportingStuff&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Service&lt;/span&gt;&lt;/span&gt; | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-ExcelReport&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-open&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;span class="modifier"&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;p class="pscode"&gt;Your new function &lt;strong&gt;Out-ExcelReport&lt;/strong&gt; just became reusable, and you can import your module in every script that needs your new reporting capabilities now. Never do you have to waste time again to create that functionality again. Cool, eh?&lt;/p&gt;
&lt;h3&gt;Adding and Managing Scripts&lt;/h3&gt;
&lt;p&gt;So far, your new module &amp;ldquo;ReportingStuff&amp;rdquo; has only one function. You can add more, though. Your new module serves as a script repository for you, and &lt;strong&gt;you can save all functions into that module&lt;/strong&gt; that deal with reporting. For example, maybe you&amp;rsquo;d also like to be able to easily create text files that are wide enough to show all results without truncation. Here&amp;rsquo;s the function:&lt;/p&gt;
&lt;div class="pscode"&gt;&amp;lt;&lt;span style="color:#008000;"&gt;&lt;span class="comment"&gt;#&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;SYNOPSIS&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Saves results as text to a text file&lt;br /&gt;.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;DESCRIPTION&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Saves results to text file and automatically adjusts the file width so no columns and no data is truncated.&lt;br /&gt;Truncation only occurs for object properties that contain &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;multi-line&lt;/span&gt;&lt;/span&gt; text.&lt;br /&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;PARAMETER&lt;/span&gt;&lt;/span&gt; Path&lt;br /&gt;Optional. Name of text file to create. Existing files will be overwritten. By default, a temporary file &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;in&lt;/span&gt;&lt;/span&gt; the temp folder is created.&lt;br /&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;PARAMETER&lt;/span&gt;&lt;/span&gt; Open&lt;br /&gt;Opens the text file after creation &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;in&lt;/span&gt;&lt;/span&gt; the application that is associated with .&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;txt-files&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;EXAMPLE&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Process&lt;/span&gt;&lt;/span&gt; | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Where-Object&lt;/span&gt;&lt;/span&gt; { &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MainWIndowTitle&lt;/span&gt;&lt;/span&gt;} | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Select-Object&lt;/span&gt;&lt;/span&gt; Name, Description, Company, MainWindowTitle , CPU | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-TextReport&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#5f9ea0;"&gt;&lt;span class="modifier"&gt;-Open&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Lists various pieces of information about running processes and writes them to a text file. The file width is automatically adjusted to provide enough room to display all information. The text file then is opened by its default application.&lt;br /&gt;.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;EXAMPLE&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-ACL&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt; | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-TextReport&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#5f9ea0;"&gt;&lt;span class="modifier"&gt;-open&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Reads the windows folder NTFS permissions and writes the results to a text file. The text file then is opened by its default application.&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;span class="comment"&gt;#&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-TextReport&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Path&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;$env:temp\report.txt&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;[&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;switch&lt;/span&gt;&lt;/span&gt;]&lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$Open&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Input&lt;/span&gt;&lt;/span&gt; | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Format-Table&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-AutoSize&lt;/span&gt;&lt;/span&gt; |&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-File&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Width&lt;/span&gt;&lt;/span&gt; 10000&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$open&lt;/span&gt;&lt;/span&gt;) { &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Path&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;}&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;br /&gt;
&lt;p&gt;Run it, and test it thoroughly. Once done, again save the function to your module, directly from memory:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-Module&lt;/span&gt;&lt;/span&gt; ReportingTools &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-TextReport&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;p&gt;Your new module now has two pieces of vocabulary. To update it, use &lt;strong&gt;&amp;ndash;force&lt;/strong&gt; while you import it: &lt;/p&gt;
&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Import-Module&lt;/span&gt;&lt;/span&gt; ReportingTools &amp;ndash;Force &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Verbose&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3 class="pscode"&gt;&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Adding Help&amp;nbsp;and Updating Modules&lt;/h3&gt;
&lt;p&gt;Note that with &lt;strong&gt;Out-TextReport&lt;/strong&gt;, I added a &lt;strong&gt;comment-based help&lt;/strong&gt; block to the code. That&amp;rsquo;s a really good idea because you probably remember how you discovered and learned 3rd party cmdlets &amp;ndash; by using &lt;strong&gt;Get-Help&lt;/strong&gt; and looking at the examples. &lt;/p&gt;
&lt;p&gt;You should provide the same helpful information for the users of your own &amp;ldquo;cmdlets&amp;rdquo;. That&amp;rsquo;s just fair (and gives them an especially professional touch, too). So take a little time and create a great help block with practical examples. &lt;/p&gt;
&lt;p&gt;If you save a function to your module that does not yet have a help block, &lt;strong&gt;Out-Module&lt;/strong&gt; adds one. So when you load and edit functions from your module (hang in, we&amp;rsquo;ll cover that in a second), you just need to fill out the placeholders and save the script.&lt;/p&gt;
&lt;p&gt;You can even &lt;strong&gt;update functions in your module(s)&lt;/strong&gt;. Just assume you wanted to polish a function. Simply open the module path,&amp;nbsp; and load the function into your favorite script editor. Make the adjustments, then save it back:&lt;/p&gt;
&lt;div class="pscode"&gt;Explorer (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-ModulePath&lt;/span&gt;&lt;/span&gt; ReportingTools)&lt;/div&gt;
&lt;p&gt;Likewise, you can send a function that you changed, back to the module by using &lt;strong&gt;Out-Module&lt;/strong&gt; again. It will replace the old version.&lt;/p&gt;
&lt;h3&gt;More to come...&lt;/h3&gt;
&lt;p&gt;At our first &lt;strong&gt;European PowerShell Deep Dive&lt;/strong&gt; yesterday, I also did a presentation about the &lt;strong&gt;power of regular expressions&lt;/strong&gt; and how beautifully PowerShell embraces them. I added all the example functions to a sample module using the technique described above. So next week, I&amp;#39;ll share some serious &lt;strong&gt;RegEx magic&lt;/strong&gt; with you. Stay tuned!&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=12822" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Module" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Module/default.aspx" /><category term="Function" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Function/default.aspx" /><category term="Out-TextReport" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Out-TextReport/default.aspx" /><category term="Out-Module" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Out-Module/default.aspx" /><category term="Deep Dive" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Deep+Dive/default.aspx" /><category term="Out-ExcelReport" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Out-ExcelReport/default.aspx" /></entry><entry><title>Applying NTFS Permissions</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/09/21/applying-ntfs-permissions.aspx" /><id>/cs/blogs/tobias/archive/2011/09/21/applying-ntfs-permissions.aspx</id><published>2011-09-21T10:21:00Z</published><updated>2011-09-21T10:21:00Z</updated><content type="html">&lt;p&gt;Recently, I needed to &lt;strong&gt;create a folder with NTFS permissions&lt;/strong&gt;. PowerShell can do that for you, and when you look at your weapons, you&amp;#39;ll find that sometimes it is best to mix command types and not just stick to cmdlets. At the end, I had a handy function that would take a path and a username and do all the tricky NTFS permissions stuff for me. Here is how.&lt;/p&gt;
&lt;h3&gt;Creating Folders&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s start with the simple part and write a function that creates a folder if that folder does not yet exist:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Create-Folder&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;) &lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; ( (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Test-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;) &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-ne&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$true&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ItemType&lt;/span&gt;&lt;/span&gt; Directory | &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;}&lt;/div&gt;
&lt;h3&gt;Apply Permissions&lt;/h3&gt;
&lt;p&gt;Next, I want to &lt;strong&gt;add NTFS permissions&lt;/strong&gt; to that folder. A specifc user should get change permission, and all Administrators should get full permission. There are cmdlets to do the job like &lt;strong&gt;Get/Set-ACL&lt;/strong&gt;, but working with them can be hard because they really are just simple wrappers for low-level .NET methods. &lt;/p&gt;
&lt;p&gt;PowerShell is not limited to cmdlets. You can happily use established console-based applications like &lt;strong&gt;cacls.exe&lt;/strong&gt;. Here is an example:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Create-Folder&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;, &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$user&lt;/span&gt;&lt;/span&gt;) &lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; ( (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Test-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;) &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-ne&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$true&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ItemType&lt;/span&gt;&lt;/span&gt; Directory | &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;CACLS &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;G &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;&amp;quot;Domain Admins&amp;quot;&lt;/span&gt;&lt;/span&gt;:F &lt;br /&gt;CACLS &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;E &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;G &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$user:C&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;}&lt;/div&gt;
&lt;p&gt;As it turns out, this won&amp;#39;t work yet. The first call to &lt;strong&gt;CACLS&lt;/strong&gt; removes existing permissions which is what I want. However, this triggers a confirmation, so I would have to manually &lt;strong&gt;type &amp;quot;Y&amp;quot; to approve&lt;/strong&gt; the operation. The second call to &lt;strong&gt;CACLS&lt;/strong&gt; won&amp;#39;t work at all. &lt;strong&gt;CACLS&lt;/strong&gt; can&amp;#39;t understand it, so it throws back its manual to the caller.&lt;/p&gt;
&lt;p&gt;To correct these issues, &lt;strong&gt;a couple of tricks are needed&lt;/strong&gt;. To automatically send a key to a confirmation, place it on the pipeline. And to resolve the syntax issue, submit arguments to &lt;strong&gt;CACLS&lt;/strong&gt; as a string so PowerShell won&amp;#39;t get confused:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;function&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Create-Folder&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;param&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;, &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$user&lt;/span&gt;&lt;/span&gt;) &lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; ( (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Test-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;) &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-ne&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$true&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ItemType&lt;/span&gt;&lt;/span&gt; Directory | &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;&lt;/span&gt; | CACLS &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;&amp;quot;&amp;quot;$path&amp;quot;&amp;quot; /G &amp;quot;&amp;quot;Domain Admins&amp;quot;&amp;quot;:R&amp;quot;&lt;/span&gt;&lt;/span&gt; | &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;CACLS &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;&amp;quot;&amp;quot;$path&amp;quot;&amp;quot; /E /G &amp;quot;&amp;quot;$user&amp;quot;&amp;quot;:F&amp;quot;&lt;/span&gt;&lt;/span&gt; | &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;/div&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;Now it is easy to create new folders and apply standard NTFS security:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Create-Folder&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-path&lt;/span&gt;&lt;/span&gt; c:\user1 &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-user&lt;/span&gt;&lt;/span&gt; mydomain\username&lt;/div&gt;
&lt;h3&gt;Careful!&lt;/h3&gt;
&lt;p&gt;Unfortunately, this &lt;strong&gt;approach is not culture-neutral&lt;/strong&gt;. On non-US systems, you probably will want to change two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure you &lt;strong&gt;use the correct name for the Admin group&lt;/strong&gt;. On German systems, it is called &amp;quot;Dom&amp;auml;nen-Admins&amp;quot; instead of &amp;quot;Domain Admins&amp;quot;&lt;/li&gt;
&lt;li&gt;Make sure you &lt;strong&gt;send the correct confirmation key&lt;/strong&gt;. On German systems, it is &amp;quot;J&amp;quot; rather than &amp;quot;Y&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know that sucks, but for a number of scenarios, incorporating tools like &lt;strong&gt;CACLS&lt;/strong&gt; can simplify life tremendously. Learning points here are: console-based applications are (almost) equal PowerShell citizens. To submit arguments to them, you may have to turn them into a string in order to avoid parsing conflicts.&lt;/p&gt;
&lt;p&gt;See you next time!&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=12433" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Folder" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Folder/default.aspx" /><category term="NTFS" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/NTFS/default.aspx" /><category term="get-acl" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/get-acl/default.aspx" /><category term="set-acl" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/set-acl/default.aspx" /><category term="cacls" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/cacls/default.aspx" /></entry><entry><title>Bulk-Renaming Files (and other magic)</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/09/12/bulk-renaming-files-and-other-magic.aspx" /><id>/cs/blogs/tobias/archive/2011/09/12/bulk-renaming-files-and-other-magic.aspx</id><published>2011-09-12T07:49:00Z</published><updated>2011-09-12T07:49:00Z</updated><content type="html">&lt;p&gt;Bulk-renaming files can cause some headache: maybe you&amp;#39;d like to nicely rename all your pictures with a keyword and an incrementing counter, or you&amp;#39;d want to clean up log files and assign them a standard name based on its creation date. It&amp;#39;s easy to do that for one file, and &lt;a target="_blank" href="http://powershell.com/cs/blogs/tips/archive/2011/09/08/bulk-renaming-files.aspx"&gt;with our latest tip&lt;/a&gt;, we illustrated how you can as just as easily do this for hundreds of files, too. Heck, did we get&amp;nbsp;a lot of feedback, both additional questions and great suggestions, so let&amp;#39;s check out what&amp;nbsp;other options you have to bulk-rename files.&lt;/p&gt;
&lt;h3&gt;Creating Filenames with an Incrementing Counter&lt;/h3&gt;
&lt;p&gt;In our original tip, we wanted to rename the content of a folder filled with picture files. Each picture file was supposed to get a new file name like &amp;quot;pictureX&amp;quot;, where &amp;quot;X&amp;quot; was an incrementing counter. Here is the logic:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$global:i&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; 1&lt;/div&gt;
&lt;div class="pscode"&gt;&lt;/div&gt;
&lt;div class="pscode"&gt;dir c:\pictures\ &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;Filter&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;jpg&lt;/span&gt;&lt;/span&gt; | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Rename-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-NewName&lt;/span&gt;&lt;/span&gt; { &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;picture_$i.jpg&amp;quot;&lt;/span&gt;&lt;/span&gt;; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$global:i&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;++&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;/div&gt;
&lt;p&gt;There are two things to note here: First, we need a &lt;strong&gt;global variable $i&lt;/strong&gt; which holds the incrementing counter. It needs to be global because we want to remember its setting and increment it with each new file. By default, variables are valid only within their &amp;quot;territory&amp;quot; (scriptblock) and below, so if the counter variable was not global, the scriptblock would always start with a new variable.&lt;/p&gt;
&lt;p&gt;Second, note how &lt;strong&gt;Rename-Item&lt;/strong&gt; accepts a scriptblock. Instead of assigning a static file name, a scriptblock can dynamically create the filename for you. In our example code, the new filename consists of a fixed prefix &amp;quot;picture_&amp;quot; and the counter variable. Pretty nice! But it gets better.&lt;/p&gt;
&lt;h3&gt;Taking Advantage of $_&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Jacques Barathon&lt;/strong&gt; pointed out that the scriptblock that you submit to &lt;strong&gt;Rename-Item&lt;/strong&gt; of course has a &lt;strong&gt;$_ automatic variable&lt;/strong&gt;. This is true for most scriptblocks that you submit to cmdlets. &lt;strong&gt;$_&lt;/strong&gt; always represents the current object you are working with.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s cool because now you can easily use the existing file name and manipulate it. Here is what Jacques did: he wanted to replace a single word in a filename. Let&amp;#39;s check out how he did this:&lt;/p&gt;
&lt;div class="pscode"&gt;dir &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;docx&lt;/span&gt;&lt;/span&gt; | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Rename-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-NewName&lt;/span&gt;&lt;/span&gt; {&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt;.&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;Name.Replace&lt;/span&gt;&lt;/span&gt;(&amp;lsquo;chapter&amp;rsquo;, &amp;lsquo;chapitre&amp;rsquo;)}&lt;/div&gt;
&lt;p&gt;Whew! That was easy! Since &lt;strong&gt;$_&lt;/strong&gt; is referring to the current file, he accessed the original filename through &lt;strong&gt;$_.Name&lt;/strong&gt;. The result is the filename, and it is a &lt;strong&gt;string&lt;/strong&gt; data type. So he could then use the string method &lt;strong&gt;Replace()&lt;/strong&gt; to replace a word in that filename. The result was the new filename where &amp;#39;chapter&amp;#39; was replaced by &amp;#39;chapitre&amp;#39;. This result was then used by &lt;strong&gt;Rename-Item&lt;/strong&gt; to rename the file.&lt;/p&gt;
&lt;h3&gt;The Sky Is The Limit&lt;/h3&gt;
&lt;p&gt;Of course, &lt;strong&gt;$_&lt;/strong&gt; gives you complete access to &lt;strong&gt;all file properties&lt;/strong&gt;, so you can basically access and use all file properties to construct the new filename. Let&amp;#39;s say you wanted to &lt;strong&gt;replace a filename by a&lt;/strong&gt; &lt;strong&gt;timestamp&lt;/strong&gt; based on the creation date. Here is some code that does it:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$code&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$timestamp&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Date&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;CreationTime&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-format&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;yyyyMMddHHmmssff&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$extension&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt;.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;Extension&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$timestamp&lt;/span&gt;&lt;/span&gt;.&lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$extension&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;dir c:\pictures | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Rename-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-NewName&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$code&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;Note how we placed the code (scriptblock) into an extra variable&lt;strong&gt; $code&lt;/strong&gt; to keep the code clean. &lt;/p&gt;
&lt;p&gt;While you are playing with this sample, you&amp;#39;ll definitely run into issues. When doing bulk operations, you always have to take all kinds of &lt;strong&gt;edge cases&lt;/strong&gt; into consideration. &lt;strong&gt;What if there are two files with the very same creation date?&lt;/strong&gt; Since no two files can have the same name, &lt;strong&gt;Rename-Item&lt;/strong&gt; would fail at the second file and not continue. Bummer.&lt;/p&gt;
&lt;p&gt;Happily, you are not bound to any limits. Your scriptblock can contain as much logic as you like. So here is a more advanced approach that takes care of duplicates. It first creates the new filename, then checks if a file with that name already exists, and if so adds a counter to the filename.&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$code&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$timestamp&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Date&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;CreationTime&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-format&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;yyyyMMddHHmmssff&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$extension&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt;.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;Extension&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$counter&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; 0&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;while&lt;/span&gt;&lt;/span&gt; (&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$true&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$filename&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;{0}{1}{2}&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-f&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$timestamp&lt;/span&gt;&lt;/span&gt;, &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;( &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$counter&lt;/span&gt;&lt;/span&gt;) { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;-$counter&amp;quot;&lt;/span&gt;&lt;/span&gt; } &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;&lt;/span&gt; { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt; }) , &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$extension&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$filepath&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Join-Path&lt;/span&gt;&lt;/span&gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Split-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;FullName&lt;/span&gt;&lt;/span&gt;) &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$filename&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Test-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$filepath&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$counter&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;++&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;} &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$filename&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&lt;span class="keyword"&gt;break&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;} &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dir c:\pictures | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Rename-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-NewName&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$code&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;You can reuse this logic for all events &lt;strong&gt;where you cannot be sure that the filename&lt;/strong&gt; created by your scriptblock &lt;strong&gt;is unique&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s the scoop for today. Hope to see you next week,&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;Microsoft MVP PowerShell Germany&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=12285" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Rename-Item" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Rename-Item/default.aspx" /><category term="Bulk" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Bulk/default.aspx" /></entry><entry><title>Clever Splatting to Pass Optional Parameters</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/08/03/clever-splatting-to-pass-optional-parameters.aspx" /><id>/cs/blogs/tobias/archive/2011/08/03/clever-splatting-to-pass-optional-parameters.aspx</id><published>2011-08-03T04:15:00Z</published><updated>2011-08-03T04:15:00Z</updated><content type="html">&lt;p&gt;Getting system information from WMI is a pretty straight-forward thing with &lt;strong&gt;Get-WMIObject&lt;/strong&gt;. You can even specify one or more computer names or IP addresses to retrieve the information remotely. &lt;strong&gt;That&amp;#39;s all great, but how would you design a function that encapsulates Get-WMIObject (or any other cmdlet that can work both locally and remotely)&lt;/strong&gt;? That&amp;#39;s not so trivial. &lt;/p&gt;
&lt;p&gt;Have a look. There&amp;#39;s a really clever solution for that!&lt;/p&gt;
&lt;h3&gt;Prerequisites: Getting Information Locally or Remotely&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Get-WMIObject&lt;/strong&gt; is a great example of a cmdlet with built-in remoting. For example, to get information about your BIOS, use this call:&lt;/p&gt;
&lt;div class="pscode"&gt;PS&amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-WMIObject&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Class&lt;/span&gt;&lt;/span&gt; Win32_BIOS&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SMBIOSBIOSVersion : 02LV.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MP00&lt;/span&gt;&lt;/span&gt;.20081121.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;hkk&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Manufacturer : Phoenix Technologies Ltd.&lt;br /&gt;Name : Phoenix SecureCore(tm) NB Version 02LV.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MP00&lt;/span&gt;&lt;/span&gt;.20081121.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;hkk&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;SerialNumber : ZAMA93HS600210&lt;br /&gt;Version : SECCSD &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt; 6040000&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PS&amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-WMIObject&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Class&lt;/span&gt;&lt;/span&gt; Win32_BIOS &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ComputerName&lt;/span&gt;&lt;/span&gt; storage1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SMBIOSBIOSVersion : P03&lt;br /&gt;Manufacturer : Phoenix Technologies LTD&lt;br /&gt;Name : Ver 1.00PARTTBLw&lt;br /&gt;SerialNumber : 98H340ED2H9300237A30A1&lt;br /&gt;Version : PTLTD &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt; 6040000&lt;/div&gt;
&lt;p&gt;As you can see, the cmdlet gets information both from your local system and from one (or more) remote systems - provided they are correctly configured and you have appropriate permissions. It all depends on the parameters you submitted to &lt;strong&gt;Get-WMIObject&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We are not digging into the security details here because that&amp;#39;s another topic, but if you can&amp;#39;t get &lt;strong&gt;Get-WMIObject&lt;/strong&gt; to work against remote systems, try enabling the &amp;quot;Remote Management Exception&amp;quot; in your firewall when you get &amp;quot;RPC&amp;quot;-exceptions, and use the parameter -credential to log on as a different user when you get &amp;quot;Access Denied&amp;quot;-exceptions.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Creating A (Stupid) Wrapper Function&lt;/h3&gt;
&lt;p&gt;The call to &lt;strong&gt;Get-WMIObject&lt;/strong&gt; is really very trivial, but let&amp;#39;s assume you still &lt;strong&gt;want to encapsulate it and use it as a new function&lt;/strong&gt;. How would you design a function that can run both against the local machine and the remote machine(s)?&lt;/p&gt;
&lt;p&gt;In traditional thinking, you would have to check whether the user has actually submitted the &lt;strong&gt;-computername&lt;/strong&gt; parameter, and then call &lt;strong&gt;Get-WMIObject&lt;/strong&gt; multiple times: if the parameter was submitted, you pass it on to the cmdlet, and if not, you omit it. The result usually is pretty awkward and becomes even more convoluted when you add additional parameters. Here is an &lt;strong&gt;ugly example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-BIOS&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$computername&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$null&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$credential&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$null&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$credential&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-WmiObject&lt;/span&gt;&lt;/span&gt; Win32_BIOS &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-computername&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$computername&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-credential&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$credential&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;} &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;elseif&lt;/span&gt;&lt;/span&gt; (&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$computername&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-WmiObject&lt;/span&gt;&lt;/span&gt; Win32_BIOS &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-computername&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$computername&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;} &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-WmiObject&lt;/span&gt;&lt;/span&gt; Win32_BIOS &lt;br /&gt;}&lt;br /&gt;}&lt;/div&gt;
&lt;p&gt;At least, it does what it was supposed to do:&lt;/p&gt;
&lt;div class="pscode"&gt;PS&amp;gt; &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Get-BIOS&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;SMBIOSBIOSVersion : 02LV.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MP00&lt;/span&gt;&lt;/span&gt;.20081121.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;hkk&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Manufacturer : Phoenix Technologies Ltd.&lt;br /&gt;Name : Phoenix SecureCore(tm) NB Version 02LV.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MP00&lt;/span&gt;&lt;/span&gt;.20081121.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;hkk&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;SerialNumber : ZAMA93HS600210&lt;br /&gt;Version : SECCSD &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt; 6040000&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PS&amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-BIOS&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-computername&lt;/span&gt;&lt;/span&gt; storage1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SMBIOSBIOSVersion : P03&lt;br /&gt;Manufacturer : Phoenix Technologies LTD&lt;br /&gt;Name : Ver 1.00PARTTBLw&lt;br /&gt;SerialNumber : 98H340ED2H9300237A30A1&lt;br /&gt;Version : PTLTD &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt; 6040000&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PS&amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-BIOS&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-computername&lt;/span&gt;&lt;/span&gt; storage1 &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-credential&lt;/span&gt;&lt;/span&gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Credential&lt;/span&gt;&lt;/span&gt; Administrator)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SMBIOSBIOSVersion : P03&lt;br /&gt;Manufacturer : Phoenix Technologies LTD&lt;br /&gt;Name : Ver 1.00PARTTBLw&lt;br /&gt;SerialNumber : 98H340ED2H9300237A30A1&lt;br /&gt;Version : PTLTD &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt; 6040000&lt;/div&gt;
&lt;h3&gt;Create a (Clever) Wrapper Function&lt;/h3&gt;
&lt;p&gt;When you want to &lt;strong&gt;pass optional parameters to cmdlets&lt;/strong&gt;, there is a &lt;strong&gt;much more clever and elegant way&lt;/strong&gt; in PowerShell: &lt;strong&gt;Splatting&lt;/strong&gt;! Instead of manually handing over parameters to a cmdlet, you create a hash table with the parameters you want to pass on. Then, you submit the hash table to the cmdlet.&lt;/p&gt;
&lt;p&gt;The advantage of this not widely known technique is obvious once you see the improved version of the wrapper function: PowerShell already makes available an object that you can use for splatting! The system variable &lt;strong&gt;$PSBoundParameters&lt;/strong&gt; contains all the parameters that were submitted to your function, so whatever someone submitted can be passed on to a cmdlet without the need to check for parameters and call different code:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-BIOS&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$computername&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$credential&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-WmiObject&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Class&lt;/span&gt;&lt;/span&gt; Win32_BIOS @psboundparameters&lt;br /&gt;&lt;br /&gt;}&lt;/div&gt;
&lt;p&gt;Isn&amp;#39;t that a beauty? It works exactly the same, with &lt;em&gt;much&lt;/em&gt; less code. The function calls &lt;strong&gt;Get-WMIObject&lt;/strong&gt; to retrieve WMI BIOS information and optionally passes on the &lt;strong&gt;computername&lt;/strong&gt; and/or &lt;strong&gt;credential&lt;/strong&gt; parameter. No extra work for you anymore.&lt;/p&gt;
&lt;div&gt;
&lt;p&gt;Thanks to&amp;nbsp;Aleksandar and HAL (both PS MVPs) for their valuable input!&lt;/p&gt;
&lt;p&gt;Hope to see you next week,&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;Microsoft MVP PowerShell Germany&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=11692" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Get-WMIObject" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Get-WMIObject/default.aspx" /><category term="Splatting" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Splatting/default.aspx" /><category term="$PSBoundParameters" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/_2400_PSBoundParameters/default.aspx" /></entry><entry><title>Dealing With File Locks</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/06/23/dealing-with-file-locks.aspx" /><id>/cs/blogs/tobias/archive/2011/06/23/dealing-with-file-locks.aspx</id><published>2011-06-23T10:40:00Z</published><updated>2011-06-23T10:40:00Z</updated><content type="html">&lt;p&gt;Sometimes, when you try and access a file, it may refuse to open because it is locked by another user or process. Likewise, you may want to lock a file yourself to make sure the file is not accessed and read/changed while you are manipulating it. Which raises the question: how do you control file locks?&lt;/p&gt;
&lt;h3&gt;Locking a file&lt;/h3&gt;
&lt;p&gt;Get-Content can read text-based files. This cmdlet is not locking the file, so while you are reading it, others can still access or even change it.&lt;/p&gt;
&lt;p&gt;To apply a file lock, you need to use low level .NET methods. The next example illustrates how to open a file with a read/write lock. While this script is running, no one can access the file:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$file&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; [&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.io.File&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Open&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;c:\files\somefile.txt&amp;#39;&lt;/span&gt;&lt;/span&gt;, &amp;#39;Open&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;/span&gt;Read&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;/span&gt;None&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;)&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;Read-Host &amp;#39;&lt;/span&gt;&lt;/span&gt;Press ENTER to release file&amp;#39;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$file&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Close&lt;/span&gt;&lt;/span&gt;()&lt;/div&gt;
&lt;p&gt;The method Open() accepts four arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The path to the file you want to access&lt;/li&gt;
&lt;li&gt;The action you want to take, for example &amp;quot;Open&amp;quot;&lt;/li&gt;
&lt;li&gt;The access you want to use, for example &amp;quot;Read&amp;quot;&lt;/li&gt;
&lt;li&gt;The lock. &amp;quot;None&amp;quot; grants to access to others, so the file is locked. &amp;quot;Read&amp;quot; would allow others to read the file while you are using it, and &amp;quot;ReadWrite&amp;quot; would allow others to read and/or write to the file while you are using it&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reading File Content&lt;/h3&gt;
&lt;p&gt;When you lock a file,&amp;nbsp;no one else can access it, so you cannot use Get-Content to read its content anymore, either. To read the file content, you would have to refer to .NET methods. Here is an example that reads file content of a&amp;nbsp;file you applied a lock on:&lt;/p&gt;
&lt;p&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$file&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; [&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.io.File&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Open&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;c:\files\somefile.txt&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Open&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Read&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;None&amp;#39;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$reader&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.IO.StreamReader&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$file&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$reader&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;ReadToEnd&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$reader&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Close&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$file&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Close&lt;/span&gt;&lt;/span&gt;()&lt;/p&gt;
&lt;h3&gt;Dealing With Existing File Locks&lt;/h3&gt;
&lt;p&gt;When you try and access a file, others may have already applied locks to it. For example, windows maintains a file called $env:windir\windowsupdate.log which carries a &amp;quot;Write&amp;quot; lock: you can read its contents, but you cannot write to it.&lt;/p&gt;
&lt;p&gt;If you tried and accessed that file with a lock of type &amp;quot;None&amp;quot; (exclusive access), your code would fail because the system already implemented a lock which is incompatible to the lock you wanted to apply. You can only lock a file for exclusive access if noone else has applied a&amp;nbsp;lock before.&lt;/p&gt;
&lt;p&gt;To deal with this, you would have to make sure your lock is not conflicting with existing locks. When you specify a &amp;quot;ReadWrite&amp;quot; lock (essentially allowing others to still read and write the file), you can safely read the file despite other locks (except if someone had applied a &amp;quot;None&amp;quot; lock):&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$file&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; [&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.io.File&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Open&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;$env:windir\windowsupdate.log&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Open&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Read&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ReadWrite&amp;#39;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$reader&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.IO.StreamReader&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$file&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$reader&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;ReadToEnd&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$reader&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Close&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$file&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Close&lt;/span&gt;&lt;/span&gt;()&lt;/div&gt;
&lt;p&gt;This is how Get-Content works. It uses a &amp;quot;ReadWrite&amp;quot; lock. The above low level .NET access is a lot faster though because it is not reading the file line by line. Instead, it returns the entire file content as one (large) string.&lt;/p&gt;
&lt;div&gt;
&lt;p&gt;Hope to see you next week,&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;Microsoft MVP PowerShell Germany&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=10975" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Lock" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Lock/default.aspx" /><category term="None" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/None/default.aspx" /><category term="ReadWrite" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/ReadWrite/default.aspx" /><category term="File" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/File/default.aspx" /><category term="Open" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Open/default.aspx" /></entry><entry><title>Renaming Files Puzzle - And Three Golden PowerShell Rules</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/05/23/renaming-files-puzzle-and-three-golden-powershell-rules.aspx" /><id>/cs/blogs/tobias/archive/2011/05/23/renaming-files-puzzle-and-three-golden-powershell-rules.aspx</id><published>2011-05-23T11:57:00Z</published><updated>2011-05-23T11:57:00Z</updated><content type="html">&lt;p&gt;I am moderator for one of our &lt;a target="_blank" href="http://powershell.com/cs/forums/200.aspx"&gt;Ask-the-Experts forums&lt;/a&gt;, and every once in a while, I get questions I would like to discuss. Like this one:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&amp;quot;I am tring to write a quick interactive command that will rename all the jpgs in the current directory and came up with the following command:&lt;br /&gt;&lt;br /&gt;$i=1; gci | ? { ($_.Extension -eq &amp;quot;.JPG&amp;quot;) -and !($_.Name.StartsWith(&amp;quot;cover&amp;quot;)) } | % { Rename-Item -Path &amp;quot;.\$_&amp;quot; -NewName [string]::Format(&amp;quot;picture_$i.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div id=":1dv"&gt;&lt;em&gt;&lt;strong&gt;jpg&amp;quot;); $i++ }&lt;br /&gt;&lt;br /&gt;There appears to be a parameter binding issue. But the 2 parameters I have specified (-Path and -NewName) I have named so I assumed that position is not of relevance. What am I missing here?&amp;quot;&lt;/strong&gt;&lt;/em&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s see how we can solve this puzzle and come up with an easy solution using the&amp;nbsp;&amp;quot;3 Golden PowerShell rules&amp;quot;!&lt;/p&gt;
&lt;h2&gt;Think PowerShell! Use Parameters!&lt;/h2&gt;
&lt;div&gt;
&lt;p&gt;Whenever you work with files, &lt;strong&gt;Get-Childitem&lt;/strong&gt; (aka &lt;strong&gt;dir&lt;/strong&gt; or &lt;strong&gt;ls&lt;/strong&gt;) is your friend. And like most &lt;strong&gt;Get-*&lt;/strong&gt; cmdlets, it has a lot of parameters to help you get what you want. Of course you can always use &lt;strong&gt;Where-Object&lt;/strong&gt; (short: &lt;strong&gt;?&lt;/strong&gt;) to filter the results once you got them. That is only your last resort, though. Before you do that, always make sure the original cmdlet has no way of filtering. And &lt;strong&gt;Get-Childitem&lt;/strong&gt; has. So the first part would be selecting the files you want to rename like this:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Get-Childitem c:\somefolder -Filter cover*.jpg&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another thing to watch out is this: never use &lt;strong&gt;Get-Childitem&lt;/strong&gt; without specifying an absolute or relative path to start with. Else, it will depend on your current path, and that path may change. So the next time you are running your code, it may no longer work because your current path is no longer pointing to the files you want to rename.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule #1:&lt;/strong&gt; Before you resort to &lt;strong&gt;Where-Object&lt;/strong&gt;, make sure the &lt;em&gt;upstream&lt;/em&gt; cmdlet has no built-in parameters to do the same! It is easier and much faster!&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Think PowerShell! Use Pipeline Binding!&lt;/h2&gt;
&lt;p&gt;The next thing is finding the right cmdlet for the action you want to take. &lt;strong&gt;Rename-Item&lt;/strong&gt; was the perfect choice. However, it is not necessary to use &lt;strong&gt;Foreach-Object&lt;/strong&gt; (short: &lt;strong&gt;%&lt;/strong&gt;) to iterate through all the files. Instead, &lt;strong&gt;Rename-Item&lt;/strong&gt; is able to accept the files directly via pipeline. &lt;strong&gt;Get-Help&lt;/strong&gt; can tell you that:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Get-Help -Name Rename-Item -Parameter Path&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It returns: &lt;em&gt;Accept pipeline input?&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; true (ByValue, ByPropertyName) &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So the second part of the solution looks like this:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Get-Childitem c:\somefolder -Filter cover*.jpg | Rename-Item -NewName &amp;quot;somenewname.jpg&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule #2:&lt;/strong&gt; Before you resport to &lt;strong&gt;Foreach-Object&lt;/strong&gt;, make sure the &lt;em&gt;downstream&lt;/em&gt; cmdlet cannot receive your results via pipeline!&lt;/p&gt;
&lt;h2&gt;Think PowerShell! Use Scriptblocks!&lt;/h2&gt;
&lt;p&gt;Of course, renaming a bunch of files to the exact same name will fail, and thus you may be intrigued to use a &lt;strong&gt;foreach-object&lt;/strong&gt; loop after all so you can compose individual file names. But that is not necessary. Many cmdlets accept &lt;strong&gt;scriptblocks&lt;/strong&gt; which resemble executable code, so rather than submitting a fixed name, submit code that composes the name. The final solution looks like this:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;$global:i = 1; dir c:\test1\ -filter cover*.bmp | rename-item -NewName { &amp;quot;picture_$i.jpg&amp;quot;; $global:i++}&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This line will rename all jpg files that start with &amp;quot;cover&amp;quot; in folder c:\test1 to pictureX.jpg where X is an incrementing index number.&lt;/p&gt;
&lt;p&gt;Note the use of &lt;strong&gt;global:&lt;/strong&gt;&amp;nbsp; (you could also use &lt;strong&gt;script:&lt;/strong&gt;). With this prefix, you tell PowerShell to use the same variable. If you omitted that, incrementing $i inside the scriptblock would not have an effect on the global variable $i, because inside a script block, the variable is local and would be discarded each time after the script block was done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule #3:&lt;/strong&gt;&amp;nbsp;Before you design complex code to calculate results for parameters, make sure the parameters do not accept scriptblocks in the first place.&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;Admittedly, this third rule is not that easy to follow because there is no easy way to know whether a parameter can actually receive a script block. &lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Hope to see you next week,&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;Microsoft MVP PowerShell Germany&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=10492" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Where-Object" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Where-Object/default.aspx" /><category term="Pipeline" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Pipeline/default.aspx" /><category term="scriptblock" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/scriptblock/default.aspx" /><category term="golden rule" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/golden+rule/default.aspx" /><category term="foreach-object" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/foreach-object/default.aspx" /><category term="rename" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/rename/default.aspx" /></entry><entry><title>Troubleshooting Windows (and Dimming Your Display, too)</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/05/17/troubleshooting-windows-and-dimming-your-display-too.aspx" /><id>/cs/blogs/tobias/archive/2011/05/17/troubleshooting-windows-and-dimming-your-display-too.aspx</id><published>2011-05-17T07:55:00Z</published><updated>2011-05-17T07:55:00Z</updated><content type="html">&lt;p&gt;You can&amp;#39;t get a device working you just hooked up to your computer? Your computer is running slow? Or you just can&amp;#39;t get these fancy &lt;strong&gt;Aero Glass&lt;/strong&gt; features working? When bad things happen, it&amp;#39;s usually time to get some coffee, lock the door and browse&amp;nbsp;zillions of&amp;nbsp;Internet forums that provide more or less useful suggestions. Or is there a &lt;strong&gt;smarter way&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;With Windows Vista and Server 2008, Microsoft introduced &amp;quot;&lt;strong&gt;TroubleshootingPacks&lt;/strong&gt;&amp;quot; which can &lt;strong&gt;analyze&lt;/strong&gt; and then &lt;strong&gt;solve&lt;/strong&gt; specific &lt;strong&gt;problems&lt;/strong&gt;. They are really a clever idea: if your printer is not working, the printer troubleshooter &amp;quot;knows&amp;quot; all the common pitfalls and can check them for you. Troubleshooters can&amp;#39;t solve everything, so when a troubleshooter can&amp;#39;t come up with an automated solution, you at least know there is nothing stupid you overlooked before you invest hours to investigate yourself.&lt;/p&gt;
&lt;p&gt;Why am I telling you this in my &lt;strong&gt;PowerShell&lt;/strong&gt; blog? Because these &lt;strong&gt;troubleshooters run on PowerShell&lt;/strong&gt;! That&amp;#39;s correct: the entire problem analysis and repair process is plain PowerShell code. So the troubleshooters really are just another type of &lt;strong&gt;PowerShell host&lt;/strong&gt; with a graphical user interface, and you could create your own set of troubleshooters to solve entirely different things.&lt;/p&gt;
&lt;p&gt;Today, I am showing you how you can &lt;strong&gt;invoke troubleshooters&lt;/strong&gt; from PowerShell, &lt;strong&gt;run&lt;/strong&gt; them &lt;strong&gt;unattended&lt;/strong&gt; to get problems solved fast, and &lt;strong&gt;visit the secret core&lt;/strong&gt; of those troubleshooters where you find tons of useful internal code that you can reuse for your own things - like dimming the display after 5pm. Ready? Let&amp;#39;s rock!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Remember that the troubleshooting technology is available only on Windows Vista, Windows 7 and Server 2008/2008 R2 or better. On Windows XP, you can&amp;#39;t use it.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Where are my Troubleshooters?&lt;/h2&gt;
&lt;p&gt;The built-in troubleshooters live in the &lt;strong&gt;diagnostics&lt;/strong&gt; subfolder inside of your Windows folder. There, you find a folder called &lt;strong&gt;index&lt;/strong&gt; which acts like a table of contents, and other folders like &lt;strong&gt;System&lt;/strong&gt; and &lt;strong&gt;Scheduled &lt;/strong&gt;which contain the actual troubleshooters. If you know the &lt;strong&gt;ID&lt;/strong&gt; to a particular troubleshooter, you can invoke it easily from PowerShell. For example, to run the &lt;strong&gt;Printer troubleshooter&lt;/strong&gt;, its ID is &lt;strong&gt;PrinterDiagnostic&lt;/strong&gt;, and this is how you&amp;#39;d launch it from PowerShell:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;Msdt.exe&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;ID PrinterDiagnostic&lt;/div&gt;
&lt;p&gt;This runs the Printer troubleshooter. &lt;strong&gt;Watch out&lt;/strong&gt;: if you happily run the wizard, it will automatically &amp;quot;repair&amp;quot; any problems it detected. Click &lt;strong&gt;Advanced&lt;/strong&gt; and uncheck &lt;strong&gt;Apply repairs automatically&lt;/strong&gt; if you would just like to see a list of detected problems. If you&amp;#39;d like to see other troubleshooters, open control panel:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;control.exe&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;name &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;Microsoft.Troubleshooting&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;This opens a dialog with all the locally installed troubleshooters, and in the left hand column you can click &lt;strong&gt;View All&lt;/strong&gt; to access additional troubleshooters &lt;strong&gt;online&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s all cool, but how do you know the troubleshooter ID you need to invoke from PowerShell? And is there also a way to call troubleshooters silently so they solve the problem without extensive user interaction?&lt;/p&gt;
&lt;h2&gt;Discover the TroubleshootingPack Module&lt;/h2&gt;
&lt;p&gt;Turns out there is. Actually, there is a dedicated PowerShell module for troubleshooters called &lt;strong&gt;TroubleShootingPack&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Module&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ListAvailable&lt;/span&gt;&lt;/span&gt; Tro&lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;*&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;ModuleType Name ExportedCommands&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;----------&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;----&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;----------------&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Manifest TroubleshootingPack&lt;br /&gt;Let&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;s import it and discover the new cmdlets:&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;PS &amp;gt; Import-Module trouble* -verbose&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;VERBOSE: Importing cmdlet &amp;#39;&lt;/span&gt;&lt;/span&gt;Get&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;TroubleshootingPack&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;.&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;VERBOSE: Importing cmdlet &amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-TroubleshootingPack&lt;/span&gt;&lt;/span&gt;&amp;#39;.&lt;/div&gt;
&lt;p&gt;So there are just two cmdlets in it: &lt;strong&gt;Get-TroubleshootingPack&lt;/strong&gt; and &lt;strong&gt;Invoke-TroubleshootingPack&lt;/strong&gt;. &lt;strong&gt;Get-TroubleshootingPack&lt;/strong&gt; gets you all the detail information about a specific troubleshooting pack including its &lt;strong&gt;ID&lt;/strong&gt;. Just specify the path to the folder that contains the troubleshooter:&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-TroubleshootingPack&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\printer | ft &lt;span style="color:#5f9ea0;"&gt;&lt;span class="modifier"&gt;-AutoSize&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Id Name Publisher Version&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;--&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;----&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;---------&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;-------&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;strong&gt;PrinterDiagnostic&lt;/strong&gt; Printer Microsoft Windows 1.0&lt;/div&gt;
&lt;p&gt;As always with objects, piping it to &lt;strong&gt;Select-Object *&lt;/strong&gt; reveals a ton of additional information:&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-TroubleshootingPack&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\printer | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Select-Object&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;*&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Path : C:\Windows\diagnostics\system\printer&lt;br /&gt;Id : PrinterDiagnostic&lt;br /&gt;Version : 1.0&lt;br /&gt;Publisher : Microsoft Windows&lt;br /&gt;Name : Printer&lt;br /&gt;Description : Troubleshoot problems preventing printing from completing.&lt;br /&gt;MinimumVersion : 6.1&lt;br /&gt;PrivacyLink : http:&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;//&lt;/span&gt;&lt;/span&gt;&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;go.microsoft.com&lt;/span&gt;&lt;/span&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;fwlink&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;?LinkId&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;104288&lt;br /&gt;SupportsClient : True&lt;br /&gt;SupportsServer : True&lt;br /&gt;SupportsX86 : True&lt;br /&gt;SupportsAmd64 : True&lt;br /&gt;SupportsIA64 : True&lt;br /&gt;RequiresElevation : True&lt;br /&gt;Interactive : True&lt;br /&gt;RootCauses : {Print Spooler service isn&amp;#39;t running, The Print Spooler ser&lt;br /&gt;vice is experiencing problems, No physical printer is insta&lt;br /&gt;lled, &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;%&lt;/span&gt;&lt;/span&gt;PRINTERNAME&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;%&lt;/span&gt;&lt;/span&gt; is not the default printer...}&lt;br /&gt;FoundRootCauses :&lt;br /&gt;Interactions : {Which printer would you like to troubleshoot?, Which print&lt;br /&gt;er would you like to troubleshoot?, Add a printer, Update t&lt;br /&gt;he printer driver}&lt;br /&gt;ExtensionPoint : &lt;span class="comment"&gt;&lt;span style="color:#008000;"&gt;#document&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h2&gt;Running Troubleshooters Unattended&lt;/h2&gt;
&lt;p&gt;With &lt;strong&gt;Invoke-TroubleshootingPack&lt;/strong&gt;, you can run the troubleshooter. This is not like using &lt;strong&gt;msdt.exe&lt;/strong&gt;, and the troubleshooter does not open a dialog window. Instead, it runs inside of your PowerShell window. Solving the problem is still an interactive process, though:&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-TroubleshootingPack&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\printer | Invo&lt;br /&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;ke-TroubleshootingPack&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Checking the Spooler service...&lt;br /&gt;Checking for Spooler service errors...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Which printer would you like to troubleshoot?&lt;br /&gt;Select the printer that isn&amp;#39;t working correctly.&lt;br /&gt;&lt;br /&gt;[1] Fax&lt;br /&gt;[2] HP LaserJet 4200&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;4300 PCL6&lt;br /&gt;[3] Microsoft XPS Document Writer&lt;br /&gt;[4] DYMO LabelWriter 400 Turbo&lt;br /&gt;&lt;br /&gt;[?] Help&lt;br /&gt;[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;x&lt;/span&gt;&lt;/span&gt;] Exit&lt;br /&gt;:&lt;/div&gt;
&lt;p&gt;To run troubleshooters unattended, you create an answer file with &lt;strong&gt;Get-TroubleshootingPack -answer&lt;/strong&gt;&amp;nbsp;and submit these answers to &lt;strong&gt;Invoke-TroubleshootingPack&lt;/strong&gt;. You then can run troubleshooters even as a scheduled task unattended. &lt;/p&gt;
&lt;p&gt;Here is a great detailed step-by-step introduction on how to create answer files and run troubleshooters unattended: &lt;a target="_blank" href="http://blogs.technet.com/b/heyscriptingguy/archive/2011/02/10/use-powershell-and-scheduled-tasks-to-automate-troubleshooting.aspx"&gt;http://blogs.technet.com/b/heyscriptingguy/archive/2011/02/10/use-powershell-and-scheduled-tasks-to-automate-troubleshooting.aspx&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;ExploitingTroubleshootingPacks&lt;/h2&gt;
&lt;p&gt;Each troubleshooting pack consists of a list of &lt;strong&gt;root causes&lt;/strong&gt; (which describe why a specific problem may have occured), and each root cause has its own PowerShell scripts that identify problems and repair settings. For example, these are the root causes covered by the &lt;strong&gt;Power&lt;/strong&gt; troubleshooter that aims to &lt;strong&gt;maximize your battery life&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-TroubleshootingPack&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\Power).&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;RootCauses&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Name&lt;br /&gt;&lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;----&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Minimum processor state is set too high&lt;br /&gt;Time before display dims is too &lt;span style="color:#0000ff;"&gt;&lt;span class="datatype"&gt;long&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Power plan set to High Performance&lt;br /&gt;Time before display goes to sleep is too &lt;span style="color:#0000ff;"&gt;&lt;span class="datatype"&gt;long&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Time before computer goes to sleep is too &lt;span style="color:#0000ff;"&gt;&lt;span class="datatype"&gt;long&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Time before hard disk goes to sleep is too &lt;span style="color:#0000ff;"&gt;&lt;span class="datatype"&gt;long&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;USB Selective Suspend is disabled&lt;br /&gt;Wireless adapter is not optimized for power saving&lt;br /&gt;Screen saver is enabled&lt;br /&gt;Display brightness setting is too high&lt;/div&gt;
&lt;p&gt;To check what a troubleshooter would do if a root cause was detected, take a look at the resolutions:&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; ( &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-TroubleshootingPack&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\power).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;RootCauses&lt;/span&gt;&lt;/span&gt;[&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;1]&lt;br /&gt;&lt;br /&gt;Name&lt;br /&gt;&lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;----&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Display brightness setting is too high&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PS &amp;gt; ( &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-TroubleshootingPack&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\power).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;RootCauses&lt;/span&gt;&lt;/span&gt;[&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;1].&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Resolutions&lt;/span&gt;&lt;/span&gt; | ft &lt;span style="color:#5f9ea0;"&gt;&lt;span class="modifier"&gt;-AutoSize&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Name Manual Elevation Interactive&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;----&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;------&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;---------&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;-----------&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Decrease the display brightness False True True&lt;/div&gt;
&lt;h2&gt;Reusing TroubleShootingPack Cleverness&lt;/h2&gt;
&lt;p&gt;As you have seen, the &lt;strong&gt;Power&lt;/strong&gt; troubleshootingpack does check for excessive display brightness and also contains a resolution for it. So &lt;strong&gt;it must contain some PowerShell code &lt;/strong&gt;that is actually able &lt;strong&gt;to change the display brightness&lt;/strong&gt;. But how?&lt;br /&gt;Actually, the answer to this is the &lt;strong&gt;ID&lt;/strong&gt; tagged to the resolution:&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; ( &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-TroubleshootingPack&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\power).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;RootCauses&lt;/span&gt;&lt;/span&gt;[&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;1] | select Name, ID&lt;br /&gt;&lt;br /&gt;Name Id&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;----&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;--&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Display brightness setting is too high RC_ScreenBrightness&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;RC_ScreenBrightness&lt;/strong&gt; stands for &amp;quot;&lt;strong&gt;Root Cause ScreenBrightness&lt;/strong&gt;&amp;quot;, and in the troubleshooter folder, you find two corresponding PowerShell scripts: &lt;strong&gt;TS_ScreenBrightness.ps1&lt;/strong&gt; and &lt;strong&gt;RS_ScreenBrightness.ps1&lt;/strong&gt;. TS is short for &amp;quot;TroubleShooter&amp;quot;, and RS contains the resolution code that fixes the problem. Actually, this is a fishy rule of thumb, though. When you look inside the folder, the resolver script is really called &lt;strong&gt;RS_AdjustScreenBrightness.ps1&lt;/strong&gt;. Well, we never said digging into PowerShellPacks was &lt;em&gt;that&lt;/em&gt; easy!&lt;/p&gt;
&lt;p&gt;This code must contain a way to adjust the display brightness, so let&amp;#39;s open that file:&lt;/p&gt;
&lt;div class="pscode"&gt;Notepad &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\power\&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;RS_AdjustScreenBrightness.ps1&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;Whew. It is full of code - and the code isn&amp;#39;t looking too friendly. Before you dig into it, have a look at the beginning of that file: it actually imports a library file called &lt;strong&gt;PowerConfig.ps1&lt;/strong&gt;. That&amp;#39;s where the gems are because this library makes all the energy savings settings accessible from PowerShell.&lt;/p&gt;
&lt;div class="pscode"&gt;Notepad &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\power\&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;powerconfig.ps1&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;As you&amp;#39;ll see, the library encapsulates Windows API functions so they can be called from PowerShell. &lt;/p&gt;
&lt;h2&gt;Dimming Display Brightness for Beginners&lt;/h2&gt;
&lt;p&gt;After three liters of coffee and nothing else to do in my hotel room, I created a little script that is much easier to use. It provides you with simple functions to get and set your notebook display brightness. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get-VideoBrightness&lt;/strong&gt; reads the current brightness percentage, and &lt;strong&gt;Set-VideoBrightness&lt;/strong&gt; sets it. &lt;strong&gt;Get-DefaultVideoBrightness&lt;/strong&gt; returns the recommended brightness level. All functions have a parameter &lt;strong&gt;-isAC&lt;/strong&gt; because there are actually two schemes, one for battery power and one for AC power. This parameter by default is set by &lt;strong&gt;isAC&lt;/strong&gt;, a tiny helper function that finds out whether you are running on battery or not. You can override this parameter, though, if you want to explicitly change the AC or the DC power scheme. You can &lt;a target="_blank" href="http://powershell.com/cs/media/p/10429.aspx"&gt;DOWNLOAD THE SCRIPT here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; this script depends on the &lt;strong&gt;Power&lt;/strong&gt; TroubleshootingPack library so it runs only on systems that have this TroubleshootingPack (like Windows 7). Of course it only works for displays that can be dimmed, so use it on notebooks and not on your servers.&lt;/em&gt;&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span style="color:#008000;"&gt;&lt;span class="comment"&gt;# by Tobias Weltner, PowerShell MVP&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;. &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:windir&lt;/span&gt;&lt;/span&gt;\diagnostics\system\power\&lt;span style="color:#8b4513;"&gt;&lt;span class="namespace"&gt;powerconfig.ps1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; isAC {&lt;br /&gt;(gwmi BatteryStatus &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Namespace&lt;/span&gt;&lt;/span&gt; root\wmi).&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;PowerOnline&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; GetActiveSchemeGuid()&lt;br /&gt;{&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$activeSchemeGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; [&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;PowerConfig&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;ActiveSchemeGuid&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$activeSchemeGuid&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-VideoBrightness&lt;/span&gt;&lt;/span&gt;([&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$isAC&lt;/span&gt;&lt;/span&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;(isAC))&lt;br /&gt;{&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$activeSchemeGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$powerconfig:&lt;/span&gt;&lt;/span&gt;:ActiveSchemeGuid()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$subGroupGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;new-object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;system.Guid&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;7516b95f-f776-4464-8c53-06167f40cc99&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;new-object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;system.Guid&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;aded5e82-b909-4619-9949-f5d71dac0bcb&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingvalue&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; 0&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$res&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; [&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;PowerConfig&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;ReadPowerSetting&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$isAC&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$activeSchemeGuid&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$subGroupGuid&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingGuid&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingvalue&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$res&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-eq&lt;/span&gt;&lt;/span&gt; 0)&lt;br /&gt;{&lt;br /&gt;&lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$settingvalue&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-DefaultVideoBrightness&lt;/span&gt;&lt;/span&gt;([&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$isAC&lt;/span&gt;&lt;/span&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;(isAC))&lt;br /&gt;{&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$BalancedPowerPlan&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$powerconfig:&lt;/span&gt;&lt;/span&gt;:BalancedPowerPlan()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$subGroupGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;new-object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;system.Guid&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;7516b95f-f776-4464-8c53-06167f40cc99&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;new-object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;system.Guid&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;aded5e82-b909-4619-9949-f5d71dac0bcb&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingvalue&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; 0&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$res&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; [&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;PowerConfig&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;ReadDefaultSetting&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$isAC&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$BalancedPowerPlan&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$subGroupGuid&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingGuid&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingvalue&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$res&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-eq&lt;/span&gt;&lt;/span&gt; 0)&lt;br /&gt;{&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$settingvalue&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Set-VideoBrightness&lt;/span&gt;&lt;/span&gt;([&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingvalue&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; 100, [&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$isAC&lt;/span&gt;&lt;/span&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;(isAC))&lt;br /&gt;{&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$activeSchemeGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$powerconfig:&lt;/span&gt;&lt;/span&gt;:ActiveSchemeGuid()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$subGroupGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;new-object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;system.Guid&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;7516b95f-f776-4464-8c53-06167f40cc99&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingGuid&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;new-object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;system.Guid&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;aded5e82-b909-4619-9949-f5d71dac0bcb&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;[&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt;&lt;/span&gt;][&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;PowerConfig&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;WritePowerSetting&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$isAC&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$activeSchemeGuid&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$subGroupGuid&lt;/span&gt;&lt;/span&gt;,[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingGuid&lt;/span&gt;&lt;/span&gt;,&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$settingvalue&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;span class="comment"&gt;# get current video brightness (0-100%)&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Get-VideoBrightness&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;span class="comment"&gt;# get recommended brightness&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Get-DefaultVideoBrightness&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;span class="comment"&gt;# set video brightness (0-100)%&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Set-VideoBrightness&lt;/span&gt;&lt;/span&gt; 100&lt;/div&gt;
&lt;h2&gt;What You Can Do Next&lt;/h2&gt;
&lt;p&gt;As you have seen, &lt;strong&gt;TroubleshootingPacks&lt;/strong&gt; are really &lt;strong&gt;rich PowerShell code repositories&lt;/strong&gt; that contain a lot of clever code to analyze and fix common computer problems. &lt;/p&gt;
&lt;p&gt;Experienced PowerShell scripters can analyze the code and extract the parts they need to control windows. There are a lot more gems to find, especially when it comes to tricky device management.&lt;/p&gt;
&lt;p&gt;Not so experienced PowerShell scripters can take advantage of scripts like the one I provided to dim display brightness, encapsulating all the complex stuff. &lt;/p&gt;
&lt;p&gt;And hey, if you don&amp;#39;t want to rip a TroubleshootingPack apart, you now also know how to run it altogether, interactively or unattended with an answer file. Pretty cool, huh?&lt;/p&gt;
&lt;p&gt;Hope to see you next week,&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;Microsoft MVP PowerShell Germany&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=10430" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="brightness" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/brightness/default.aspx" /><category term="API" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/API/default.aspx" /><category term="dim" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/dim/default.aspx" /><category term="TroubleshootingPack" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/TroubleshootingPack/default.aspx" /><category term="display" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/display/default.aspx" /></entry><entry><title>Multiple Text Replacement Challenge</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/04/28/multiple-text-replacement-challenge.aspx" /><id>/cs/blogs/tobias/archive/2011/04/28/multiple-text-replacement-challenge.aspx</id><published>2011-04-28T02:45:00Z</published><updated>2011-04-28T02:45:00Z</updated><content type="html">&lt;p&gt;Ready for a challenge? Here it is: &lt;em&gt;&lt;strong&gt;take a text, and replace a number of different characters. How would you do that?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I wanted PowerShell to replace all German special characters with alternative text. Boy, was I in for a surprise! &lt;/p&gt;
&lt;p&gt;If you&amp;#39;d like to take on the challenge, &lt;strong&gt;pause&lt;/strong&gt; reading now and go find a good solution! &lt;strong&gt;Then come back&lt;/strong&gt; and compare it with the solutions that came to my mind. &lt;/p&gt;
&lt;p&gt;Ok, if you do take on&amp;nbsp;the challenge, this is the text to work with:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;sterreich &amp;auml;rgert s&amp;uuml;&amp;szlig;e kl&amp;ouml;tenhafte &amp;Auml;rgonauten&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt; 1000&lt;/div&gt;
&lt;p&gt;The job is to do the following replacements:&lt;/p&gt;
&lt;p&gt;&amp;auml; = ae, &amp;ouml; = oe, &amp;uuml; = ue, &amp;Auml; = Ae, &amp;Ouml; = Oe, &amp;Uuml; = Ue, &amp;szlig; = ss&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can &lt;strong&gt;download&lt;/strong&gt; all code samples on this page right here: &lt;a href="http://powershell.com/cs/media/p/10171.aspx"&gt;http://powershell.com/cs/media/p/10171.aspx&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;Creative Solutions using Switch&lt;/h2&gt;
&lt;p&gt;You can use &lt;strong&gt;Switch&lt;/strong&gt; to do multiple string replacements. For it to work, you would need to split the text in characters first, do the replacements, then -&lt;strong&gt;join&lt;/strong&gt; it together. &lt;/p&gt;
&lt;p&gt;The code is clean, and it&amp;#39;s easy to edit the replacement table:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;sterreich &amp;auml;rgert s&amp;uuml;&amp;szlig;e kl&amp;ouml;tenhafte &amp;Auml;rgonauten&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt; 1000&lt;br /&gt;&lt;br /&gt;&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-join&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;switch&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-case&lt;/span&gt;&lt;/span&gt; ( [&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;Char&lt;/span&gt;&lt;/span&gt;[]]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; ) {&lt;br /&gt;&amp;auml; { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ae&amp;#39;&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;&amp;ouml; { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;oe&amp;#39;&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;&amp;uuml; { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ue&amp;#39;&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;&amp;Auml; { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Ae&amp;#39;&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;&amp;Ouml; { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Oe&amp;#39;&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;&amp;Uuml; { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Ue&amp;#39;&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;&amp;szlig; { &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ss&amp;#39;&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;default { &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;})&lt;/div&gt;
&lt;p&gt;With 883 milliseconds, this approach takes a long time to run, though. Bummer.&lt;/p&gt;
&lt;h2&gt;Creative Solutions Using Hashtables&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Hashtables&lt;/strong&gt; are another good way of providing replacement tables in a way that makes it easy to edit and adjust them.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;However, since PowerShell creates hashtables with &lt;strong&gt;case-insensitive keys&lt;/strong&gt;, it is not possible to differentiate between lower case and upper case keys. &lt;/p&gt;
&lt;p&gt;The workaround here is to get the hashtable from &lt;strong&gt;.NET&lt;/strong&gt; directly. This way, &lt;strong&gt;keys are case-sensitive&lt;/strong&gt;. Here is the solution:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;sterreich &amp;auml;rgert s&amp;uuml;&amp;szlig;e kl&amp;ouml;tenhafte &amp;Auml;rgonauten&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt; 1000&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;new-object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Collections&lt;/span&gt;&lt;/span&gt;.&lt;span style="color:#0000ff;"&gt;&lt;span class="datatype"&gt;Hashtable&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;auml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;ae&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;ouml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;oe&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;uuml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;ue&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;Auml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;Ae&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;Ouml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;Oe&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;Uuml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;Ue&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;szlig;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;ss&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;[&lt;span class="optional"&gt;&lt;span style="color:#0000ff;"&gt;Regex&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Replace&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;[$(-join $ht.keys)]&amp;quot;&lt;/span&gt;&lt;/span&gt;, {&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;[&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Args&lt;/span&gt;&lt;/span&gt;[0].&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Value&lt;/span&gt;&lt;/span&gt;]})&lt;/div&gt;
&lt;p&gt;With 405 milliseconds, this approach is a lot faster. However, it is still relatively slow, and the way the text is actually replaced is a bit complex, using a regex replacement with a dynamic function.&lt;/p&gt;
&lt;h2&gt;Using a Replacement Table - Much Faster&lt;/h2&gt;
&lt;p&gt;I did like the idea of using a hash table as a replacement table, though. I did not like the complex regex clause, and of course I wanted it faster. &lt;/p&gt;
&lt;p&gt;So here is the next version. It uses a &lt;strong&gt;foreach&lt;/strong&gt; loop and the &lt;strong&gt;-creplace&lt;/strong&gt; operator:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;sterreich &amp;auml;rgert s&amp;uuml;&amp;szlig;e kl&amp;ouml;tenhafte &amp;Auml;rgonauten&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt; 1000&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;new-object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Collections&lt;/span&gt;&lt;/span&gt;.&lt;span style="color:#0000ff;"&gt;&lt;span class="datatype"&gt;Hashtable&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;auml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;ae&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;ouml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;oe&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;uuml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;ue&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;Auml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;Ae&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;Ouml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;Oe&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;Uuml;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;Ue&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&amp;szlig;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;ss&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$key&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;in&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Keys&lt;/span&gt;&lt;/span&gt;) { &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-creplace&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$key&lt;/span&gt;&lt;/span&gt;, &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$ht&lt;/span&gt;&lt;/span&gt;.&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$key&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;This code &lt;strong&gt;just takes 7,3 milliseconds&lt;/strong&gt;, so it runs &lt;strong&gt;55x faster&lt;/strong&gt; - wow. Can it run even faster? &lt;/p&gt;
&lt;h2&gt;Hard Coding - and a Big Surprise&lt;/h2&gt;
&lt;p&gt;Inspired by the top performance &lt;strong&gt;-creplace&lt;/strong&gt; delivered, I next tried a hard-coding approach:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;sterreich &amp;auml;rgert s&amp;uuml;&amp;szlig;e kl&amp;ouml;tenhafte &amp;Auml;rgonauten&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt; 1000&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-creplace&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;auml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ae&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-creplace&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;ouml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;oe&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-creplace&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;uuml;&amp;#39;&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ue&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-creplace&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Auml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Auml;e&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-creplace&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Oe&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-creplace&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Uuml;&amp;#39;&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Ue&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-creplace&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;szlig;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ss&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;Surprisingly, this code was &lt;strong&gt;not faster&lt;/strong&gt; than the previous approach. Considering how ugly and unflexible this code was, I moved on immediately in disgust.&lt;/p&gt;
&lt;h2&gt;Hard Coding again - and another Surprise&lt;/h2&gt;
&lt;p&gt;Next, I tried another hard-coded approach, this time using &lt;strong&gt;string methods&lt;/strong&gt; over regular expressions:&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;sterreich &amp;auml;rgert s&amp;uuml;&amp;szlig;e kl&amp;ouml;tenhafte &amp;Auml;rgonauten&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt; 1000&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Replace&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;auml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ae&amp;#39;&lt;/span&gt;&lt;/span&gt;).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Replace&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;ouml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;oe&amp;#39;&lt;/span&gt;&lt;/span&gt;).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Replace&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;uuml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ue&amp;#39;&lt;/span&gt;&lt;/span&gt;).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Replace&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Auml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Ae&amp;#39;&lt;/span&gt;&lt;/span&gt;).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Replace&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Oe&amp;#39;&lt;/span&gt;&lt;/span&gt;).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Replace&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Uuml;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;Ue&amp;#39;&lt;/span&gt;&lt;/span&gt;).&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Replace&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;szlig;&amp;#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;ss&amp;#39;&lt;/span&gt;&lt;/span&gt;)&lt;/p&gt;
&lt;p&gt;While this code was ugly, too, &lt;strong&gt;with just 2 milliseconds it ran lightning fast&lt;/strong&gt;. There is no faster way for multiple string replacements.&lt;/p&gt;
&lt;h2&gt;Dynamic Code Combines Best of Both Worlds&lt;/h2&gt;
&lt;p&gt;So I finally was looking for a way to take advantage of the speed yet create a code design that would allow it to&amp;nbsp;edit and adjust&amp;nbsp;the replacement strings dynamically. Here it is:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;Ouml;sterreich &amp;auml;rgert s&amp;uuml;&amp;szlig;e kl&amp;ouml;tenhafte &amp;Auml;rgonauten&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;*&lt;/span&gt;&lt;/span&gt; 1000&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$t&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;&amp;auml;,ae,&amp;ouml;,oe,&amp;uuml;,ue,&amp;Auml;,Ae,&amp;Ouml;,Oe,&amp;Uuml;,Ue,&amp;szlig;,ss&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-Expression&lt;/span&gt;&lt;/span&gt; (&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;$text&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;+&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-join&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$e&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;in&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$t&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Split&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;/span&gt;)) { &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;.Replace(&amp;quot;{0}&amp;quot;,&amp;quot;{1}&amp;quot;)&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-f&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$e&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;([&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$foreach&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MoveNext&lt;/span&gt;&lt;/span&gt;();&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$foreach&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Current&lt;/span&gt;&lt;/span&gt;) &lt;br /&gt;} &lt;br /&gt;))&lt;/div&gt;
&lt;p&gt;With still less than 3 milliseconds, this &lt;strong&gt;approach was super fast, 338x faster than the original approach&lt;/strong&gt;. Note how it uses &lt;strong&gt;Invoke-Expression&lt;/strong&gt; to actually &lt;strong&gt;generate dynamic code on-the-fly&lt;/strong&gt;, so it is no longer hard-coding the replacement strings. With the list of replacement texts in &lt;strong&gt;$t&lt;/strong&gt;, it is very easy to adjust. So I decided to stick with this one and make it a function:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Update-Text&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;[Parameter(Mandatory&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$true&lt;/span&gt;&lt;/span&gt;)]&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$text&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$replacementlist&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;&amp;auml;,ae,&amp;ouml;,oe,&amp;uuml;,ue,&amp;Auml;,Ae,&amp;Ouml;,Oe,&amp;Uuml;,Ue,&amp;szlig;,ss&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-Expression&lt;/span&gt;&lt;/span&gt; (&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;$text&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;+&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-join&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$e&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;in&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$replacementlist&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Split&lt;/span&gt;&lt;/span&gt;(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;/span&gt;)) { &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;.Replace(&amp;quot;{0}&amp;quot;,&amp;quot;{1}&amp;quot;)&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-f&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$e&lt;/span&gt;&lt;/span&gt;, &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;[&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt;&lt;/span&gt;]&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$foreach&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MoveNext&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$foreach&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Current&lt;/span&gt;&lt;/span&gt;) &lt;br /&gt;} &lt;br /&gt;)&lt;br /&gt;)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PS &amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Update-Text&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;This is a test&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;#39;T,t,i,I,te,TE&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;thIs Is a TEst&lt;/div&gt;
&lt;p&gt;Hope to see you next week,&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;Microsoft MVP PowerShell Germany&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=10170" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Split" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Split/default.aspx" /><category term="performance" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/performance/default.aspx" /><category term="foreach" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/foreach/default.aspx" /><category term="Text" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Text/default.aspx" /><category term="Invoke-Expression" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Invoke-Expression/default.aspx" /><category term="Replace" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Replace/default.aspx" /><category term="Switch" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Switch/default.aspx" /><category term="-creplace" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/-creplace/default.aspx" /><category term="-replace" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/-replace/default.aspx" /></entry><entry><title>One PowerShell Tip A Day Keeps The Doctor Away</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/04/12/one-powershell-tip-a-day-keeps-the-doctor-away.aspx" /><id>/cs/blogs/tobias/archive/2011/04/12/one-powershell-tip-a-day-keeps-the-doctor-away.aspx</id><published>2011-04-12T15:19:00Z</published><updated>2011-04-12T15:19:00Z</updated><content type="html">&lt;p&gt;You probably know I have been writing one PowerShell tip every day - since 2008. This piled up to a &lt;a target="_blank" href="http://powershell.com/cs/blogs/tips/"&gt;tremendous gold mine of little tips and tricks&lt;/a&gt; you can use to improve your code.&lt;/p&gt;
&lt;p&gt;Sometimes, the truly amazing thing is to see what &lt;strong&gt;&lt;em&gt;you&lt;/em&gt;&lt;/strong&gt; do with these bits and pieces, and today I&amp;#39;d like to thank &lt;em&gt;Robbie Wiley&lt;/em&gt; for sharing his personal use case and how he redesigned it using one of our last weeks&amp;#39; tips.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;quot; I have a function called Get-Scrapnotes that I use to find a series of text files that I create each month.&amp;nbsp; The file is always called scrapnotes.txt and it has been my practice for several years to archive that file. WHERE it has been archived has changed a little bit over the years.&amp;nbsp; I have to look for it in my archive directory at 1 or 2 levels deep beneath the year/month directory.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Turning Slow Code into Fast Code&lt;/h3&gt;
&lt;p&gt;One of the first solutions Robbie came up with was to use &lt;strong&gt;Get-Childitem&lt;/strong&gt; with &lt;strong&gt;-recurse&lt;/strong&gt; like this:&lt;/p&gt;
&lt;p&gt;Get-ChildItem e:\archives&lt;em&gt; &lt;strong&gt;-include&lt;/strong&gt;&lt;/em&gt; &amp;#39;scrapnotes.txt&amp;#39; -recurse&lt;/p&gt;
&lt;p&gt;This worked but took minutes to complete because it had to visit any single folder below the archives directory, and some of which were extensive. It also was using slow &amp;#39;client side&amp;#39; filtering: &lt;strong&gt;Get-ChildItem&lt;/strong&gt; first gets every single file, and then &lt;strong&gt;-include&lt;/strong&gt; picks the one you want. &lt;/p&gt;
&lt;p&gt;After some investigation, Robbie improved the solution:&lt;/p&gt;
&lt;p&gt;Get-ChildItem e:\archives &lt;em&gt;&lt;strong&gt;-filter&lt;/strong&gt;&lt;/em&gt; &amp;#39;scrapnotes.txt&amp;#39; -recurse&lt;/p&gt;
&lt;p&gt;This cut the time almost in half because &lt;strong&gt;-filter&lt;/strong&gt; is using &amp;quot;server side&amp;quot; filtering: &lt;strong&gt;Get-Childitem&lt;/strong&gt; gets the files you want in the first place and skips all others. Still, it took minutes to run.&lt;/p&gt;
&lt;p&gt;He then created a sophisticated script to optimize the other source of performance penalty: to limit the number of subfolders the script needed to visit. His script did improve execution time considerably but&amp;nbsp;was too large, complex&amp;nbsp;and specific to share here.&lt;/p&gt;
&lt;h3&gt;Searching Just Two Levels Deep&lt;/h3&gt;
&lt;p&gt;Last week we published the tip below&amp;nbsp;that inspired Robbie to revisit his solution and improve it a bit more:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Did you know that you can use multiple wildcards in paths? This will give you a lot of control. Check this out: This line will find all DLL-files in all sub-folders up to two levels below your Windows folder:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Resolve-Path $env:windir\*\*\*.dll -ea 0&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;And this line will lists the Desktop folder content for all user accounts on your computer-provided that you have sufficient privileges:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;dir c:\users\*\desktop\*&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Take a look what exactly Robbie did with this piece of information. Since he knew the files he was looking for were located anywhere within the first two subdirectory levels, he managed to search just these levels within a matter of milliseconds, using the wildcard trick:&lt;/p&gt;
&lt;p&gt;$scrapnotes = @()&lt;br /&gt;$scrapnotes += resolve-path E:\Archives\20*\*\*\scrapnotes.txt -ea 0 | % {Get-Item $_.path} &lt;br /&gt;$scrapnotes += resolve-path E:\Archives\20*\*\scrapnotes.txt -ea 0 | %{Get-Item $_.path} &lt;br /&gt;$scrapnotes += resolve-path E:\Archives\20*\scrapnotes.txt -ea 0 | %{Get-Item $_.path} &lt;br /&gt;$scrapnotes = $scrapnotes | sort creationtime&lt;/p&gt;
&lt;p&gt;That is pretty excellent. Thanks Robbie for sharing this!&lt;/p&gt;
&lt;p&gt;Hope to see you next week,&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;Microsoft MVP PowerShell Germany&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;tobias.weltner@scriptinternals.de&lt;/a&gt;&amp;nbsp; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=9952" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Recurse" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Recurse/default.aspx" /><category term="Resolve-Path" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Resolve-Path/default.aspx" /><category term="Wildcard" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Wildcard/default.aspx" /></entry><entry><title>Executing Code On Behalf Of Someone Else</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/03/13/executing-code-on-behalf-of-someone-else.aspx" /><id>/cs/blogs/tobias/archive/2011/03/13/executing-code-on-behalf-of-someone-else.aspx</id><published>2011-03-13T15:19:00Z</published><updated>2011-03-13T15:19:00Z</updated><content type="html">&lt;p&gt;In almost all of my trainings I get this question: &lt;em&gt;&amp;quot;Can I launch a program remotely so another user can actually see it?&amp;quot;&lt;/em&gt; To answer that question, I&amp;#39;d like to &lt;strong&gt;take you on a quick security tour&lt;/strong&gt; and provide you with a test tool that may or may not &lt;strong&gt;produce surprising results&lt;/strong&gt; in your environment.&lt;/p&gt;
&lt;h3&gt;Why Launching Things For Other Users Can Be Bad&lt;/h3&gt;
&lt;p&gt;Back in the old days, you were able to use &lt;strong&gt;WMI&lt;/strong&gt; to launch a process visibly in another users context. So if you were working at some help desk, and a user called in, you could simply help them and launch things for them. However, anything you launched continued to run under your account, so if you launched a &lt;strong&gt;notepad.exe&lt;/strong&gt; for someone else, that person &lt;strong&gt;was able to use notepad with your credentials&lt;/strong&gt;. Of course, Microsoft disabled that for security reasons.&lt;/p&gt;
&lt;p&gt;Today, when the target is &lt;strong&gt;Windows Vista/Server 2008 or better&lt;/strong&gt;, you can again &lt;strong&gt;launch processes visibly in another users context&lt;/strong&gt;. This time, however, the &lt;strong&gt;task scheduler&lt;/strong&gt; is used. It can be instructed to launch whatever you want in the interactive session of someone else. All you need is this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Local Administrator privileges on the target machine&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Windows Vista/W7 or Server 2008/R2 on all machines&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the task scheduler runs the task on behalf of the target person, you are not jeopardizing your own identity anymore. The user can use whatever you launched, but he will be using it with his own privileges, not yours. &lt;/p&gt;
&lt;p&gt;That sounds great&lt;strong&gt; until you start thinking backwards. What if the person I am launching the program for has actually more privileges that I do?&lt;/strong&gt; Huh?&lt;/p&gt;
&lt;h3&gt;Houston - We (Might) Have&amp;nbsp;A Problem!&lt;/h3&gt;
&lt;p&gt;Which brings us to the &lt;strong&gt;second objective&lt;/strong&gt; of this post: &lt;strong&gt;Security&lt;/strong&gt;. In not so few companies, &lt;strong&gt;local admin accounts&lt;/strong&gt; are &lt;strong&gt;below security radar&lt;/strong&gt;. Sometimes, the password for the local &amp;quot;Administrator&amp;quot; account is even common knowledge because it is used whenever someone needs to install something special or change settings. That&amp;#39;s convenient until people start to realize that a &lt;strong&gt;local administrator&lt;/strong&gt; is &lt;strong&gt;potentially just as powerful as the most powerful domain account&lt;/strong&gt; that exists in your entire company. Let&amp;#39;s check out why.&lt;/p&gt;
&lt;p&gt;With the task scheduler, &lt;strong&gt;any local admin can launch programs on behalf of the logged on user&lt;/strong&gt;. So if that user happens to be &lt;strong&gt;Enterprise Admin&lt;/strong&gt;, and you wouldn&amp;#39;t launch something as cute as notepad.exe but instead a PowerShell script that adds your account (or all accounts in your company)&amp;nbsp;to the Domain Admin group, you probably can imagine what this means to corporate security. Since the script runs on behalf of the other person, if someone analyzes the change to find out the bad guy, logs won&amp;#39;t show the true script initiator but instead the person that it was scheduled for.&lt;/p&gt;
&lt;p&gt;So is this an &lt;strong&gt;exploit&lt;/strong&gt;? Something to &lt;strong&gt;get really excited about?&lt;/strong&gt; &lt;strong&gt;No&lt;/strong&gt; - except if you did not realize the importance of local admin accounts in overall corporate security. A local admin &lt;strong&gt;owns&lt;/strong&gt; a local machine. So a local admin could have installed&amp;nbsp;a key logger, replaced explorer.exe with some malicious clone, or simply put script code into the logon script of someone else. The script I am going to present is special only in that it is (a) pretty easy to use and (b) a great &lt;strong&gt;security intrusion detector&lt;/strong&gt; because if you really can do something bad with it, then it&amp;#39;s time to seriously review your security settings.&lt;/p&gt;
&lt;h3&gt;Word Of Caution&lt;/h3&gt;
&lt;p&gt;Use the script to &lt;strong&gt;test-drive your security only&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;If you are a &lt;strong&gt;domain admin&lt;/strong&gt;, then &lt;strong&gt;you know&lt;/strong&gt; you have plentyful privileges but still might find&amp;nbsp;the script&amp;nbsp;useful to launch software visibly for other people. Since you are domain admin, &lt;strong&gt;you are authorized to do this&lt;/strong&gt;. If you abuse your privileges, then that&amp;#39;s like stealing pencils or selling company secrets, and you get into trouble. &lt;/p&gt;
&lt;p&gt;If you are however a &lt;strong&gt;regular user&lt;/strong&gt; and you still can launch things on behalf of others, or if you know local admin credentials because they are not kept secret, and you can use them to launch things in other users sessions, then you know &lt;strong&gt;something is wrong&lt;/strong&gt;. Don&amp;#39;t continue to use this script to launch &amp;quot;special&amp;quot; websites on behalf of your boss just to see what happens next,&amp;nbsp;or fire up 1000 instances of excel on behalf of that buddy of yours down the isle. Instead, &lt;strong&gt;report it to your security department&lt;/strong&gt; to help create more awareness.&lt;/p&gt;
&lt;h3&gt;Launching Commands On Behalf of Someone Else&lt;/h3&gt;
&lt;p&gt;The following script provides a function called &lt;strong&gt;Start-ProcessInteractive&lt;/strong&gt;. You can specify a target computer, a path to an executable on that computer and also some arguments. If you do not specify a path and arguments, then the defaults will run a powershell command and write a file into the target windows folder. That&amp;#39;s a proof-of-concept, because if that command works it illustrates that the PowerShell command was launched with full privileges.&lt;/p&gt;
&lt;p&gt;The function schedules the task for the &lt;strong&gt;currently logged on&lt;/strong&gt; user. If no currently logged on user could be identified, then either no user was physically logged on, or the target machine is running &lt;strong&gt;virtual machines&lt;/strong&gt; in which case you can manually submit the user account you want to schedule the command for.&lt;/p&gt;
&lt;p&gt;Note that this type of task scheduling &lt;strong&gt;requires Windows Vista/Server 2008&lt;/strong&gt; or higher. It will not work on XP.&lt;/p&gt;
&lt;p&gt;You can &lt;a target="_blank" href="http://powershell.com/cs/media/p/9660.aspx"&gt;download the script here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Start-ProcessInteractive&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$filepath&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;powershell.exe&amp;#39;&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$arguments&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;-noprofile -command Get-Date | Out-File $env:windir\testfile.txt&amp;#39;&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;[Parameter(Mandatory&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$true&lt;/span&gt;&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$computername&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Execute-Tool&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$r&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-Expression&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;) 2&amp;gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;&amp;amp;&lt;/span&gt;&lt;/span&gt;1&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$LASTEXITCODE&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-ne&lt;/span&gt;&lt;/span&gt; 0) { Throw &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$r&lt;/span&gt;&lt;/span&gt;[0].&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;Exception.Message&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$computername&lt;/span&gt;&lt;/span&gt; | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;ForEach-Object&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;try {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$username&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-WmiObject&lt;/span&gt;&lt;/span&gt; Win32_ComputerSystem &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ComputerName&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$_&lt;/span&gt;&lt;/span&gt; | &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Select-Object&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ExpandProperty&lt;/span&gt;&lt;/span&gt; UserName&lt;br /&gt;} catch {}&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$computer&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$_&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$username&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-eq&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$null&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Write-Warning&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;On $computername no user is currently physically logged on.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$username&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Read-Host&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;Enter username of logged on user at the remote system&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$username&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-ne&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$xml&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; @&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;?xml version=&amp;quot;&lt;/span&gt;&lt;/span&gt;1.0&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot; encoding=&amp;quot;&lt;/span&gt;&lt;/span&gt;UTF&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;16&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;?&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Task version=&amp;quot;&lt;/span&gt;&lt;/span&gt;1.2&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot; xmlns=&amp;quot;&lt;/span&gt;&lt;/span&gt;http:&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;//&lt;/span&gt;&lt;/span&gt;&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;schemas.microsoft.com&lt;/span&gt;&lt;/span&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;windows&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;2004&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;02&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;mit&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;/&lt;/span&gt;&lt;/span&gt;task&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;RegistrationInfo /&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Triggers /&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Settings&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;MultipleInstancesPolicy&amp;gt;IgnoreNew&amp;lt;/MultipleInstancesPolicy&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;DisallowStartIfOnBatteries&amp;gt;false&amp;lt;/DisallowStartIfOnBatteries&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;StopIfGoingOnBatteries&amp;gt;false&amp;lt;/StopIfGoingOnBatteries&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;AllowHardTerminate&amp;gt;true&amp;lt;/AllowHardTerminate&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;StartWhenAvailable&amp;gt;false&amp;lt;/StartWhenAvailable&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;RunOnlyIfNetworkAvailable&amp;gt;false&amp;lt;/RunOnlyIfNetworkAvailable&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;IdleSettings /&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;AllowStartOnDemand&amp;gt;true&amp;lt;/AllowStartOnDemand&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Enabled&amp;gt;true&amp;lt;/Enabled&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Hidden&amp;gt;false&amp;lt;/Hidden&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;RunOnlyIfIdle&amp;gt;false&amp;lt;/RunOnlyIfIdle&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;WakeToRun&amp;gt;false&amp;lt;/WakeToRun&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;ExecutionTimeLimit&amp;gt;PT72H&amp;lt;/ExecutionTimeLimit&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Priority&amp;gt;7&amp;lt;/Priority&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;/Settings&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Actions Context=&amp;quot;&lt;/span&gt;&lt;/span&gt;Author&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Exec&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Command&amp;gt;$filepath&amp;lt;/Command&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Arguments&amp;gt;$arguments&amp;lt;/Arguments&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;/Exec&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;/Actions&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Principals&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;Principal id=&amp;quot;&lt;/span&gt;&lt;/span&gt;Author&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;UserId&amp;gt;$username&amp;lt;/UserId&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;LogonType&amp;gt;InteractiveToken&amp;lt;/LogonType&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;RunLevel&amp;gt;HighestAvailable&amp;lt;/RunLevel&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;/Principal&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;/Principals&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;lt;/Task&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;@&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$jobname&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;remotejob{0}&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-f&lt;/span&gt;&lt;/span&gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Random&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;try {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$xml&lt;/span&gt;&lt;/span&gt; | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Out-File&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;$env:temp\tj1.xml&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Execute-Tool&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;schtasks /CREATE /TN $jobname /XML $env:temp\tj1.xml /S $computer&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Start-Sleep&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Seconds&lt;/span&gt;&lt;/span&gt; 1&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Execute-Tool&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;schtasks /RUN /TN $jobname /S $computer&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Execute-Tool&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;schtasks /DELETE /TN $jobname /s $computer /F&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;catch {&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Write-Warning&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;$_ (trying to access user &amp;#39;$username&amp;#39; on system &amp;#39;$computer&amp;#39;)&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;/div&gt;
&lt;p&gt;I have used this script successfully&amp;nbsp;in a number of environments but &lt;strong&gt;I cannot guarantee anything&lt;/strong&gt;. It is just a proof-of-concept.&amp;nbsp;I am&amp;nbsp;looking forward&amp;nbsp;to get your feedback.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security is important&lt;/strong&gt;, and I sincerely hope I was able to illustrate why &lt;strong&gt;protecting even local admin accounts is important&lt;/strong&gt; in any good security concept. If you feel that this script &lt;strong&gt;could do harm in your environment&lt;/strong&gt;, then don&amp;#39;t blame the script for it. Instead, make sure it can&amp;#39;t do harm by &lt;strong&gt;reviewing your corporate security settings&lt;/strong&gt;. This script is just one example of a multitude of other approaches that take advantage of the power of local admins. So if this script can do something it shouldn&amp;#39;t, then a heck of a number of other techniques could, too. Close that security hole.&lt;/p&gt;
&lt;p&gt;If &lt;strong&gt;security is not important&lt;/strong&gt; to you (or your security is in great shape), then you still might find that script useful. It &lt;strong&gt;demonstrates&lt;/strong&gt; how to &lt;strong&gt;schedule tasks using XML&lt;/strong&gt;. The problem with the regular command line switches is that they are (a) localized (different for every language/culture) and (b) incomplete. You cannot control all the things you can set up when scheduling a task using the UI. With XML, you can define the task culture-neutral and you have access to all settings.&lt;/p&gt;
&lt;p&gt;Hope to see you next week,&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=9661" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="Security" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Security/default.aspx" /><category term="Start-ProcessInteractive" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Start-ProcessInteractive/default.aspx" /><category term="Task Scheduler" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Task+Scheduler/default.aspx" /></entry><entry><title>Analyzing Networks With PowerShell</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/03/09/analyzing-networks-with-powershell.aspx" /><id>/cs/blogs/tobias/archive/2011/03/09/analyzing-networks-with-powershell.aspx</id><published>2011-03-09T02:16:00Z</published><updated>2011-03-09T02:16:00Z</updated><content type="html">&lt;p&gt;I often need to &lt;strong&gt;analyze networks&lt;/strong&gt; and &lt;strong&gt;find machines and IP addresses&lt;/strong&gt;. So today, I am going to&amp;nbsp;share a set of four (4) very useful PowerShell functions that make it easy to analyze network segments - and they are pretty fast, too! This is the second part of a 2-part-series. &lt;a target="_blank" href="http://powershell.com/cs/blogs/tobias/archive/2011/02/20/creating-ip-ranges-and-other-type-magic.aspx"&gt;Here is the first part btw&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Check this out: this simple line just scanned my hotel wlan and returned my neighbors computers&amp;nbsp;IP addresses (and some host names) in about 5 seconds:&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-IPRange&lt;/span&gt;&lt;/span&gt; | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Test-Online&lt;/span&gt;&lt;/span&gt; | &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Get-HostName&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;HostName Aliases AddressList&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;--------&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-------&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;-----------&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;server.mshome.net&lt;/span&gt;&lt;/span&gt; {} {192.168.0.1}&lt;br /&gt;SCHUPIAP1 {} {192.168.0.50}&lt;br /&gt;WARNING: IP 192.168.0.51 did not &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;&lt;/span&gt; DNS information&lt;br /&gt;WARNING: IP 192.168.0.52 did not &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;&lt;/span&gt; DNS information&lt;br /&gt;WARNING: IP 192.168.0.53 did not &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;&lt;/span&gt; DNS information&lt;br /&gt;demo5 {} {192.168.0.158}&lt;/div&gt;
&lt;p&gt;Of course the &lt;strong&gt;real value&lt;/strong&gt; is not sniffing through public networks. That&amp;#39;s what you do when you are grounded at some hotel and bored. In real life, you would use these functions to &lt;strong&gt;find network devices, printers&lt;/strong&gt;, or just &lt;strong&gt;identify&lt;/strong&gt; online systems that are ready and available&amp;nbsp;for &lt;strong&gt;remote access&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Network Analyzing&amp;nbsp;Tools Made by PowerShell&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;I decided to create these four PowerShell functions:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-IPAddress&lt;/span&gt;&lt;/span&gt; [&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-first&lt;/span&gt;&lt;/span&gt;] [&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-IPv4&lt;/span&gt;&lt;/span&gt;] [&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-IPv6&lt;/span&gt;&lt;/span&gt;] &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-IPRange&lt;/span&gt;&lt;/span&gt; [&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-first&lt;/span&gt;&lt;/span&gt;] &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-IPRange&lt;/span&gt;&lt;/span&gt; [&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-start&lt;/span&gt;&lt;/span&gt; &amp;lt;&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;/span&gt;&amp;gt;] [&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-end&lt;/span&gt;&lt;/span&gt; &amp;lt;&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;/span&gt;&amp;gt;] &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Test-Online&lt;/span&gt;&lt;/span&gt; [&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-computername&lt;/span&gt;&lt;/span&gt;] &amp;lt;&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;/span&gt;&amp;gt; [[&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-throttleLimit&lt;/span&gt;&lt;/span&gt;] &amp;lt;Int32&amp;gt;] &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-HostName&lt;/span&gt;&lt;/span&gt; [&lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-IPAddress&lt;/span&gt;&lt;/span&gt;] &amp;lt;&lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;/span&gt;[]&amp;gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Get-IPAddress&lt;/strong&gt; returns your current IP address(es). You can select whether you want &lt;strong&gt;IPv4&lt;/strong&gt;, &lt;strong&gt;IPv6&lt;/strong&gt; or both, and whether you want just the first available IP address or all of them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New-IPRange&lt;/strong&gt; creates an IPv4 address range. If you don&amp;#39;t specify anything, you get the range your network adapter is in. You can also use &lt;strong&gt;-start&lt;/strong&gt; and &lt;strong&gt;-end&lt;/strong&gt; to create other IP address ranges&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test-Online&lt;/strong&gt; uses &lt;strong&gt;background jobs&lt;/strong&gt; and parallel processing to ping a range of ip addresses. It is very fast. &lt;strong&gt;-throttleLimit&lt;/strong&gt;&amp;nbsp;controls how many simultaneous pings&amp;nbsp;are used. The &lt;strong&gt;default is 300&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get-HostName&lt;/strong&gt; resolves a list of ip addresses and returns host name and alias.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can &lt;a target="_blank" href="http://powershell.com/cs/media/p/9600.aspx"&gt;download the functions&lt;/a&gt; here.&lt;/p&gt;
&lt;h3&gt;Some Background&lt;/h3&gt;
&lt;p&gt;PowerShell comes with a cmdlet called &lt;strong&gt;Test-Connection&lt;/strong&gt; which can &amp;ldquo;ping&amp;rdquo; ip addresses and host names. Like most cmdlets, it &lt;strong&gt;works sequentially&lt;/strong&gt; by default. &lt;strong&gt;Pinging hundreds of computers can become a lengthy task&lt;/strong&gt;. Fortunately, PowerShell V2 supports &lt;strong&gt;background jobs&lt;/strong&gt;. That way, tasks can be executed in &lt;strong&gt;parallel rather than sequentially&lt;/strong&gt;. Pinging an entire network segment now&amp;nbsp;takes only seconds.&lt;/p&gt;
&lt;p&gt;The most efficient way to use PowerShells new background job capabilities is to &lt;strong&gt;use cmdlets that support background jobs natively&lt;/strong&gt;. These cmdlets all support the &lt;strong&gt;&amp;ndash;asJob&lt;/strong&gt; switch parameter.&lt;/p&gt;
&lt;p&gt;To make it simple to ping your current network segment, &lt;strong&gt;Get-IPAddress&lt;/strong&gt; can find out your own IP address, and &lt;strong&gt;New-IPRange&lt;/strong&gt; uses this to return all IP addresses within that segment. &lt;/p&gt;
&lt;p&gt;You can then pipe the IP address list to &lt;strong&gt;Test-Online&lt;/strong&gt;, and after just a couple of seconds, you receive a filtered IP address list with only online addresses.&lt;/p&gt;
&lt;p&gt;Of course, the cmdlet &lt;strong&gt;Test-Connection&lt;/strong&gt; used by &lt;strong&gt;Test-Online&lt;/strong&gt; has &lt;strong&gt;limited ressources&lt;/strong&gt;, and once you process more than 400 or so addresses at once, you may get exceptions. That&amp;#39;s why it makes sense to &lt;strong&gt;implement a throttle limit&lt;/strong&gt;. This works by &lt;strong&gt;splitting&lt;/strong&gt; arrays of &lt;strong&gt;IP addresses into chunks&lt;/strong&gt; and processing these chunks sequentially. Throttling needs to be implemented manually by &lt;strong&gt;Test-Online&lt;/strong&gt; &amp;nbsp;because the &lt;strong&gt;-throttleLimit&lt;/strong&gt; parameter supported natively by &lt;strong&gt;Test-Connection&lt;/strong&gt; is broken and does not do anything.&lt;/p&gt;
&lt;h3&gt;What&amp;#39;s Next?&lt;/h3&gt;
&lt;p&gt;More fun is coming up. I am currently teaching PowerShell at a number of companies and universities, and we always find interesting things to play with. For example,&amp;nbsp;we&amp;nbsp;&lt;strong&gt;just created a script to launch commands on behalf of someone&lt;/strong&gt; else.&amp;nbsp;It&amp;nbsp;was&amp;nbsp;considerable fun to &lt;strong&gt;open&amp;nbsp;web pages in the session of our enterprise admin&lt;/strong&gt; (although his amusement was somewhat limited).&amp;nbsp;&amp;nbsp;It was not so much fun anymore when we &lt;strong&gt;discovered &lt;/strong&gt;that we could launch &lt;strong&gt;arbitary PowerShell code&lt;/strong&gt; with &lt;strong&gt;full privileges&lt;/strong&gt;&amp;nbsp;on his behalf. All we needed were local admin rights on his machine, and it is common practice to grant this to a lot of folks&amp;nbsp;in many companies (but obviously &lt;strong&gt;not a good idea as you&amp;#39;ll see&lt;/strong&gt;). &lt;/p&gt;
&lt;p&gt;So before I share with you excatly how that worked and what we did, I&amp;#39;d like to check back with a couple of folks and also want to point out that this whole thing really primarily emphasizes &lt;strong&gt;how important &lt;/strong&gt;even &lt;strong&gt;local admin accounts are for&lt;/strong&gt; &lt;strong&gt;corporate security&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Hope you had fun, see you around next week ...&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=9601" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="ping" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/ping/default.aspx" /><category term="Test-Connection" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Test-Connection/default.aspx" /><category term="New-IPRange" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/New-IPRange/default.aspx" /><category term="Online" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Online/default.aspx" /><category term="Background Job" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/Background+Job/default.aspx" /></entry><entry><title>Accessing Databases from PowerShell</title><link rel="alternate" type="text/html" href="/cs/blogs/tobias/archive/2011/03/01/accessing-data-bases.aspx" /><id>/cs/blogs/tobias/archive/2011/03/01/accessing-data-bases.aspx</id><published>2011-03-01T16:54:00Z</published><updated>2011-03-01T16:54:00Z</updated><content type="html">&lt;p&gt;Recently, I needed to &lt;strong&gt;access an SQL&lt;/strong&gt;&amp;nbsp;&lt;strong&gt;database from PowerShell&lt;/strong&gt;. There are no cmdlets to help you, but with a bunch of helper functions, it is easy and straightforward to access databases (including &lt;strong&gt;Microsoft Access&lt;/strong&gt; files), retrieve data &lt;strong&gt;using SQL&lt;/strong&gt; and even inserting and updating information (&lt;em&gt;I know I promised to talk about speeding up range pings in your network but this database issue got into my way so I decided to cover this first&lt;/em&gt; &lt;img src="http://powershell.com/cs/emoticons/emotion-2.gif" alt="Big Smile" /&gt;).&lt;/p&gt;
&lt;h3&gt;Connection String: Where It All Begins&lt;/h3&gt;
&lt;p&gt;The first thing you need to access a database is a &lt;strong&gt;&amp;quot;connection string&amp;quot;.&lt;/strong&gt; It is a cryptic piece of text telling the computer where the database is located and what database driver you want to use. Constructing such a connection string can be a mess. Fortunately, there are some &lt;strong&gt;secret tricks&lt;/strong&gt; you can use to &lt;strong&gt;create the connection string automatically&lt;/strong&gt;. Have a look at the function &lt;strong&gt;New-ConnectionString&lt;/strong&gt;&amp;nbsp;(&lt;a target="_blank" href="http://powershell.com/cs/media/p/9529.aspx"&gt;which you can download here&lt;/a&gt;):&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-ConnectionString&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;$env:temp\connection.udl&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ItemType&lt;/span&gt;&lt;/span&gt; File &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Force&lt;/span&gt;&lt;/span&gt; | &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;span class="verbnoun"&gt;Start-Process&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#5f9ea0;"&gt;&lt;span class="modifier"&gt;-Wait&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;try {&lt;br /&gt;(&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Content&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$path&lt;/span&gt;&lt;/span&gt;)[2..10] | &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;Out-String&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;} catch { }&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Remove-Item&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$path&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;/div&gt;
&lt;p&gt;When you run &lt;strong&gt;New-ConnectionString&lt;/strong&gt;, it &lt;strong&gt;invokes a system dialog&lt;/strong&gt; that helps you choose the correct database driver, pick the database you want to connect to, configure the connection using logon credentials etc. Simply choose the option to use a connection string and then click the button to create one. &lt;/p&gt;
&lt;p&gt;Now, the &lt;strong&gt;wizard walks you through&lt;/strong&gt; all the necessary configuration steps. Once done, you can even&amp;nbsp;&lt;strong&gt;test the connection&lt;/strong&gt; to see if you did everything right, and when you close the wizard, &lt;strong&gt;New-ConnectionString&lt;/strong&gt; spits out the magic connection string you just created! Cool, eh?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;NOTE: Many database drivers still only exist in 32bit versions, so if you are using a 64bit machine, you may want to try this in a 32bit PowerShell console. You will notice that New-ConnectionString will offer a lot more database drivers when launched from within a 32bit PowerShell than a 64bit PowerShell. To run PowerShell in 32bit mode on 64bit, launch PowerShell (x86) instead of PowerShell.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here is how you would create a connection string to a plain old Microsoft Access mdb database:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Launch the 32bit Version of PowerShell when you work on a 64bit machine&amp;nbsp;(most Access database drivers only exist in 32bit versions)&lt;/li&gt;
&lt;li&gt;Call &lt;strong&gt;New-ConnectionString&lt;/strong&gt; to invoke the wizard&lt;/li&gt;
&lt;li&gt;Choose the option to use a connection string (second option in section #1)&lt;/li&gt;
&lt;li&gt;Click the button to create a new connection string&lt;/li&gt;
&lt;li&gt;A new window opens. Click the &amp;quot;computer data source&amp;quot; tab, and double-click the database driver you want to use, for example &amp;quot;MS Access Database&amp;quot;&lt;/li&gt;
&lt;li&gt;Yet another window opens. Click the button &amp;quot;Database&amp;quot;, and select the mdb database file you want to use&lt;/li&gt;
&lt;li&gt;Leave the fields for username and password blank if the database does not require authentication, and click OK&lt;/li&gt;
&lt;li&gt;Optionally, you can now configure details. For example, check &amp;quot;No password required&amp;quot;, or click the &amp;quot;Advanced&amp;quot; tab to make additional adjustments&lt;/li&gt;
&lt;li&gt;Click the button &amp;quot;Test Connection&amp;quot; at the lower end of the dialog window to test your configuration and check whether you can access the database.&lt;/li&gt;
&lt;li&gt;Finally, click &amp;quot;OK&amp;quot;. New-ConnectionString returns the connection string to you. It looks similar to this:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="pscode"&gt;PS &amp;gt; &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;New-ConnectionString&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Provider&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;MSDASQL.1;Persist Security Info&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;False;Extended Properties&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;DSN=MS Access Database;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;DBQ=c:\skripts\nordwind.mdb;DefaultDir=c:\skripts;DriverId=25;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;FIL=MS Access;MaxBufferSize=2048;PageTimeout=5;UID=admin;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;Accessing a Database&lt;/h3&gt;
&lt;p&gt;Now that you have a valid connection string to your database, you can &lt;strong&gt;send plain SQL&lt;/strong&gt; to it and &lt;strong&gt;get back results&lt;/strong&gt;. I created a small function called &lt;strong&gt;Invoke-SQL&lt;/strong&gt;. It takes a valid SQL command that you want to send to your database, and the connection string you just created so that it knows where to retrieve the data. Here&amp;#39;s the code in action (apologies for using a German sample database, but I am sure you get the idea):&lt;/p&gt;
&lt;div class="pscode"&gt;PS &amp;gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$c&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#5f9ea0;"&gt;&lt;span class="verbnoun"&gt;New-ConnectionString&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;PS &amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-sql&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;select Firma, Land, Telefon from kunden&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$c&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Land Firma Telefon&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;----&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-----&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;-------&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Deutschland Alfreds Futterkiste 030&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;0074321&lt;br /&gt;Mexiko Ana Trujillo Emparedados y helados (5) 555&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;4729&lt;br /&gt;Mexiko Antonio Moreno Taquer&amp;iacute;a (5) 555&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;3932&lt;br /&gt;Gro&amp;szlig;britannien Around the Horn (71) 555&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;7788&lt;br /&gt;Schweden Berglunds snabbk&amp;ouml;p 0921&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;12 34 65&lt;br /&gt;Deutschland Blauer See Delikatessen 0621&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-&lt;/span&gt;&lt;/span&gt;08460&lt;br /&gt;Frankreich Blondel p&amp;egrave;re et fils 88.60.15.31&lt;br /&gt;Spanien B&amp;oacute;lido Comidas preparadas (91) 555 22 82&lt;br /&gt;(...)&lt;/div&gt;
&lt;p&gt;NOTE: In this example, I am creating the connection string&amp;nbsp; from scratch using &lt;strong&gt;New-ConnectionString&lt;/strong&gt; and going through the wizard. In real-world scenaros, of course, you&amp;#39;d run &lt;strong&gt;New-ConnectionString&lt;/strong&gt; only once to get the string and then hard-code that into your scripts.&lt;/p&gt;
&lt;p&gt;Here is &lt;strong&gt;Invoke-SQL&lt;/strong&gt; (&lt;a target="_blank" href="http://powershell.com/cs/media/p/9530.aspx"&gt;you can download it here&lt;/a&gt;):&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-SQL&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;param&lt;/span&gt;&lt;/span&gt;(&lt;br /&gt;[Parameter(Mandatory&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$true&lt;/span&gt;&lt;/span&gt;)]&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sql&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;select * from Kunden&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;br /&gt;[Parameter(Mandatory&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$true&lt;/span&gt;&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$connectionstring&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$db&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Object&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-comObject&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#8b4513;"&gt;&lt;span class="namespace"&gt;ADODB.Connection&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$db&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Open&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$connectionstring&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$rs&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$db&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Execute&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sql&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;while&lt;/span&gt;&lt;/span&gt; (&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;!&lt;/span&gt;&lt;/span&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$rs&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;EOF&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$hash&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; @{}&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt;&lt;/span&gt; (&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$field&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;in&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$rs&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Fields&lt;/span&gt;&lt;/span&gt;) {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$hash&lt;/span&gt;&lt;/span&gt;.&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$field&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Name&lt;/span&gt;&lt;/span&gt;) &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$field&lt;/span&gt;&lt;/span&gt;.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;Value&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$rs&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;MoveNext&lt;/span&gt;&lt;/span&gt;() &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Object&lt;/span&gt;&lt;/span&gt; PSObject &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-property&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#800080;"&gt;&lt;span class="var"&gt;$hash&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$rs&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Close&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$db&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;Close&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;}&lt;/div&gt;
&lt;p&gt;Note that &lt;strong&gt;Invoke-SQL&lt;/strong&gt; returns rich PowerShell objects so once you get the database results, you can easily pipe it on to other cmdlets to export it to a csv-file or do whatever else you want. Note also that I am using old COM objects to do the database access. I compared performance with native .NET methods, and there is really no speed difference. The COM approach is reliable, fast and needs much less code than .NET.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Important&lt;/strong&gt;: When you run Invoke-SQL on a 64bit machine, the same restrictions apply that I mentioned for New-ConnectionString: if you picked a database driver that only exists in a 32bit environment, then you can only use this driver (and connection string) from within a 32bit PowerShell. So again, on 64bit machines you may want to run this code in a 32bit PowerShell console.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hope you had fun, see you next week around...&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=9531" width="1" height="1"&gt;</content><author><name>Tobias</name><uri>http://powershell.com/cs/members/Tobias/default.aspx</uri></author><category term="sql" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/sql/default.aspx" /><category term="database" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/database/default.aspx" /><category term="connectionstring" scheme="http://powershell.com/cs/blogs/tobias/archive/tags/connectionstring/default.aspx" /></entry></feed>
