<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://powershell.com/cs/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results for 'app:weblogs' matching tags 'Weekend Scripter' and 'guest blogger'</title><link>http://powershell.com/cs/search/SearchResults.aspx?q=app:weblogs&amp;tag=Weekend+Scripter,guest+blogger&amp;orTags=0&amp;o=DateDescending</link><description>Search results for 'app:weblogs' matching tags 'Weekend Scripter' and 'guest blogger'</description><dc:language>en-US</dc:language><generator>CommunityServer 2008.5 (Build: 30929.2835)</generator><item><title>Weekend Scripter: Use PowerShell to Upload a New File Version to SharePoint</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/04/28/weekend-scripter-use-powershell-to-upload-a-new-file-version-to-sharepoint.aspx</link><pubDate>Sun, 28 Apr 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:23107</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;strong style="font-size:12px;"&gt;Summary&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;: Microsoft PowerShell MVP, Niklas Goude, talks about using Windows PowerShell to upload a new version of a file to SharePoint.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Today Niklas Goude is our guest blogger. You can read more from Niklas in his &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/tags/niklas+goude/" target="_blank"&gt;past Hey, Scripting Guy! Blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Take it away Niklas&amp;hellip;&lt;/p&gt;
&lt;p&gt;In a previous post, &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2012/04/30/3354785.aspx" target="_blank"&gt;Use PowerShell Cmdlets to Manage SharePoint Document Libraries&lt;/a&gt;, we talked about uploading files to a share in SharePoint 2010.&amp;nbsp;&lt;span style="font-size:12px;"&gt;Now we&amp;#39;ll take this a step further and update a minor or a major version of an existing document.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a quick recap of the code used to upload the file:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# Add the Snapin&lt;br /&gt; Add-PSSnapin Microsoft.SharePoint.PowerShell&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# Retrieve specific Site&lt;br /&gt; $spWeb = Get-SPWeb http://SP01&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# Create instance of Folder&lt;br /&gt; $spFolder = $spWeb.GetFolder(&amp;quot;Shared Documents&amp;quot;)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# Get the file on Disk that we want to upload&lt;br /&gt; $file = Get-Item C:\Documents\MyDoc.docx&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# upload the file.&lt;br /&gt; $spFolder.Files.Add(&amp;quot;Shared Documents/MyDoc.docx&amp;quot;,$file.OpenRead(),$false)&lt;/p&gt;
&lt;p&gt;What we&amp;rsquo;ve done so far is to upload a single document to a document library in SharePoint 2010. The file used in this example is stored on drive C:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7041.wes_2D00_4_2D00_28_2D00_13_2D00_1.jpg"&gt;&lt;img style="border:0px currentColor;" title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7041.wes_2D00_4_2D00_28_2D00_13_2D00_1.jpg" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The document contains a single line:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5165.wes_2D00_4_2D00_28_2D00_13_2D00_2.jpg"&gt;&lt;img style="border:0px currentColor;" title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5165.wes_2D00_4_2D00_28_2D00_13_2D00_2.jpg" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;After we run the Windows PowerShell code, the document gets uploaded to a document library in SharePoint 2010.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8551.wes_2D00_4_2D00_28_2D00_13_2D00_3.jpg"&gt;&lt;img style="border:0px currentColor;" title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8551.wes_2D00_4_2D00_28_2D00_13_2D00_3.jpg" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;We can check the versioning for the document by clicking Version History in SharePoint:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0066.wes_2D00_4_2D00_28_2D00_13_2D00_4.jpg"&gt;&lt;img style="border:0px currentColor;" title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/350x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0066.wes_2D00_4_2D00_28_2D00_13_2D00_4.jpg" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll see that the version number is set to 0.1:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8802.wes_2D00_4_2D00_28_2D00_13_2D00_5.jpg"&gt;&lt;img style="border:0px currentColor;" title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8802.wes_2D00_4_2D00_28_2D00_13_2D00_5.jpg" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s open the file that is stored on drive C and modify it:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0602.wes_2D00_4_2D00_28_2D00_13_2D00_6.jpg"&gt;&lt;img style="border:0px currentColor;" title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0602.wes_2D00_4_2D00_28_2D00_13_2D00_6.jpg" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Back in Windows PowerShell, we use &lt;strong&gt;SPFileCollection&lt;/strong&gt; to pick up the document we just uploaded. In this example, we are going to filter out the document where the name is equal to MyDoc.docx by using the &lt;strong&gt;Where-Object&lt;/strong&gt; cmdlet.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# Retrieve specific Site&lt;br /&gt; $spWeb = Get-SPWeb http://SP01&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# Create instance of Folder&lt;br /&gt; $spFolder = $spWeb.GetFolder(&amp;quot;Shared Documents&amp;quot;)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# Retrieve a Specific File.&lt;br /&gt; $spFile = $spFolder.Files | Where-Object { $_.Name -eq &amp;quot;MyDoc.docx&amp;quot; }&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;We pick up the file because we want to use some of its properties for the new version that we want to upload. When we upload a new version of the document, we still use the &lt;strong style="font-size:12px;"&gt;Add&lt;/strong&gt; method that is provided by the Microsoft.SharePoint.SPFileCollection, but with a different overload definition. Here&amp;rsquo;s the definition on MSDN: &lt;/span&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms448353.aspx" target="_blank"&gt;SPFileCollection.Add method (String, Stream, SPUser, SPUser, DateTime, DateTime)&lt;/a&gt;&lt;span style="font-size:12px;"&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The parameters we want to use are: &lt;strong&gt;urlOfFile&lt;/strong&gt;, &lt;strong&gt;File&lt;/strong&gt;, &lt;strong&gt;CreatedBy&lt;/strong&gt;, &lt;strong&gt;ModifiedBy&lt;/strong&gt;, &lt;strong&gt;TimeCreated&lt;/strong&gt;, and &lt;strong&gt;TimeLastModified&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We can get the following values from the existing document in SharePoint 2010: &lt;strong&gt;UrlOfFile&lt;/strong&gt;, &lt;strong&gt;CreatedBy&lt;/strong&gt;, &lt;strong&gt;ModifiedBy&lt;/strong&gt;, and &lt;strong&gt;TimeCreated&lt;/strong&gt;. We can get &lt;strong&gt;File&lt;/strong&gt; by using &lt;strong&gt;Get-Item&lt;/strong&gt;, and we can get &lt;strong&gt;TimeLastModified&lt;/strong&gt; by simply using &lt;strong&gt;Get-Date&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s get the modified MyDoc.docx from drive C:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$file = Get-Item C:\Documents\MyDoc.docx&lt;/p&gt;
&lt;p&gt;Next we run the method:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$newVersion = $spFolder.Files.Add($spFile.Name, $file.OpenRead(), $spFile.Author, $spFile.ModifiedBy, $spFile.TimeCreated, (Get-Date))&lt;/p&gt;
&lt;p&gt;If we open the SharePoint document library again, we&amp;rsquo;ll see that we have a new minor version of our document, .02.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6710.wes_2D00_4_2D00_28_2D00_13_2D00_7.jpg"&gt;&lt;img style="border:0px currentColor;" title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6710.wes_2D00_4_2D00_28_2D00_13_2D00_7.jpg" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And finally, if we want to add the modified document as a major version, we use the &lt;strong&gt;Publish&lt;/strong&gt; method:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$newVersion.Publish(&amp;quot;&amp;quot;)&lt;/p&gt;
&lt;p&gt;Now we have a new major version, 1.0, instead.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8357.wes_2D00_4_2D00_28_2D00_13_2D00_8.jpg"&gt;&lt;img style="border:0px currentColor;" title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8357.wes_2D00_4_2D00_28_2D00_13_2D00_8.jpg" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;~Niklas&lt;/p&gt;
&lt;p&gt;Thank you, Niklas, for taking your time to share your knowledge.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3569353" width="1" height="1" alt="" /&gt;</description></item><item><title>Weekend Scripter: Improve Performance When Combining PowerShell Arrays</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/04/27/weekend-scripter-improve-performance-when-combining-powershell-arrays.aspx</link><pubDate>Sat, 27 Apr 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:23109</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;span style="font-size:12px;"&gt;&lt;strong&gt;Summary&lt;/strong&gt;: Microsoft premier field engineer, Chris Wu, talks about combining Windows PowerShell arrays.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Chris Wu, a Microsoft PFE, is back to share his knowledge. See &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/tags/chris+wu/http:/blogs.technet.com/b/heyscriptingguy/archive/tags/chris+wu/" target="_blank"&gt;previous Hey, Scripting Guy! Blog guest posts&lt;/a&gt; from Chris.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Here is contact information for Chris:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Twitter: &lt;a href="https://twitter.com/chwu_ms"&gt;https://twitter.com/chwu_ms&lt;/a&gt;&lt;br /&gt; Facebook: &lt;a href="https://www.facebook.com/mschwu"&gt;https://www.facebook.com/mschwu&lt;/a&gt;&lt;br /&gt; LinkedIn: &lt;a href="http://ca.linkedin.com/in/mschwu"&gt;http://ca.linkedin.com/in/mschwu&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Take it away Chris&amp;hellip;&lt;/p&gt;
&lt;p&gt;While teaching a Windows PowerShell workshop, I was asked about how to combine two arrays of different objects (which share one key property) into one that contains objects with properties from both source objects. One real world scenario is to merge information retrieved from Active Directory (a list of Active Directory users and their properties) and Exchange Server (mailboxes).&lt;/p&gt;
&lt;p&gt;The current approach by the student is to use two-level loops, which has seen performance issues when source arrays become huge in size (the following code snippet uses dummy data for demonstration purposes).&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$ADList = @&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;chwu,chwu@microsoft.com,Chris Wu&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;tst1,,Test User1&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;tst2,tst2@contoso.com,Test User2&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;quot;@ | ConvertFrom-Csv -Header Name,mail,CN&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$EXList = @&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;chwu,ex1.contoso.com&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;tst2,ex2.contoso.com&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;quot;@ | ConvertFrom-Csv -Header Name,MailServer&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Result = @()&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;foreach($ad in $ADList) {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; $Match = $false&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; foreach($ex in $EXList) {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ($ad.Name -eq $ex.Name) {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Result += New-Object PSObject -Property @{Name=$ad.Name; mail=$ad.mail; CN=$ad.CN; MailServer=$ex.MailServer}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Match = $true&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; if(-not $Match) {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Result += New-Object PSObject -Property @{Name=$ad.Name; mail=$ad.mail; CN=$ad.CN}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3716.wes_2D00_4_2D00_27_2D00_13_2D00_1.png"&gt;&lt;img style="border:0px currentColor;" title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3716.wes_2D00_4_2D00_27_2D00_13_2D00_1.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this post, I will explore several options to improve the performance and cleanness of this code snippet.&lt;/p&gt;
&lt;p&gt;The first thing we can do is remove the use of the &lt;strong&gt;$Result&lt;/strong&gt; array, which has two drawbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every assignment operation will create a new array in memory with data copied from the source, which is inefficient.&lt;/li&gt;
&lt;li&gt;It defeats the streaming benefit of the WindowsPowerShell pipeline because it returns all objects as a whole at the end of the processing. A best practice in Windows PowerShell is to emit an individual object whenever it&amp;rsquo;s ready.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another performance issue stems from the use of an inner loop to search for a matching record in the second array, which basically multiplies the total number of iterations. We can utilize a hash table for faster lookup. The &lt;strong&gt;Group-Object&lt;/strong&gt; cmdlet offers a convenient &lt;strong&gt;AsHashTable &lt;/strong&gt;parameter that can be used here.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8512.wes_2D00_4_2D00_27_2D00_13_2D00_2.png"&gt;&lt;img style="border:0px currentColor;" title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8512.wes_2D00_4_2D00_27_2D00_13_2D00_2.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please be warned that the value portion of each entry is an array of matching records. If we are grouping records by using a property with unique values (such as &lt;strong&gt;SamAccountName&lt;/strong&gt;), those arrays will apparently contains one single element each.&lt;/p&gt;
&lt;p&gt;So an enhanced version of the code snippet is like this (with the constructing source arrays removed):&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$h = $EXList | Group-Object -Property Name -AsHashTable&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$ADList | %{&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; if($h[$_.Name]) {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; New-Object PSObject -Property @{Name=$_.Name; mail=$_.mail; CN=$_.CN; MailServer=$h[$_.Name][0].MailServer}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; } else {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; New-Object PSObject -Property @{Name=$_.Name; mail=$_.mail; CN=$_.CN}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p&gt;The last (but not the least) idea is to sort both arrays based on the key property (user name) beforehand, then we can pair records in a single iteration. Note that in this particular example, users found in Active Directory is a superset of users in Exchange, so we need a pointer variable to deal with this little quirk.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$ADList = @&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;chwu,chwu@microsoft.com,Chris Wu&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;tst1,,Test User1&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;tst2,tst2@contoso.com,Test User2&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;quot;@ | ConvertFrom-Csv -Header Name,mail,CN | Sort-Object -Property Name&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$EXList = @&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;chwu,ex1.contoso.com&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;tst2,ex2.contoso.com&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;quot;@ | ConvertFrom-Csv -Header Name,MailServer | Sort-Object -Property Name&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$ADList | % {$p = 0} {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; if($_.Name -eq $EXList[$p].Name) {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; New-Object PSObject -Property @{Name=$_.Name; mail=$_.mail; CN=$_.CN; MailServer=$EXList[$p].MailServer}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $p++&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; } else {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; New-Object PSObject -Property @{Name=$_.Name; mail=$_.mail; CN=$_.CN}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p&gt;The last two snippets perform much better than the original one, but which one is faster remains a question (I haven&amp;rsquo;t tested them against large arrays just yet). I would like to hear about your results, and I welcome your thoughts and ideas.&lt;/p&gt;
&lt;p&gt;~Chris&lt;/p&gt;
&lt;p&gt;Thanks Chris excellent blog post. Join me tomorrow for more cool Windows PowerShell stuff.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3566535" width="1" height="1" alt="" /&gt;</description></item><item><title>Weekend Scripter: Use PowerShell to Clean Out Temp Folders</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/04/14/weekend-scripter-use-powershell-to-clean-out-temp-folders.aspx</link><pubDate>Sun, 14 Apr 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:22791</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;strong style="font-size:12px;"&gt;Summary&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;: Guest blogger, Bob Stevens, talks about using Windows PowerShell to clean out temporary folders on desktops following a malware infection.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Today, we welcome back our newest guest blogger, Bob Stevens. Yesterday Bob wrote about a quick script that he developed to pick out comments from a Windows PowerShell script: &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2013/04/13/weekend-scripter-pick-comments-from-a-powershell-script.aspx" target="_blank"&gt;Weekend Scripter: Pick Comments from a PowerShell Script&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I made Bob&amp;rsquo;s virtual acquaintance recently when I did a Live Meeting presentation to the &lt;a href="http://www.tcposhug.com/" target="_blank"&gt;Twin Cities PowerShell User Group.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here is Bob&amp;rsquo;s contact information:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Blog: &lt;a href="http://stuckinmypowershell.blogspot.com/" target="_blank"&gt;Help! I&amp;rsquo;m Stuck In My Powershell!&lt;/a&gt;&lt;br /&gt; Twitter: &lt;a href="https://twitter.com/B_stevens6" target="_blank"&gt;@B_stevens6&lt;/a&gt;&lt;br /&gt; LinkedIn: &lt;a href="http://www.linkedin.com/profile/edit?trk=hb_tab_pro_top" target="_blank"&gt;Robert Stevens&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Take it away, Bob&amp;hellip;&lt;/p&gt;
&lt;p&gt;For a local service desk systems analyst, nothing is more frustrating than malware. Not only is it a time sink&amp;mdash;it also has the indented potential to cause irreparable damage. No network that connects to the Internet is immune to it.&lt;/p&gt;
&lt;p&gt;Most organizations have their own standard operating procedures regarding malware removal. Even so, individuals technician have their special tweaks and tricks to increase the likelihood of success. I like to target the malware where it resides: Temp Folders. And after cleaning and clearing a number of workstations, it occurred to me that I could use a Windows PowerShell script to do just that, saving myself five minutes of hoping that the computer will let me open a folder.&lt;/p&gt;
&lt;p&gt;I started by creating a list of the locations that temporary files are automatically placed by the Windows&amp;nbsp;XP operating system (starting with Windows Vista, they are in the C:\Users folder):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;C:\Windows\Temp&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;C:\Windows\Prefetch&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;C:\Documents and Settings\*\Local Settings\Temp&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;C:\Users\*\Appdata\Local\Temp&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that I have defined our locations, I need to define what I want to do. For this, I create a flowchart:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6472.1.PNG"&gt;&lt;img style="border:0px currentColor;" title="Image of flowchart" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6472.1.PNG" alt="Image of flowchart" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I start with the &lt;strong&gt;Set-Location&lt;/strong&gt; command and define the location as &lt;strong&gt;&amp;ldquo;C:\Windows\Temp&amp;rdquo;&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set-Location &amp;ldquo;C:\Windows\Temp&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Now that I am located in the Windows temp folder, I need to delete the files. This can be done with the old DOS command &lt;strong&gt;Del&lt;/strong&gt;, but I prefer using the Windows Powershell cmdlet &lt;strong&gt;Remove-Item&lt;/strong&gt; to standardize the script. The items need to be removed indiscriminately, so I use a wildcard character. A wildcard character is a special character that represents one or more other characters. The question mark (&lt;strong&gt;?&lt;/strong&gt;) wildcard stands for one character and the asterisk (&lt;strong&gt;*&lt;/strong&gt;) wildcard stands for any number of characters. Because I do not want to discriminate between different files, I use the asterisk.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Remove-Item *&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Next I tell the &lt;strong&gt;Remove-Item&lt;/strong&gt; cmdlet to also remove all files in subdirectories with the &lt;strong&gt;-recurse&lt;/strong&gt; switch:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Remove-Item * -recurse&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;And I tell it to select hidden files with the &lt;strong&gt;-force&lt;/strong&gt; switch:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Remove-Item * -recurse -force&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Together the two lines looked like this:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-Location &amp;ldquo;C:\Windows\Temp&amp;rdquo;&lt;br /&gt; Remove-Item * -recurse -force&lt;/p&gt;
&lt;p&gt;I do the same for the rest of the folders and the complete script begins to take shape:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-Location &amp;ldquo;C:\Windows\Temp&amp;rdquo;&lt;br /&gt; Remove-Item * -recurse -force&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-Location &amp;ldquo;C:\Windows\Prefetch&amp;rdquo;&lt;br /&gt; Remove-Item * -recurse -force&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-Location &amp;ldquo;C:\Documents and Settings&amp;rdquo;&lt;br /&gt; Remove-Item &amp;ldquo;.\*\Local Settings\temp\*&amp;rdquo; -recurse -force&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-Location &amp;ldquo;C:\Users&amp;rdquo;&lt;br /&gt; Remove-Item &amp;ldquo;.\*\Appdata\Local\Temp\*&amp;rdquo; -recurse -force&lt;/p&gt;
&lt;p&gt;Wait. Why is there an asterisk in the middle of the last path? You can use wildcard characters to do this:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Remove-Item &amp;ldquo;.\*\Appdata\Local\Temp\*&amp;rdquo; -recurse -force&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This says, &amp;ldquo;Look in all folders in this directory with the path structure that matches this.&amp;rdquo; In my case, this is all of the user profile Local Settings\temp folders.&lt;/p&gt;
&lt;p&gt;But this looks very busy, so at Ed Wilson&amp;rsquo;s suggestion, an array would prevent all the unnecessary jumping around with the &lt;strong&gt;Set-Location&lt;/strong&gt; command. So we change our flowchart to look something like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0218.2.PNG"&gt;&lt;img style="border:0px currentColor;" title="Image of flowchart" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0218.2.PNG" alt="Image of flowchart" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:12px;"&gt;Arrays are a nifty programming feature that groups a number of strings together into one variable, while remaining individual strings. They are defined much like a normal variable&amp;mdash;they start with the variable (&lt;/span&gt;&lt;strong style="font-size:12px;"&gt;$&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;) indicator followed by the array name:&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;$tempfolders&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Just like a variable, I use the equal sign (&lt;strong&gt;=&lt;/strong&gt;) to define it.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;$tempfolders =&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Here is where the arrays and variables differ when defining. I start with the array indicator (&lt;strong&gt;@&lt;/strong&gt;):&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;$tempfolders = @&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;And I follow it with parentheses to group strings together:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;$tempfolders = @()&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;What you put inside the parentheses is your choice. For my purposes, I fill it with temp folder paths:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$tempfolders = @( &amp;quot;C:\Windows\Temp\*&amp;quot;, &amp;quot;C:\Windows\Prefetch\*&amp;quot;, &amp;quot;C:\Documents and Settings\*\Local Settings\temp\*&amp;quot;, &amp;quot;C:\Users\*\Appdata\Local\Temp\*&amp;quot; )&lt;/p&gt;
&lt;p&gt;Notice that each string is neatly encapsulated by double quotation marks (&lt;strong&gt;&amp;ldquo; &amp;rdquo;&lt;/strong&gt;) and separated by a comma and a space (&lt;strong&gt;, &lt;/strong&gt;). The quotation marks are necessary for any string with a space in it, and the comma with a space separates the values. Both are essential to define an array. Additionally you can see that each string ends with a wildcard character. This is going to remove the necessity for me to define exactly what to remove in the next line.&lt;/p&gt;
&lt;p&gt;Now I use the &lt;strong&gt;Remove-Item&lt;/strong&gt; cmdlet again; but this time for the &lt;strong&gt;-path&lt;/strong&gt; operator, I use the &lt;strong&gt;$tempfolders&lt;/strong&gt; array variable:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Remove-Item $tempfolders -force -recurse&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;This line instructs Windows Powershell to do exactly the same as previously, but for every item in the array.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Side-by-side, here are the two versions of the script:&lt;/span&gt;&lt;/p&gt;
&lt;table cellspacing="0" cellpadding="0"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;1 Set-Location &amp;ldquo;C:\Windows\Temp&amp;rdquo;&lt;/p&gt;
&lt;p&gt;2 Remove-Item * -recurse -force&lt;/p&gt;
&lt;p&gt;3 Set-Location&lt;/p&gt;
&lt;p&gt;4 &amp;ldquo;C:\Windows\Prefetch&amp;rdquo;&lt;/p&gt;
&lt;p&gt;5 Remove-Item * -recurse -force&lt;/p&gt;
&lt;p&gt;6 Set-Location &amp;ldquo;C:\Documents and Settings&amp;rdquo;&lt;/p&gt;
&lt;p&gt;7 Remove-Item &amp;ldquo;.\*\Local&lt;/p&gt;
&lt;p&gt;8 Settings\temp\*&amp;rdquo; -recurse -force&lt;/p&gt;
&lt;p&gt;9 Set-Location &amp;ldquo;C:\Users&amp;rdquo;&lt;/p&gt;
&lt;p&gt;10 Remove-Item &amp;ldquo;.\*\Appdata\Local\Temp\*&amp;rdquo; -recurse -force&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;1 $tempfolders = @(&amp;quot;C:\Windows\Temp\*&amp;quot;, &amp;quot;C:\Windows\Prefetch\*&amp;quot;, &amp;quot;C:\Documents and Settings\*\Local Settings\temp\*&amp;quot;, &amp;quot;C:\Users\*\Appdata\Local\Temp\*&amp;quot;)&lt;/p&gt;
&lt;p&gt;2 Remove-Item $tempfolders -force -recurse&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;With two lines of code, I was able to save myself between three minutes and 30 minutes of work. This is the purpose of scripting at its finest: automate repetitive tasks to allow the technician to do more in-depth work. Thank you all for reading, and as always, let me know if you have developed a better way!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;~Bob&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Bob, thanks again for a real world example and a great suggestion. Join us tomorrow for a blog post by Boe Prox about installing WSUS on Windows Server 2012. It is a great blog and I am sure you will enjoy it.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3564151" width="1" height="1" alt="" /&gt;</description></item><item><title>Weekend Scripter: Pick Comments from a PowerShell Script</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/04/13/weekend-scripter-pick-comments-from-a-powershell-script.aspx</link><pubDate>Sat, 13 Apr 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:22793</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;strong style="font-size:12px;"&gt;Summary&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;: Guest blogger, Bob Stevens, shares a script to pick out comments from a Windows PowerShell script.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Today we have a new guest blogger, Bob Stevens. I made Bob&amp;rsquo;s virtual acquaintance recently when I did a Live Meeting presentation to the &lt;a href="http://www.tcposhug.com/" target="_blank"&gt;Twin Cities PowerShell User Group.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here is Bob&amp;rsquo;s contact information:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:12px;"&gt;Blog: &lt;/span&gt;&lt;a href="http://stuckinmypowershell.blogspot.com/" target="_blank"&gt;Help! I&amp;rsquo;m Stuck in My Powershell!&lt;/a&gt;&lt;br /&gt; Twitter: &lt;a href="https://twitter.com/B_stevens6" target="_blank"&gt;@B_stevens6&lt;/a&gt;&lt;br /&gt; LinkedIn: &lt;a href="http://www.linkedin.com/profile/edit?trk=hb_tab_pro_top" target="_blank"&gt;Robert Stevens&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The floor is yours, Bob&amp;hellip;&lt;/p&gt;
&lt;p&gt;As a local Help Desk technician, I run into many repetitive support tasks. From low toners to Internet Explorer issues, I have done it all. About three months ago I discovered that I could use PowerShell to automate a number of these tasks, thereby freeing my time for some of the more unusual issues. Fortunately, all of the computers at my site have Windows PowerShell&amp;nbsp;2.0 installed, so it was a matter of ensuring that they can run scripts. This can be done by changing the &lt;strong&gt;Set-ExecutionPolicy&lt;/strong&gt; cmdlet to &lt;strong&gt;Unrestricted&lt;/strong&gt; in the following manner:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-ExecutionPolicy Unrestricted&lt;/p&gt;
&lt;p&gt;When the work is done, switch it back to the organization default with:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-ExecutionPolicy Remote-Signed&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Set-ExecutionPolicy&lt;/strong&gt; governs which scripts can be run on any given system. By setting it as &lt;strong&gt;Unrestricted&lt;/strong&gt;, I am removing all restrictions. I switch it back to &lt;strong&gt;Remote-Signed&lt;/strong&gt; to prevent users from running scripts that can potentially damage a system, thereby presenting a potential for data loss.&lt;/p&gt;
&lt;p&gt;Fast forward three months and multiple scripts later&amp;hellip;&lt;/p&gt;
&lt;p&gt;It dawned on me that I would need to create documentation for each of these scripts. Documentation provides my coworkers with the insight they need to understand the purpose and functionality of my work and to pick up where I left off should the script need to be altered. Thankfully, like a good Windows PowerShell scripter, I commented liberally throughout my scripts to ensure that I knew where I would need to alter it in the future. To this end I started working on a script to pull comments. I knew that I habitually use single line comments for documentation and block comments for commenting out blocks of code. Happy accident because the script I devised only pulls the first and the last lines of a block comment.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;strong&gt;Note&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;For simplicity, I name all directories a variation of &lt;strong&gt;&amp;ldquo;foo&amp;rdquo;&lt;/strong&gt; and all input files a variation of &lt;strong&gt;&amp;ldquo;foo.*&amp;rdquo;&lt;/strong&gt;. You can set foo as whatever you want.&lt;/p&gt;
&lt;p&gt;As usual I started with setting my location:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-Location &amp;ldquo;C:\foo&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Next we set our source script file as a variable. I use variables in my scripts to enable me to change one line of code, rather than five lines, thereby reducing the chance of an error. Variables are defined by the dollar sign (&lt;strong&gt;$&lt;/strong&gt;).&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$script = &amp;ldquo;foo.ps1&amp;rdquo;&lt;/p&gt;
&lt;p&gt;We need to define an output variable as &lt;strong&gt;$out&lt;/strong&gt;. Note that I used the &lt;strong&gt;$script&lt;/strong&gt; variable in the variable value. This will result in the file name of &lt;strong&gt;foo.ps1 comments.txt&lt;/strong&gt;. This is to differentiate between output files. For this to work, there must be a space between &lt;strong&gt;$script&lt;/strong&gt; and &lt;strong&gt;comments.txt&lt;/strong&gt;:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$out = &amp;ldquo;$script comments.txt&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Now that we have defined the output file name, we need to create the output file itself, and I do this with the &lt;strong&gt;New-Item&lt;/strong&gt; cmdlet. Of course, we need to define the object as a file&amp;mdash;otherwise we get a dialog box asking us if it&amp;rsquo;s a file or folder:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;New-Item &amp;ldquo;out&amp;rdquo; -ItemType File&lt;/p&gt;
&lt;p&gt;Now our preparation is complete:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-Location &amp;quot;c:\foo&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$script = &amp;quot;foo.ps1&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$out = &amp;quot;$script comments.txt&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;New-Item &amp;quot;$out&amp;quot; -ItemType File&lt;/p&gt;
&lt;p&gt;We need to pull the content of our source file with the &lt;strong&gt;Get-Content&lt;/strong&gt; cmdlet:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Get-Content $script&lt;/p&gt;
&lt;p&gt;The next line is to prevent Windows PowerShell from appending the output to output that already exists in the variable by creating an array, this is done with the array (&lt;strong&gt;@&lt;/strong&gt;) operator, followed by both parentheses:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments = @()&lt;/p&gt;
&lt;p&gt;This is where the magic takes place. We need to use the &lt;strong&gt;Select-String&lt;/strong&gt; cmdlet. This command requires two parameters: &lt;strong&gt;Pattern&lt;/strong&gt; and &lt;strong&gt;File&lt;/strong&gt;. Both values need to be quoted if you are not using a variable to define it. As we are searching for comments, we are going to select strings that contain &lt;strong&gt;&amp;ldquo;#&amp;rdquo;&lt;/strong&gt;:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Select-String -Pattern &amp;ldquo;#&amp;rdquo; $script&lt;/p&gt;
&lt;p&gt;This is a bit more complex, and it requires stringing three commands together, so we use the pipe (&lt;strong&gt;|&lt;/strong&gt;) operator. The pipe operator merely states do &amp;ldquo;this&amp;rdquo; and then do &amp;ldquo;that&amp;rdquo; with the output of &amp;ldquo;this.&amp;rdquo; Pipe operators must always have a space preceding and succeeding it:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Select-String -Pattern &amp;ldquo;#&amp;rdquo; $script |&lt;/p&gt;
&lt;p&gt;For our purposes, we are going to say, &amp;ldquo;For each object, do this.&amp;rdquo; Coincidentally (or not), Microsoft decided to add a &lt;strong&gt;Foreach-Object&lt;/strong&gt; cmdlet for just this purpose! And everything that you are doing with &lt;strong&gt;Foreach-Object&lt;/strong&gt; must be in braces to group them together:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Select-String - Pattern &amp;ldquo;#&amp;rdquo; $script |&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;Foreach-Object {}&lt;/p&gt;
&lt;p&gt;When we string commands like this together, formatting is important&amp;mdash;not for functionality, but for readability. Now we need to comment the full line where &lt;strong&gt;&amp;ldquo;#&amp;rdquo;&lt;/strong&gt; appears. It is important to note that you must use &lt;strong&gt;&amp;ldquo;+=&amp;rdquo;&lt;/strong&gt;, or you will end up with an empty file:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Select-String - Pattern &amp;ldquo;#&amp;rdquo; $script |&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;Foreach-Object {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.line&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p&gt;We need to tell Windows PowerShell to grab everything after &lt;strong&gt;&amp;ldquo;#&amp;rdquo; &lt;/strong&gt;in that string. This is tricky, but it can be done with the &lt;strong&gt;context.postcontext&lt;/strong&gt; definition:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Select-String - Pattern &amp;ldquo;#&amp;rdquo; $script |&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;Foreach-Object {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.line&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.context.postcontext&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p&gt;We now need to tell Windows PowerShell to extract everything that we just defined within the &lt;strong&gt;Foreach-Object&lt;/strong&gt; curly brackets:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Select-String - Pattern &amp;ldquo;#&amp;rdquo; $script |&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;Foreach-Object {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.line&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.context.postcontext&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments&lt;/p&gt;
&lt;p&gt;Finally, we dump our output into the output file &lt;strong&gt;$out&lt;/strong&gt; with the &lt;strong&gt;Set-Content&lt;/strong&gt; cmdlet:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Select-String - Pattern &amp;ldquo;#&amp;rdquo; $script |&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;Foreach-Object {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.line&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.context.postcontext&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments | Set-Content $out&lt;/p&gt;
&lt;p&gt;The complete script looks something like this:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Set-Location &amp;quot;c:\foo&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$script = &amp;quot;foo.ps1&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$out = &amp;quot;$script comments.txt&amp;quot;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;New-Item &amp;quot;$out&amp;quot; -ItemType File&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Get-Content $script&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments = @()&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Select-String -Pattern &amp;quot;#&amp;quot; $script |&lt;/p&gt;
&lt;p style="padding-left:60px;"&gt;Foreach-Object {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.line&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments += $_.context.postcontext&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$comments | Set-Content $out&lt;/p&gt;
&lt;p&gt;The result should take the following input:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3426.wes_2D00_4_2D00_13_2D00_13_2D00_1.png"&gt;&lt;img style="border:0px currentColor;" title="Image of script" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3426.wes_2D00_4_2D00_13_2D00_13_2D00_1.png" alt="Image of script" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And give you the following output (&lt;strong&gt;Select-String -pattern &amp;ldquo;#&amp;rdquo;&lt;/strong&gt; shows up because it contains a &lt;strong&gt;&amp;ldquo;#&amp;rdquo;&lt;/strong&gt;):&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5773.wes_2D00_4_2D00_13_2D00_13_2D00_2.png"&gt;&lt;img style="border:0px currentColor;" title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5773.wes_2D00_4_2D00_13_2D00_13_2D00_2.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This saved me an hour now and countless future hours that I would spend extracting comments for documentation.&lt;/p&gt;
&lt;p&gt;When I was verifying my work, I ran across the following note to myself stating that I referenced a Rob Campbell in another script. Some of the code made it in here.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Rob Campbell, Mjolinor: &lt;a href="http://social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/b41bfe7f-2ec3-428e-8a79-962afa076067/" target="_blank"&gt;How do you extract data from a txt file with powershell&lt;/a&gt;. As always, input is always appreciated.&lt;/p&gt;
&lt;p&gt;Thank you for your time.&amp;nbsp;I uploaded the complete script to the Script Center Repository: &lt;a href="http://gallery.technet.microsoft.com/scriptcenter/Extracting-comments-from-a-149af1ea" target="_blank"&gt;Extracting Comments from a Script with PowerShell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;~Bob&lt;em&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Thank you, Bob, for sharing your script and your insight with us today. Join us tomorrow when Bob talks about a script he wrote to clean up user profiles. It is cool, and you do not want to miss it.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3564133" width="1" height="1" alt="" /&gt;</description></item><item><title>Do One Thing and Do It Well</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/04/07/do-one-thing-and-do-it-well.aspx</link><pubDate>Sun, 07 Apr 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:22610</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;span style="font-size:small;"&gt;&lt;strong style="font-size:12px;"&gt;Summary&lt;/strong&gt;: Microsoft PowerShell MVPs, Don Jones and Jeffery Hicks, talk about a fundamental tool design consideration.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Microsoft Scripting Guy, Ed Wilson, is here. This week we will not have our usual &lt;strong&gt;PowerTip&lt;/strong&gt;. Instead we have excerpts from seven books from Manning Press. In addition, each blog will have a special code for 50% off the book being excerpted that day. Remember that the code is valid only for the day the excerpt is posted. The coupon code is also valid for a second book from the Manning collection.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;This excerpt is from &lt;a href="http://www.manning.com/jones4/" target="_blank"&gt;Learn PowerShell Toolmaking in a Month of Lunches&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; By Don Jones and Jeffery Hicks&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0068.wes_2D00_4_2D00_7_2D00_13_2D00_1.jpg"&gt;&lt;img style="border:0px currentColor;" title="Photo of book cover" src="http://blogs.technet.com/resized-image.ashx/__size/150x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0068.wes_2D00_4_2D00_7_2D00_13_2D00_1.jpg" alt="Photo of book cover" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Here&amp;rsquo;s a basic tenant of good Windows PowerShell tool design: do one thing, and do it well. Broadly speaking, a function should do one&amp;mdash;and only one&amp;mdash;of these things:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;Retrieve data from someplace&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;Process data&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;Output data to some place&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;Put data into some visual format meant for human consumption&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;This fits well with the command-naming convention in Windows PowerShell: If your function uses the verb Get, that&amp;rsquo;s what it should do: get. If it&amp;rsquo;s outputting data, you name it with a verb like Export, or Out, or something else. If each command (okay, function) worries about just one of those things, then they&amp;rsquo;ll have the maximum possible flexibility.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;For example, let&amp;rsquo;s say we want to write a tool that will retrieve some key operating system information from multiple computers and then display that information in a nicely formatted onscreen table. It&amp;rsquo;d be easy to write that tool so that it opened Active Directory, got a bunch of computer names, queried the information from them, and then formatted a nice table as output.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;The problem?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Well, what if tomorrow we didn&amp;rsquo;t want the data on the screen but rather wanted it in a CSV file? What if one time we needed to query a small list of computers rather than a bunch of computers from the directory? Either change would involve coding changes, probably resulting in many different versions of our tool lying around. Had we made it more modular and followed the basic philosophy we just outlined, we wouldn&amp;rsquo;t have to do that. Instead, we might have designed the following:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;One function that gets computer names from the directory&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;One function that accepts computer names, queries those computers, and produces the desired data&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;One function that formats data into a nice onscreen table&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Suddenly, everything becomes more flexible. That middle function could now work with any source of computer names: the directory, a text file, or whatever. Its data could be sent to any other command to produce output. Maybe we&amp;rsquo;d pipe it to &lt;strong&gt;Export-CSV&lt;/strong&gt;&amp;nbsp;to make that CSV file&amp;nbsp;or to &lt;strong&gt;ConvertTo-HTML&lt;/strong&gt;&amp;nbsp;to make an HTML page. What about the onscreen table we want right now? We&amp;rsquo;re betting &lt;strong&gt;Format-Table&lt;/strong&gt;&amp;nbsp;could do the job, meaning we don&amp;rsquo;t even have to write that third function at all&amp;mdash;less work for us!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;So let&amp;rsquo;s talk about function design. We&amp;rsquo;re going to suggest that there are really three categories of functions (or tools): input, functional, and output.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-size:small;"&gt;Input tools&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Input tools are the functions that don&amp;rsquo;t produce anything inherently useful, but are rather meant to feed information to a second tool. So a function that retrieves computer names from a configuration management database is an input tool. You don&amp;rsquo;t necessarily want the computer names, but there might be an endless variety of other tools that you want to send computer names to&amp;mdash;including any number of built-in Windows PowerShell commands.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Here&amp;rsquo;s a good example of how to draw a line between your functions. Let&amp;rsquo;s say you&amp;rsquo;re writing a hunk of commands intended to retrieve computer names from your configuration management database. Your intent today is to query some WMI information from those computers&amp;mdash;but aren&amp;rsquo;t there other tools that need computer names as input? Sure! &lt;strong&gt;Restart-Computer&lt;/strong&gt;&amp;nbsp;accepts computer names. So does &lt;strong&gt;Get-EventLog&lt;/strong&gt;, &lt;strong&gt;Get-Process&lt;/strong&gt;, &lt;strong&gt;Invoke-Command&lt;/strong&gt;, and a dozen more commands. That&amp;rsquo;s what suggests (to us, at least) that functionality for getting names from the database should be a standalone tool. It could potentially feed a lot more than only today&amp;rsquo;s current needs.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Windows PowerShell already comes with a number of input tools. Sticking with the theme of getting computer names, you might use &lt;strong&gt;Import-CSV&lt;/strong&gt;, &lt;strong&gt;Get-Content&lt;/strong&gt;, or &lt;strong&gt;Get-ADComputer&lt;/strong&gt;&amp;nbsp;to retrieve computer names from various sources. To us, this further emphasizes the fact that the task of getting computer names is a standalone capability, rather than being part of another tool.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-size:small;"&gt;Functional tools&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;This is the kind of tool you&amp;rsquo;ll be writing most often. The idea is that this kind of tool doesn&amp;rsquo;t spend time retrieving information that it needs to do its main job. Instead, it accepts that information via a parameter of some kind&amp;mdash;that parameter being fed by manually entered data, by another command, and so on.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;So if your functional tool is going to query information from remote computers, it doesn&amp;rsquo;t internally do anything to get those computers&amp;rsquo; names; but instead, it accepts them on a parameter. It doesn&amp;rsquo;t care where the computer names come from&amp;mdash;that&amp;rsquo;s another job.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;When it&amp;rsquo;s been given the information it needs to operate, a functional tool does its job and then outputs objects to the pipeline. Specifically, it outputs a single kind of object, so that all of its output is consistent. This functional tool also doesn&amp;rsquo;t worry about what you plan to do with that output&amp;mdash;it simply puts objects into the pipeline. This kind of tool doesn&amp;rsquo;t spend a nanosecond worrying about formatting, about output files, or about anything else. It does its job, perhaps produces some objects as output, and that&amp;rsquo;s it.&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;&lt;strong&gt;Note&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Not all functional tools will produce output of any kind. A command that just does something&amp;mdash;perhaps reconfiguring a computer&amp;mdash;might not produce any output, apart from error messages if something goes wrong. That&amp;rsquo;s fine.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-size:small;"&gt;Output tools&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Output tools are specifically designed to take data (in the form of objects), which has been produced by a functional tool, and then put that data into a final form. Let&amp;rsquo;s stress that: final form. We looked up final in our dictionary, and it says something like, &amp;ldquo;pertaining to or coming at the end; last in place, order, or time.&amp;rdquo; In other words, when you send your data to an output tool, you&amp;rsquo;re finished with it. You don&amp;rsquo;t want anything else happening to the data. You want to save it in a file or a database, or display it onscreen, or fax it to someone, or tap it out in Morse code&amp;hellip;whatever. Windows PowerShell verbs for this include &lt;strong&gt;Export&lt;/strong&gt;, &lt;strong&gt;Out&lt;/strong&gt;, and &lt;strong&gt;ConvertTo&lt;/strong&gt;, to name a few.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Consider the inverse of this philosophy: If you have a tool that&amp;rsquo;s putting data into some final form, like a text file or an onscreen display, that tool should be doing nothing else. Why?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Consider a function that we&amp;rsquo;ve created, named &lt;strong&gt;Get-ComputerDetails&lt;/strong&gt;. This function gets a bunch of information from a bunch of computers. It then produces a pretty, formatted table on the screen. That&amp;rsquo;s a text-based display. Doing so means we could never do this:&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Get-ComputerDetails | Where OSBuildNumber &amp;ndash;le 7600 |&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Sort ComputerName | ConvertTo-HTML | Out-File computers.html&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;Why couldn&amp;rsquo;t we do that? Because, in this example, &lt;strong style="font-size:12px;"&gt;Get-ComputerDetails&lt;/strong&gt; is producing text. &lt;strong style="font-size:12px;"&gt;Where-Object&lt;/strong&gt;, &lt;strong style="font-size:12px;"&gt;Sort-Object&lt;/strong&gt;, and &lt;strong style="font-size:12px;"&gt;ConvertTo-HTML&lt;/strong&gt; can&amp;rsquo;t deal with text&amp;mdash;they deal with objects. &lt;strong style="font-size:12px;"&gt;Get-ComputerDetails&lt;/strong&gt;&amp;nbsp;has put our data into its final form, meaning&amp;mdash;according to the dictionary&amp;mdash;that &lt;strong style="font-size:12px;"&gt;Get-ComputerDetails&lt;/strong&gt; is &amp;ldquo;coming at the end&amp;rdquo; and should be &amp;ldquo;last in place.&amp;rdquo; Nothing can come after it&amp;mdash;meaning we have less flexibility.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;A better design would have had &lt;strong&gt;Get-ComputerDetails&lt;/strong&gt; produce only objects and to create a second command, perhaps called &lt;strong&gt;Format-MyPrettyDisplay&lt;/strong&gt;, which handles the formatting. That way we could get our originally desired output:&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Get-ComputerDetails | Format-MyPrettyDisplay&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;But we could also do this:&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Get-ComputerDetails | Where OSBuildNumber &amp;ndash;le 7600 |&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;Sort ComputerName | ConvertTo-HTML | Out-File computers.html&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;This would allow us to change our minds about using &lt;strong style="font-size:12px;"&gt;Format-MyPrettyDisplay&lt;/strong&gt; from time-to-time, instead sending our data objects on to other commands to produce different displays, filter the data, source the data, create files, and so on.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;This blog discussed the basics of good Windows PowerShell tool design. A function should perform only one of the following actions:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;Retrieve data from someplace&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;Process data&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;Output data to some place&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size:small;"&gt;Put data into a visual format meant for human consumption&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;We talked about three different categories of functions, or tools: input, functional, and output.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;~Don and Jeffrey&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:small;"&gt;&lt;strong&gt;Here is the code for the discount offer today at &lt;/strong&gt;&lt;a href="http://www.manning.com/" target="_blank"&gt;www.manning.com&lt;/a&gt;: &lt;strong&gt;scriptw7&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:small;"&gt; Valid for 50% off &lt;a href="http://www.manning.com/jones4/" target="_blank"&gt;Learn PowerShell Toolmaking in a Month of Lunches&lt;/a&gt; and &lt;a href="http://www.manning.com/harryman/" target="_blank"&gt;SharePoint 2010 Owner&amp;#39;s Manual&lt;/a&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:small;"&gt; Offer valid from April 7, 2013 12:01 AM until April 8, midnight (EST)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:small;"&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3563563" width="1" height="1" alt="" /&gt;</description></item><item><title>Performance Counters and Windows System Assessment Report</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/04/06/performance-counters-and-windows-system-assessment-report.aspx</link><pubDate>Sat, 06 Apr 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:22612</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;strong style="font-size:12px;"&gt;Summary&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;: Microsoft PowerShell MVP, Richard Siddaway, talks about using Windows PowerShell and WMI to work with performance counters and Windows assessment.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. This week we will not have our usual &lt;strong&gt;PowerTip&lt;/strong&gt;. Instead we have excerpts from seven books from Manning Press. In addition, each blog will have a special code for 50% off the book being excerpted that day. Remember that the code is valid only for the day the excerpt is posted. The coupon code is also valid for a second book from the Manning collection.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;This excerpt is from &lt;a href="http://www.manning.com/siddaway2/"&gt;PowerShell and WMI&lt;br /&gt;&lt;/a&gt;&lt;span style="font-size:12px;"&gt;&amp;nbsp; By Richard Siddaway&lt;/span&gt;&lt;span style="font-size:12px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="Body" align="left"&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6266.wes_2D00_4_2D00_6_2D00_13_2D00_1.jpg"&gt;&lt;img style="border:0px currentColor;" title="Photo of book cover" src="http://blogs.technet.com/resized-image.ashx/__size/150x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6266.wes_2D00_4_2D00_6_2D00_13_2D00_1.jpg" alt="Photo of book cover" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class="Body1" align="left"&gt;Measuring system performance has traditionally involved looking at the performance counters. These can be accessed through the performance monitor (SYSMON for those who remember earlier versions of Windows), and they can be saved as required. You can also use the &lt;strong&gt;Get-Counter&lt;/strong&gt; cmdlet (which works against remote machines), or you can use the WMI Win32_Perf* classes.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;Windows Vista introduced the system assessment report. This rates a number of system hardware components (including memory, CPU, disk, and graphics) to produce an overall rating for the system. The higher the score, the better the system should perform.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;I&amp;rsquo;m often asked about system stability. The number of unscheduled restarts is one way to measure stability. Later versions of Windows calculate a stability index on an hourly basis. This is calculated based on failures and changes, with recent events being more heavily weighted. The maximum possible score is 10.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;Performance counters are still required to dig into individual aspects of the system. In this set of tips, we&amp;rsquo;ll cover performance counters and Windows system assessment reports.&lt;/p&gt;
&lt;h2&gt;Reading performance counters&lt;/h2&gt;
&lt;p class="Body1" align="left"&gt;If you&amp;rsquo;ve spent any time investigating system performance, you know that there&amp;rsquo;s a huge list of available Windows performance counters. The problem of finding the correct counter to use is increased when you consider that applications such as SQL Server, IIS, and Exchange Server add their own raft of counters. WMI enables you to access some, but not all, of the counters.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;You can see which counters are available on a specific system like this:&lt;span style="font-size:12px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Get-WmiObject -List Win32_PerfFormattedData* | select name&lt;span style="font-size:12px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="Body1" align="left"&gt;Here&amp;rsquo;s an extract from the results:&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Win32_PerfFormattedData_PerfDisk_LogicalDisk&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Win32_PerfFormattedData_PerfDisk_PhysicalDisk&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Win32_PerfFormattedData_PerfOS_PagingFile&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Win32_PerfFormattedData_PerfOS_Processor&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Win32_PerfFormattedData_PerfOS_Memory&lt;/p&gt;
&lt;p class="Body" align="left"&gt;&lt;span style="font-size:12px;"&gt;You should use the &lt;/span&gt;&lt;strong style="font-size:12px;"&gt;Recurse&lt;/strong&gt;&lt;span style="font-size:12px;"&gt; parameter&amp;nbsp;when searching for these classes because they won&amp;rsquo;t necessarily be added to the default WMI namespace.&lt;/span&gt;&lt;/p&gt;
&lt;p class="Callout" style="padding-left:30px;" align="left"&gt;&lt;strong&gt;Tip&lt;/strong&gt; &amp;nbsp; The Win32_PerfFormattedData class is a superclass that will call the other performance formatted data classes. There will be a lot of data to wade through.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;There are also related classes that return the raw performance counter data. These classes are difficult to use, because each value has to be processed through a calculation to derive a meaningful result. It&amp;rsquo;s easier to use the formatted WMI classes or &lt;strong&gt;Get-Counter&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Problem&lt;/h3&gt;
&lt;p class="Body1" align="left"&gt;You need to monitor the processor performance of one of your systems. The server has multiple processors (or cores), and you need to display the information for each processor core and the total to ensure that the application is using the processor resources in an optimum manner.&lt;/p&gt;
&lt;h3&gt;Solution&lt;/h3&gt;
&lt;p class="Body1" align="left"&gt;The following listing presents a function that takes a computer name and a number as parameters. The number determines how many times you&amp;rsquo;ll sample the processor information.&lt;/p&gt;
&lt;p class="Body"&gt;&lt;strong&gt;Listing 1 Accessing performance counters&lt;/strong&gt;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;function get-cpucounter{&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;[CmdletBinding()]&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;param (&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;[parameter(ValueFromPipeline=$true,&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp; ValueFromPipelineByPropertyName=$true)]&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp; [string]$computername=&amp;quot;$env:COMPUTERNAME&amp;quot;,&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp; [int]$number=1&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;)&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;BEGIN{&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#1&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;$source=@&amp;quot;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;public class CPUcounter&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;{&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public&amp;nbsp; string&amp;nbsp; Timestamp&amp;nbsp; {get; set;}&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public&amp;nbsp; string Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {get; set;}&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public&amp;nbsp; ulong PercProcTime&amp;nbsp; {get; set;}&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;quot;@&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Add-Type -TypeDefinition $source -Language CSharpversion3&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}#begin&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;PROCESS{&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;1..$number | foreach {&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;$date = (Get-Date).ToString()&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Processor `&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;-ComputerName $computername | foreach {&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $value = New-Object -TypeName CPUCounter -Property @{&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TimeStamp = $date&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Name = $_.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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #2&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PercProcTime&amp;nbsp; = $_.PercentProcessorTime&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $value&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;Start-Sleep -Seconds 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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#3&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}#process&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p class="CodeAnnotation" style="padding-left:30px;"&gt;#1 Create class&lt;/p&gt;
&lt;p class="CodeAnnotation" style="padding-left:30px;"&gt;#2 Create object and set properties&lt;/p&gt;
&lt;p class="CodeAnnotation" style="padding-left:30px;"&gt;#3 Pause execution&lt;/p&gt;
&lt;p class="Body" align="left"&gt;&lt;span style="font-size:12px;"&gt;Some inline C# code is used to create a new .NET class&amp;nbsp;to store your results (#1). The class defines three properties&amp;mdash;a timestamp, the name of the processor, and the percentage processor time (how much it was used during the measurement period). This is compiled by using &lt;/span&gt;&lt;strong style="font-size:12px;"&gt;Add-Type&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;. Creating a class in this manner enables you to strongly type the properties, which supplies another level of error checking.&lt;/span&gt;&lt;/p&gt;
&lt;p class="Body" align="left"&gt;The range operator (&lt;strong&gt;..&lt;/strong&gt;) is used to put the required series of numbers into the pipeline. Windows PowerShell will process each value, and for each of them retrieve the processor performance data by using Win32_PerfFormattedData_PerfOS_Processor. One object per processor, plus one for the total, will be returned. You create an object by using your specially created .NET class, populate its properties (#2), and output it. A one-second pause is activated before you start again (#3).&lt;/p&gt;
&lt;p class="Body" align="left"&gt;On my development system, I use this code:&lt;span style="font-size:12px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;1..10 | foreach {Measure-Command -Expression {Get-WmiObject&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;[CA] -Class Win32_PerfFormattedData_PerfOS_Processor&amp;nbsp; }}&lt;span style="font-size:12px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="Body1" align="left"&gt;It show that the &lt;strong&gt;Get-WmiObject&lt;/strong&gt; command&amp;nbsp;takes about 300 milliseconds to retrieve the data. The function could be altered to change the delay, or you could even make it a parameter.&lt;/p&gt;
&lt;h3&gt;Discussion&lt;/h3&gt;
&lt;p class="Body1" align="left"&gt;The following image displays the results from using this function. The results show that processing is relatively equally distributed across the two cores. I wouldn&amp;rsquo;t expect to see the values being identical across all processors or cores all of the time.&lt;/p&gt;
&lt;p class="FigureCaption"&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2146.wes_2D00_4_2D00_6_2D00_13_2D00_3.png"&gt;&lt;img style="border:0px currentColor;" title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2146.wes_2D00_4_2D00_6_2D00_13_2D00_3.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class="Callout" style="padding-left:30px;" align="left"&gt;&lt;strong&gt;Tip&lt;/strong&gt; &amp;nbsp;&amp;nbsp;In case you&amp;rsquo;re wondering how I managed to drive processor performance so high, I set a few continuously looping recursive directory listings. They&amp;rsquo;re a good way to tax the system without spending a lot of money on simulation tools.&lt;/p&gt;
&lt;p class="Body1" align="left"&gt;Each of the WMI performance counter classes will need to be investigated to determine the properties that you need to record. For example, the class used here also returns information regarding interrupts.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;One common scenario that you&amp;rsquo;ll get is users&amp;rsquo; claiming a difference in performance between two systems. You can use the Windows system assessment report to provide a high-level comparison between the hardware of the two systems.&lt;/p&gt;
&lt;h2&gt;Windows system assessment report&lt;/h2&gt;
&lt;p class="Body1" align="left"&gt;The assessment report was introduced in Windows Vista. It examines a number of hardware components to determine an overall score for the system.&lt;/p&gt;
&lt;p class="Callout" style="padding-left:30px;" align="left"&gt;&lt;strong&gt;Tip&lt;/strong&gt; &amp;nbsp; The overall score is determined by the lowest of the individual component scores. Always examine the full report to determine whether a single component is adversely affecting performance.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;Accessing this information for the local computer through the GUI is acceptable, but you also need a way to perform this action remotely.&lt;/p&gt;
&lt;h3&gt;Problem&lt;/h3&gt;
&lt;p class="Body1" align="left"&gt;You need to create Windows system assessment reports for a number of remote computers. This will enable you to determine which computers should be refreshed and which are worth reusing.&lt;/p&gt;
&lt;h3&gt;Solution&lt;/h3&gt;
&lt;p class="Body1" align="left"&gt;The following listing utilizes the Win32_WinSat class to solve this issue. A hash table lookup is created to decode the assessment state property.&lt;span style="font-size:12px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="Body1" align="left"&gt;&lt;strong&gt;Listing 2: System assessment information&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;$satstate = DATA {&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;ConvertFrom-StringData -StringData @&amp;#39;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;0 = StateUnknown&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;1 = Valid&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;2 = IncoherentWithHardware&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;3 = NoAssessmentAvailable&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;4 = Invalid&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;#39;@&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;function get-systemassessment{&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;[CmdletBinding()]&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;param (&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;[parameter(ValueFromPipeline=$true,&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp; ValueFromPipelineByPropertyName=$true )]&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp; [string]$computername=&amp;quot;$env:COMPUTERNAME&amp;quot;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;)&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;PROCESS{&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;Get-WmiObject -Class Win32_WinSat -ComputerName $computername |&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;select CPUScore, D3DScore, DiskScore, GraphicsScore,&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;MemoryScore, TimeTaken,&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;@{N=&amp;quot;AssessmentState&amp;quot;; E={$satstate[&amp;quot;$($_.WinSATAssessmentState)&amp;quot;]}},&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;@{N=&amp;quot;BaseScore&amp;quot;; E={$_.WinSPRLevel}}&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}#process&lt;/p&gt;
&lt;p class="Code" style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p class="Body" align="left"&gt;&amp;nbsp;&lt;span style="font-size:12px;"&gt;The function returns the data from the WMI class&amp;nbsp;and uses &lt;/span&gt;&lt;strong style="font-size:12px;"&gt;Select-Object&lt;/strong&gt;&lt;span style="font-size:12px;"&gt; to output the properties and two calculated fields. One calculated field decodes the assessment state and the other renames the overall score.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Discussion&lt;/h3&gt;
&lt;p class="Body1" align="left"&gt;This report shouldn&amp;rsquo;t be taken in isolation when looking at system performance. The age of the system and any remaining warranty should also be considered.&lt;/p&gt;
&lt;p class="Body1" align="left"&gt;Working with event logs, scheduled jobs, and performance indicators is an essential part of the administrator&amp;rsquo;s role. Windows PowerShell and WMI provide a number of tools to help you in these tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Event log discovery and configuration&lt;/li&gt;
&lt;li&gt;Backup and clearing of event logs&lt;/li&gt;
&lt;li&gt;Lifecycle management for scheduled jobs, including creation, discovery, and deletion&lt;/li&gt;
&lt;li&gt;Retrieval of data from performance counters&lt;/li&gt;
&lt;li&gt;Production of system assessment reports and stability index data&lt;/li&gt;
&lt;/ul&gt;
&lt;p class="Body" align="left"&gt;These techniques enable you to gather data for possible forensic investigations, perform out-of-hours tasks through scheduling jobs, and determine how your systems are performing in real time and with a historic perspective. We discussed two of those techniques: performance counters and Windows system assessment reports.&lt;/p&gt;
&lt;p class="Body" align="left"&gt;~Richard&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;strong&gt;Here is the code for the discount offer today at &lt;/strong&gt;&lt;a href="http://www.manning.com/" target="_blank"&gt;www.manning.com&lt;/a&gt;: &lt;strong&gt;scriptw6&lt;/strong&gt;&lt;br /&gt; Valid for 50% off &lt;a href="http://www.manning.com/siddaway2/" target="_blank"&gt;PowerShell and WMI&lt;/a&gt; and &lt;a href="http://www.manning.com/wicklund/" target="_blank"&gt;SharePoint 2010 Workflows in Action&lt;/a&gt; &lt;br /&gt; Offer valid from April 6, 2013 12:01 AM until April 7, midnight (EST)&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3563534" width="1" height="1" alt="" /&gt;</description></item><item><title>Weekend Scripter: Managing Dell AppAssure with Windows PowerShell</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/03/31/weekend-scripter-managing-dell-appassure-with-windows-powershell.aspx</link><pubDate>Sun, 31 Mar 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:22537</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;strong style="font-size:12px;"&gt;Summary&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;: Guest blogger, Mike Robbins, talks about using Windows PowerShell to manage Dell AppAssure.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Guest blogger, Mike Robbins, returns today to share his experience. You can also read &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/tags/mike+f+robbins/" target="_blank"&gt;previous blogs by Mike&lt;/a&gt;.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8054.wes_2D00_3_2D00_31_2D00_13_2D00_bio.jpg"&gt;&lt;img title="Photo of Mike Robbins" src="http://blogs.technet.com/resized-image.ashx/__size/150x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8054.wes_2D00_3_2D00_31_2D00_13_2D00_bio.jpg" alt="Photo of Mike Robbins" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:12px;"&gt;Mike Robbins is a senior systems engineer with almost 20 years of professional experience as an IT pro who currently works for a healthcare company located in Meridian, MS. During his career, Mike has provided enterprise computing solutions for educational, financial, healthcare, and manufacturing customers. He&amp;rsquo;s a Windows PowerShell enthusiast who uses Windows PowerShell on a daily basis to administer Windows Server, Hyper-V, SQL Server, Exchange Server, SharePoint, Active Directory, Terminal Services, EqualLogic Storage Area Networks, AppAssure, and Backup Exec. Mike is an author of a chapter in the book &lt;/span&gt;&lt;a style="font-size:12px;" href="http://manning.com/hicks/" target="_blank"&gt;PowerShell Deep Dives&lt;/a&gt;&lt;span style="font-size:12px;"&gt;, he has presented sessions at PowerShell Saturday 003 in Atlanta, for the Mississippi PowerShell User Group, and for the Florida PowerShell User Group. Mike is also one of the cofounders of the &lt;/span&gt;&lt;a style="font-size:12px;" href="http://mspsug.com/" target="_blank"&gt;Mississippi PowerShell User Group&lt;/a&gt;&lt;span style="font-size:12px;"&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Blog: &lt;a href="http://mikefrobbins.com/" target="_blank"&gt;Mike F Robbins Computing Solutions&lt;/a&gt;&lt;br /&gt; Twitter: &lt;a href="http://twitter.com/mikefrobbins"&gt;@mikefrobbins&lt;/a&gt;&lt;br /&gt;&lt;a href="http://mspsug.com" target="_blank"&gt; Mississippi PowerShell User Group&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s Mike&amp;hellip;&lt;/p&gt;
&lt;p&gt;For those of you not familiar with Dell AppAssure, it&amp;rsquo;s a backup, replication, and recovery solution. More information about this product can be found on the &lt;a href="http://www.appassure.com/"&gt;AppAssure&lt;/a&gt; website.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s no secret that I&amp;rsquo;m a big fan of Windows PowerShell so when a third-party vendor, such as Dell, adds PowerShell support to their products, I also become very interested in those products. (I&amp;rsquo;m not affiliated with Microsoft, Dell, or AppAssure in any way other than being a customer.)&lt;/p&gt;
&lt;p&gt;AppAssure added Windows PowerShell support via a Windows PowerShell module in version 5.3.1 of their product. This module named AppAssurePowerShellModule includes a total of 31 cmdlets, which are &amp;nbsp;listed in the following image:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/1067.wes_2D00_3_2D00_31_2D00_13_2D00_1.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/1067.wes_2D00_3_2D00_31_2D00_13_2D00_1.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:12px;"&gt;Usually most vendors are slow to support the latest and greatest version of Windows PowerShell, but not AppAssure. According to AppAssure&amp;rsquo;s support documentation, &lt;/span&gt;&lt;a style="font-size:12px;" href="http://www.appassure.com/support/KB/how-to-import-the-appassure-5-powershell-module/" target="_blank"&gt;How to Import the AppAssure 5 PowerShell Module&lt;/a&gt;&lt;span style="font-size:12px;"&gt;, they prefer Windows PowerShell&amp;nbsp;3.0, although Windows PowerShell&amp;nbsp;2.0 is also supported. The examples found in this blog use Windows PowerShell&amp;nbsp;3.0 syntax, which also means that the AppAssure PowerShell module doesn&amp;rsquo;t have to be explicitly imported before using the cmdlets. If you were running Windows PowerShell&amp;nbsp;2.0, you would need to import the AppAssure PowerShell module by using the following command prior to attempting to use any of the cmdlets:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6545.wes_2D00_3_2D00_31_2D00_13_2D00_2.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6545.wes_2D00_3_2D00_31_2D00_13_2D00_2.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the previous example, &lt;strong&gt;Name&lt;/strong&gt; is a positional parameter which can be omitted if the first item specified after &lt;strong&gt;Import-Module&lt;/strong&gt; is the name of the Windows PowerShell module.&lt;/p&gt;
&lt;p&gt;From what I&amp;rsquo;ve seen in the industry, the average IT pro isn&amp;rsquo;t using Windows PowerShell yet. Hopefully that will soon change with more third-party vendors adding Windows PowerShell integration to their products and with cmdlets (such as those in the AppAssure PowerShell module) being so easy to use. Most of the cmdlets in the AppAssure PowerShell module require only opening Windows PowerShell on the AppAssure core server and running the cmdlet with no parameters or with very few mandatory parameters being required.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Get-ProtectedServers&lt;/strong&gt; cmdlet is a perfect example of this. It returns all of the servers that are protected by the AppAssure core server that you&amp;rsquo;re currently logged in to without specifying anything other than the cmdlet name. The information provided includes the server names, status, AppAssure agent version, and a few other properties:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5707.wes_2D00_3_2D00_31_2D00_13_2D00_3.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5707.wes_2D00_3_2D00_31_2D00_13_2D00_3.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wasn&amp;rsquo;t that much easier and more efficient than using the GUI to retrieve this information? Grouping the protected servers to determine how many are listed for each version, or returning a list that is grouped by version (including the names of the protected servers for each version) are also easy tasks when using Windows PowerShell:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3175.wes_2D00_3_2D00_31_2D00_13_2D00_4.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3175.wes_2D00_3_2D00_31_2D00_13_2D00_4.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve found something that it is difficult to determine in the AppAssure GUI. When I start replicating protected servers to another AppAssure core server, and I choose to initially seed the transfer via SneakerNet, how do I know when the seeding of the protected server to the portable media device is complete?&lt;/p&gt;
&lt;p&gt;This is something that&amp;rsquo;s very important. Disconnecting it from the source AppAssure core server and shipping it to the site where the destination AppAssure core server resides, before the seeding process has completed, could cause the protected servers to not be replicated, not have a replicated base image, or have an orphaned chain of recovery points. Determining the seed drive progress for each protected server that you&amp;rsquo;ve chosen to replicate to a remote AppAssure core server is also easy to determine with Windows PowerShell as shown in the following example:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3010.wes_2D00_3_2D00_31_2D00_13_2D00_5.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3010.wes_2D00_3_2D00_31_2D00_13_2D00_5.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not really a big fan of logging on to a server via a remote desktop to manage it. In the following scenario, I use the &lt;strong&gt;New-PSSession&lt;/strong&gt; cmdlet to create a persistent connection to three AppAssure core servers. Two of the servers are in different Active Directory forests than the Windows 8 workstation where I am running the commands. Each of these AppAssure core servers requires different credentials than those I&amp;rsquo;m currently using on my workstation and to run Windows PowerShell. They also each require different credentials than the others:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7380.wes_2D00_3_2D00_31_2D00_13_2D00_6.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7380.wes_2D00_3_2D00_31_2D00_13_2D00_6.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;According to the previously referenced AppAssure article, &lt;a href="http://www.appassure.com/support/KB/how-to-import-the-appassure-5-powershell-module/" target="_blank"&gt;How to Import the AppAssure 5 PowerShell Module&lt;/a&gt;, the module shouldn&amp;rsquo;t be imported on a non-AppAssure core server. This is why I don&amp;rsquo;t have the AppAssure Windows PowerShell module installed on my local workstation. Using the Windows PowerShell &lt;strong&gt;Invoke-Command&lt;/strong&gt; cmdlet allows us to remotely manage multiple AppAssure core servers while staying within the recommended supported configuration for using their Windows PowerShell module.&lt;/p&gt;
&lt;p&gt;Now I can use a single Windows PowerShell command to check the status of all the protected servers in the three datacenters, which have an AppAssure core server. I want to know if any of the servers that are supposed to be protected by AppAssure aren&amp;rsquo;t being protected:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6712.wes_2D00_3_2D00_31_2D00_13_2D00_7.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6712.wes_2D00_3_2D00_31_2D00_13_2D00_7.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Based on the results in the previous example, I have one server out of all the protected servers in all three datacenters that has a status of &lt;strong&gt;unreachable&lt;/strong&gt;. This doesn&amp;rsquo;t seem too impressive until you factor in that the three datacenters have a total of 53 protected servers:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5047.wes_2D00_3_2D00_31_2D00_13_2D00_8.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5047.wes_2D00_3_2D00_31_2D00_13_2D00_8.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With that many servers, it&amp;rsquo;s easy to see how efficient it is to use this Windows PowerShell command rather than using the AppAssure GUI (web) interface. It took a total of 1 minute and 25 seconds to query the three AppAssure core servers for the status on all 53 protected servers:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6014.wes_2D00_3_2D00_31_2D00_13_2D00_9.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6014.wes_2D00_3_2D00_31_2D00_13_2D00_9.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Two of the AppAssure core servers and twenty-two of the protected servers in the previous example reside at remote datacenters that are connected via a VPN across the Internet (not on the LAN).&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve only looked at one of the cmdlets provided in the AppAssure PowerShell module in this blog, but there&amp;rsquo;s much more that can be done with Windows PowerShell when it comes to managing AppAssure. Want to protect a new server? That&amp;rsquo;s what the &lt;strong&gt;Start-Protect&lt;/strong&gt; cmdlet is for. Want to pause the AppAssure replication between AppAssure core servers during business hours and resume it after business hours due to bandwidth constraints?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s what the &lt;strong&gt;Suspend-Replication&lt;/strong&gt; and &lt;strong&gt;Resume-Replication&lt;/strong&gt; cmdlets are for. This is also where Windows PowerShell&amp;nbsp;3.0 comes in handy. You could use Windows PowerShell to set up scheduled tasks that run Windows PowerShell commands to pause and resume the replication. I wrote a blog about that very subject last month: &lt;a href="http://mikefrobbins.com/2013/02/07/use-powershell-to-create-a-scheduled-task-that-uses-powershell-to-pause-and-resume-appassure-core-replication/" target="_blank"&gt;Use PowerShell to Create a Scheduled Task that Uses PowerShell to Pause and Resume AppAssure Core Replication&lt;/a&gt;. It demonstrates this process, if it&amp;rsquo;s something of interest.&lt;/p&gt;
&lt;p&gt;There is also an AppAssure event log added to the AppAssure core server during installation of the product that contains an abundance of information that can be queried by using Windows PowerShell&amp;mdash;as you would any other event log.&lt;/p&gt;
&lt;p&gt;Where can we find more information about Managing Dell AppAssure with Windows PowerShell? In the &lt;a href="http://docs.appassure.com/display/AA50D/AppAssure+5+Technical+Documentation" target="_blank"&gt;AppAssure 5 Technical Documentation&lt;/a&gt; section of the AppAssure website, there&amp;rsquo;s an &lt;em&gt;AppAssure 5 PowerShell Reference Guide&lt;/em&gt;. You could also view the Help for the cmdlets contained in the AppAssure PowerShell module. If you&amp;rsquo;re interested in more blog posts about using Windows PowerShell to manage Dell AppAssure, see the &lt;a href="http://mikefrobbins.com/category/appassure/" target="_blank"&gt;AppAssure category&lt;/a&gt; on my site, &lt;a href="http://mikefrobbins.com/"&gt;Mike F Robbins Computing Solutions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I would also like to invite you to join us on the second Tuesday of each month at 8:30 PM Central Time for the &lt;a href="http://mspsug.com/"&gt;Mississippi PowerShell User Group&lt;/a&gt; meetings. These meetings are held online (virtual) via Microsoft Lync. Anyone from anywhere can join in and learn more about Windows PowerShell from our awesome line-up of speakers that we have scheduled throughout 2013. Each of our guest speakers for the remainder of this year is an author of at least one chapter in the book &lt;a href="http://manning.com/hicks/" target="_blank"&gt;PowerShell Deep Dives&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;~Mike&lt;/p&gt;
&lt;p&gt;Awesome blog post, Mike. Thank you so much for taking the time to share your experience with us.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3561658" width="1" height="1" alt="" /&gt;</description></item><item><title>Weekend Scripter: Run C# Code from Within PowerShell</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/03/30/weekend-scripter-run-c-code-from-within-powershell.aspx</link><pubDate>Sat, 30 Mar 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:22516</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;strong style="font-size:12px;"&gt;Summary&lt;/strong&gt;&lt;span style="font-size:12px;"&gt;: Learn how to execute C# programs from source without a compiled binary by using Windows PowerShell.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Today guest blogger, Ingo Karstein, is back with us to share his knowledge. You can also read &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/tags/ingo+karstein/" target="_blank"&gt;previous guest blogs by Ingo&lt;/a&gt;. Take it away Ingo&amp;hellip;&lt;/p&gt;
&lt;p&gt;Some time ago, I created a script called PS2EXE that creates EXE files out of Windows PowerShell script files. It is posted on the Hey, Scripting Guy! Blog: &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2011/07/22/learn-about-two-codeplex-projects-ps2exe-and-robopowercopy.aspx" target="_blank"&gt;Learn About Two CodePlex Projects: PS2EXE and RoboPowerCopy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now I have created another script, rather the opposite of PS2EXE: &lt;strong&gt;C#Script&lt;/strong&gt;. This script is able to execute C# programs from source code without a compiled binary.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve done this because I have several C# tools that I always use for my daily business. Some of them are not easily convertible to Windows PowerShell. But I like the fact that script files are always readable because you only need the source code, no compiler. There is no need for binaries with separate source projects somewhere on the hard disk, so I decided to create a script with the purpose of running C# code inside Windows PowerShell.&lt;/p&gt;
&lt;p&gt;The idea is simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Take a C# program file and compile it into the memory.&lt;/li&gt;
&lt;li&gt;Search for the &lt;strong&gt;Main&lt;/strong&gt; method and call them using .NET reflection.&lt;/li&gt;
&lt;li&gt;Add some basic .NET console support to write output from the C# program to the Windows PowerShell environment.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The C# program will be executed in a real .NET thread that is created in the Windows PowerShell script by using a helper class that is compiled in memory at runtime too. This helper class provides some synchronous .NET events that can be subscribed in Windows PowerShell to handle the console output.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;strong&gt;Note&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;You can download C#Script from the Microsoft TechNet Gallery: &lt;a href="http://gallery.technet.microsoft.com/C-Script-Execute-plain-a9eae961" target="_blank"&gt;C#Script: Execute source code C# programs from PowerShell&lt;/a&gt;. You should be aware of the following limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This project is in the alpha state! There will be errors in it. So please be careful, especially in a production environment.&lt;/li&gt;
&lt;li&gt;Console input not implemented. Therefore, we need a custom class derived from System.IO.TextReader.&lt;/li&gt;
&lt;li&gt;There is no resource file support! It is just plain C#.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To demonstrate the script, I created two C# demo projects: &amp;ldquo;Test&amp;rdquo; and &amp;ldquo;TestWin.&amp;rdquo; The first one is a console application, the second is a Windows Forms application.&lt;/p&gt;
&lt;p&gt;The following screenshot shows my &amp;ldquo;TestWin&amp;rdquo; demo project. My csscript.ps1 file is in the folder &amp;ldquo;C:\source2\csscript,&amp;rdquo; and &amp;ldquo;testwin&amp;rdquo; is in the subfolder.&amp;nbsp;(The Windows 8 operating system is in German, but you get the point, I&amp;rsquo;m sure.)&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3808.wes_2D00_3_2D00_30_2D00_13_2D00_1.png"&gt;&lt;img title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3808.wes_2D00_3_2D00_30_2D00_13_2D00_1.png" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:12px;"&gt;Let&amp;rsquo;s have a look into &amp;ldquo;TestWin.&amp;rdquo; The following screenshot is from the Visual Studio 2012 project.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7725.wes_2D00_3_2D00_30_2D00_13_2D00_2.png"&gt;&lt;img title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7725.wes_2D00_3_2D00_30_2D00_13_2D00_2.png" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Of course it can be run in Visual Studio 2012 or as standalone .NET assembly (EXE file). The list box is empty. It would show the program&amp;#39;s arguments if there were any.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2211.wes_2D00_3_2D00_30_2D00_13_2D00_3.png"&gt;&lt;img title="Image of dialog box" src="http://blogs.technet.com/resized-image.ashx/__size/300x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2211.wes_2D00_3_2D00_30_2D00_13_2D00_3.png" alt="Image of dialog box" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:12px;"&gt;At the beginning of the Program.cs file, there is an XML configuration section for C#Script:&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;lt;csscript&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp; &amp;lt;nodebug/&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp; &amp;lt;references&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;reference&amp;gt;System&amp;lt;/reference&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;reference&amp;gt;System.Core&amp;lt;/reference&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;reference&amp;gt;System.Data&amp;lt;/reference&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;reference&amp;gt;System.Data.DataSetExtensions&amp;lt;/reference&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;reference&amp;gt;System.Xml&amp;lt;/reference&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;reference&amp;gt;System.Xml.Linq&amp;lt;/reference&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;reference&amp;gt;System.Windows.Forms&amp;lt;/reference&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;reference&amp;gt;System.Drawing&amp;lt;/reference&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp; &amp;lt;/references&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp; &amp;lt;mode&amp;gt;winexe&amp;lt;/mode&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp; &amp;lt;files&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;file&amp;gt;Form1.cs&amp;lt;/file&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;file&amp;gt;Form1.Designer.cs&amp;lt;/file&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;////&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;file&amp;gt;Test&amp;lt;/file&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;nbsp; &amp;lt;/files&amp;gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;//&amp;lt;/csscript&amp;gt;&lt;/p&gt;
&lt;p&gt;This rules the compilation of the program when using C#Script. Here, you specify the .NET assembly references, the execution mode, and the source files. By using four slash characters, the line will be ignored. In the &amp;ldquo;files&amp;rdquo; section, you specify all necessary C# files if there are more than one. The additional files do not&amp;nbsp; need XML configuration.&lt;/p&gt;
&lt;p&gt;In my demo, the project needs three C# files to run: Program.cs, Form1.cs, and Form1.Designer.cs. The configuration XML is stored only at the beginning of Program.cs.&amp;rdquo;&amp;nbsp;&lt;span style="font-size:12px;"&gt;By using &lt;/span&gt;&lt;strong style="font-size:12px;"&gt;&amp;lt;debug/&amp;gt;,&lt;/strong&gt;&lt;span style="font-size:12px;"&gt; it&amp;rsquo;s possible to debug the C# program file. I will show that later.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s go to the Windows PowerShell command line and use C#Script:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5241.wes_2D00_3_2D00_30_2D00_13_2D00_4.png"&gt;&lt;img title="Image of command" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/5241.wes_2D00_3_2D00_30_2D00_13_2D00_4.png" alt="Image of command" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At the command line, I type:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;.\csscript.ps1 .\testwin\testwin\Program.cs &amp;quot;Greetings&amp;quot; &amp;quot;from&amp;quot; &amp;quot;germany&amp;quot; &amp;quot;!&amp;quot;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s have a look at the console application demo.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7271.wes_2D00_3_2D00_30_2D00_13_2D00_5.png"&gt;&lt;img title="Image of menu" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/7271.wes_2D00_3_2D00_30_2D00_13_2D00_5.png" alt="Image of menu" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At the Windows PowerShell command line, I type:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;.\csscript.ps1 .\test\test\Program.cs &amp;quot;Greetings&amp;quot; &amp;quot;from&amp;quot; &amp;quot;germany&amp;quot; &amp;quot;!&amp;quot;&lt;/p&gt;
&lt;p&gt;Here I use the &lt;strong&gt;&amp;lt;debug/&amp;gt;&lt;/strong&gt; configuration to be able to debug the program. This gives me the Debugger Attach dialog from Visual Studio&amp;nbsp;2012 when I run the previous command-line statement:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3073.wes_2D00_3_2D00_30_2D00_13_2D00_6.png"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3073.wes_2D00_3_2D00_30_2D00_13_2D00_6.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You will automatically get the source file of the C#Script internal helper class with hard coded breakpoints:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3750.wes_2D00_3_2D00_30_2D00_13_2D00_7.png"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3750.wes_2D00_3_2D00_30_2D00_13_2D00_7.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here you can see how it works inside: Internally it creates a thread and executes the original program by reflection. The &lt;strong&gt;Main&lt;/strong&gt; method of the C# program is given in &lt;strong&gt;Method&lt;/strong&gt; parameter, and the command-line arguments are in the &lt;strong&gt;prms&lt;/strong&gt; parameter.&lt;/p&gt;
&lt;p&gt;The next hard coded breakpoint is specified in the Program.cs file. The file will have a new name. (Here the name is &lt;strong&gt;n_dspgoj.0.cs&lt;/strong&gt;.)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2625.wes_2D00_3_2D00_30_2D00_13_2D00_8.png"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2625.wes_2D00_3_2D00_30_2D00_13_2D00_8.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is the output in the console:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0601.wes_2D00_3_2D00_30_2D00_13_2D00_9.png"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0601.wes_2D00_3_2D00_30_2D00_13_2D00_9.png" alt="Image of command output" /&gt;&lt;/a&gt;&amp;gt;&lt;/p&gt;
&lt;p&gt;In the C#Script package, I&amp;rsquo;ve included a file named &amp;ldquo;csscript.bat&amp;rdquo; that helps you execute csscript from the traditional Windows shell:&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/1205.wes_2D00_3_2D00_30_2D00_13_2D00_10.png"&gt;&lt;img title="Image of script" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/1205.wes_2D00_3_2D00_30_2D00_13_2D00_10.png" alt="Image of script" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can use it like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0317.wes_2D00_3_2D00_30_2D00_13_2D00_11.png"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0317.wes_2D00_3_2D00_30_2D00_13_2D00_11.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tested this C#Script with one of my favorite tools: the SharePoint Feature Administration and Clean Up Tool (it&amp;rsquo;s a Windows Forms application).&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:12px;"&gt;1. I downloaded the code from CodePlex: &lt;/span&gt;&lt;a style="font-size:12px;" href="http://featureadmin.codeplex.com/SourceControl/changeset/view/78751" target="_blank"&gt;SharePoint Feature Administration and Clean Up Tool&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:12px;"&gt;2. Unzip to a folder.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:12px;"&gt;3. Create a batch file &amp;ldquo;run.bat.&amp;rdquo;&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;span style="font-size:12px;"&gt;@echo off&lt;/span&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;call csscript.bat &amp;quot;FeatureAdmin2013-VisualStudio2012\Program.cs&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;4.&amp;nbsp;&lt;span style="font-size:12px;"&gt;Copy &amp;ldquo;csscript.ps1&amp;rdquo; and &amp;ldquo;csscript.bat&amp;rdquo; into the folder.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8228.wes_2D00_3_2D00_30_2D00_13_2D00_12.png"&gt;&lt;img title="Image of folder" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/8228.wes_2D00_3_2D00_30_2D00_13_2D00_12.png" alt="Image of folder" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:12px;"&gt;5. Modify the file &amp;ldquo;Program.cs&amp;rdquo; to contain the config XML structure.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6371.wes_2D00_3_2D00_30_2D00_13_2D00_13.png"&gt;&lt;img title="Image of script" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/6371.wes_2D00_3_2D00_30_2D00_13_2D00_13.png" alt="Image of script" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;strong&gt;Note&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;ldquo;requiredframework&amp;rdquo; and &amp;ldquo;requiredplatform&amp;rdquo; are set because SharePoint 2013 needs .NET Framework&amp;nbsp;4.0 and 64-bit processes.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:12px;"&gt;6. Execute the program with &amp;ldquo;run.bat&amp;rdquo; without compilation in VS2012.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0310.wes_2D00_3_2D00_30_2D00_13_2D00_14.png"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/0310.wes_2D00_3_2D00_30_2D00_13_2D00_14.png" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For this program, I&amp;rsquo;ll not need a compiled EXE anymore! Now I&amp;rsquo;d like to get your response! If you found any errors, please report them on the TechNet Gallery page: &lt;a href="http://gallery.technet.microsoft.com/C-Script-Execute-plain-a9eae961" target="_blank"&gt;C#Script: Execute source code C# programs from PowerShell&lt;/a&gt;. Please feel free to modify C#Script and send me your changes.&lt;/p&gt;
&lt;p&gt;~Ingo&lt;/p&gt;
&lt;p&gt;Ingo, thank you for sharing this with us today. I love it.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&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://blogs.technet.com/aggbug.aspx?PostID=3561632" width="1" height="1" alt="" /&gt;</description></item><item><title>Weekend Scripter: Convert Word Documents to PDF Files with PowerShell</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/03/24/weekend-scripter-convert-word-documents-to-pdf-files-with-powershell.aspx</link><pubDate>Sun, 24 Mar 2013 05:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:22442</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;: Windows PowerShell MVP, Sean Kearney, talks about using Windows PowerShell to convert Word documents to PDF files en-masse.&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Today&amp;rsquo;s blog is brought to you by Windows PowerShell MVP and honorary Scripting Guy, Sean Kearney.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/tags/sean+kearney/" target="_blank"&gt;Previous blog posts by Sean Kearney&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Take it away Sean&amp;hellip;&lt;/p&gt;
&lt;p&gt;My boss looks up at me today, and sighs, &amp;ldquo;I love the built-in &lt;strong&gt;SaveAs PDF&lt;/strong&gt; in Word 2013. But I want to do multiple documents at the same time. Oh, if ONLY there was some way to do this in bulk.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The wires and lights starting blinking in my head. I&amp;rsquo;m about to leap out of my chair because I hear &amp;ldquo;Bulk.&amp;rdquo; Many to do, repeatable, and&amp;hellip;&lt;/p&gt;
&lt;p&gt;POWERSHELL!&lt;/p&gt;
&lt;p&gt;So accessing a file in Microsoft Word programmatically is quite easy. We&amp;rsquo;ve been doing it for years.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Word=NEW-OBJECT &amp;ndash;COMOBJECT WORD.APPLICATION&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Doc=$Word.Documents.Open(&amp;ldquo;C:\Foofile.docx&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;And along the same lines, we could save this same file in the following manner.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Doc.saveas([ref] &amp;ldquo;C:\Foofile.docx&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;If we would like to save it in an alternate format, like in .pdf format, things get a wee bit fancier. We have to speak a bit of .NET.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Doc.saveas([ref] &amp;ldquo;C:\Foofile.pdf&amp;rdquo;, [ref] 17)&lt;/p&gt;
&lt;p&gt;If your brain didn&amp;rsquo;t pop out just now, you&amp;rsquo;re OK. Let&amp;rsquo;s get a little fancier. What if I want Microsoft Word to save that PDF file with the same name as the parent without knowing the name?&lt;/p&gt;
&lt;p&gt;Now we&amp;rsquo;re stepping into the land of fun. We can access the file name of that single document in the following way. Three of the available properties in the Word object are the &lt;strong&gt;Name&lt;/strong&gt; of the document, the &lt;strong&gt;Path&lt;/strong&gt; to the document, and the &lt;strong&gt;FullName&lt;/strong&gt; path. I poked out using the following cmdlet to&amp;hellip;well, to be honest&amp;hellip;to guess.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Doc | get-member &amp;ndash;membertype property *Name*&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2275.wes_2D00_3_2D00_24_2D00_13_2D00_1.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/2275.wes_2D00_3_2D00_24_2D00_13_2D00_1.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note the two little nuggets. In poking about and using a similar search for &lt;strong&gt;Path&lt;/strong&gt;, &amp;nbsp;I found&amp;nbsp;the property holding its path.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Doc | get-member &amp;ndash;membertype property *Path*&lt;/p&gt;
&lt;p&gt;So I could do something like this: Open some file, get the file name information, swap out .docx with .pdf, and then save it.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3681.wes_2D00_3_2D00_24_2D00_13_2D00_2.jpg"&gt;&lt;img title="Image of command output" src="http://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-76-18/3681.wes_2D00_3_2D00_24_2D00_13_2D00_2.jpg" alt="Image of command output" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With these three bits of information, I don&amp;rsquo;t have to actually know &amp;nbsp;the file name. Word will tell me based on the document. But let&amp;rsquo;s simplify this down a bit. Let&amp;rsquo;s just take a known file name and resave it as a PDF file with the same file name. All we need to do is run a &lt;strong&gt;Replace()&lt;/strong&gt; method on the provided file name, and swap .docx with .pdf.&lt;/p&gt;
&lt;p&gt;Yes&amp;hellip;.we&amp;rsquo;re presuming it&amp;rsquo;s a .pdf, J.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$File=&amp;rdquo;C:\Foofolder\foofile.docx&amp;rdquo;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Word=NEW-OBJECT &amp;ndash;COMOBJECT WORD.APPLICATION&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Doc=$Word.Documents.Open($File)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Doc.saveas([ref] (($File).replace(&amp;ldquo;docx&amp;rdquo;,&amp;rdquo;pdf&amp;rdquo;)), [ref] 17)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Doc.close()&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s all fine and dandy. But what if we have a folder of DOCX files that we want to convert at once?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s pretend we ran the following lines in Windows PowerShell:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$File=&amp;rdquo;C:\Foofolder\foofile.docx&amp;rdquo;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Files=GET-CHLDITEM &amp;lsquo;C:\FooFolder\*.DOCX&amp;rsquo;&lt;/p&gt;
&lt;p&gt;Now we could cheat and access the full file name and path by accessing the &lt;strong&gt;FullName&lt;/strong&gt; from the drive system. But let&amp;rsquo;s have some fun with Word and ask it these questions.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Foreach ($File in $Files) {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # open a Word document, filename from the directory&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Doc=$Word.Documents.Open($File.fullname)&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s ask Word what is the name of the file. And while we&amp;rsquo;re at it, let&amp;rsquo;s swap the .docx file extension with .pdf.&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp; $Name=($Doc.Fullname).replace(&amp;ldquo;docx&amp;rdquo;,&amp;rdquo;pdf&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;Then we&amp;rsquo;ll access that file within Microsoft Word and use the built-in &lt;strong&gt;SaveAs PDF&lt;/strong&gt; option in Word 2010 or Word 2013 to produce a PDF file in the same folder as the original Word document. When done, we close the file.&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Doc.saveas([ref] $Name, [ref] 17)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Doc.close()&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p&gt;So when done our script will look like this:&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;# Acquire a list of DOCX files in a folder&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Files=GET-CHLDITEM &amp;lsquo;C:\FooFolder\*.DOCX&amp;rsquo;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;Foreach ($File in $Files) {&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # open a Word document, filename from the directory&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Doc=$Word.Documents.Open($File.fullname)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Swap out DOCX with PDF in the Filename&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;$Name=($Doc.Fullname).replace(&amp;ldquo;docx&amp;rdquo;,&amp;rdquo;pdf&amp;rdquo;)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Save this File as a PDF in Word 2010/2013&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Doc.saveas([ref] $Name, [ref] 17)&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Doc.close()&lt;/p&gt;
&lt;p style="padding-left:30px;"&gt;}&lt;/p&gt;
&lt;p&gt;So why the big secrecy about using the document names in Word itself? In the future, I&amp;rsquo;ll show you how to programmatically trigger a mail merge, and you&amp;rsquo;ll see where it&amp;rsquo;s needed there.&lt;/p&gt;
&lt;p&gt;Cheers and remember to keep on scriptin&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;~Sean,&lt;br /&gt; The Energized Tech&lt;/p&gt;
&lt;p&gt;Thanks, Sean, for taking the time to share your scripting expertise with us today. Join me tomorrow when I have a guest blog post from Ingo Karstein about using Windows PowerShell with SharePoint. It is cool and you do not want to miss it.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3558495" width="1" height="1" alt="" /&gt;</description></item><item><title>Weekend Scripter: The PowerShell Community State of the Union</title><link>http://powershell.com/cs/blogs/hey-scriptingguy/archive/2013/03/03/weekend-scripter-the-powershell-community-state-of-the-union.aspx</link><pubDate>Sun, 03 Mar 2013 06:00:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:21942</guid><dc:creator>Anonymous</dc:creator><description>&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;: The Scripting Wife provides a status update on the Windows PowerShell Community and insights on upcoming activities.&lt;/p&gt;
&lt;p&gt;Microsoft Scripting Guy, Ed Wilson, is here. Today I was busy working on a Windows PowerShell script when the Scripting Wife came floating in and asked me if she could write a guest blog. When that happens (for that matter, whenever the Scripting Wife asks for anything), the answer is always, &amp;ldquo;Yes, of course.&amp;rdquo; So without further delay, here is Teresa Wilson, aka &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/tags/scripting+wife/" target="_blank"&gt;The Scripting Wife&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;PowerShell User Group update&lt;/h1&gt;
&lt;p&gt;Hello Scripters. Hope you are having a wonderful day. I asked Ed if I could write today about some new information for user groups and about a couple of upcoming events. Although he is a good husband and he usually agrees with things I ask him to do, he also is a great advocate for Windows PowerShell and the PowerShell community, which meant he said, &amp;ldquo;Of course.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;In June, I offered some information about starting a Windows PowerShell User Group in my blog, &lt;a href="http://blogs.technet.com/b/heyscriptingguy/archive/2012/06/23/weekend-scripter-scripting-wife-discusses-setting-up-a-powershell-user-group.aspx" target="_blank"&gt;Scripting Wife Discusses Setting Up a PowerShell User Group&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is the list of items that I suggested:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create your user group name and register it at &lt;a href="http://www.powershellgroup.org/" target="_blank"&gt;PowerShell Community Groups&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a Twitter account for the group.&lt;/li&gt;
&lt;li&gt;Sign up at &lt;a href="https://www.technicalcommunity.com/Pages/default.aspx" target="_blank"&gt;Microsoft User Group Support Services&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Sign up at &lt;a href="http://www.gitca.org/" target="_blank"&gt;GITCA&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Sign up at &lt;a href="http://www.ineta.org/default.aspx" target="_blank"&gt;INETA&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Register at &lt;a href="http://ug.oreilly.com/" target="_blank"&gt;O&amp;rsquo;Reilly User Groups&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Find a location to host the meetings.&lt;/li&gt;
&lt;li&gt;Identify and contact sponsors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And now the new kids in town...&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Register at &lt;a href="http://www.manning.com/ugprogram/" target="_blank"&gt;Manning User Group Program&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Register at &lt;a href="http://powershell.org/groups/" target="_blank"&gt;PowerShell.org&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And finally, one change that I am aware of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sign up at &lt;a href="https://www.technicalcommunity.com/Pages/default.aspx" target="_blank"&gt;Microsoft User Group Support Services&lt;/a&gt; was on my old list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style="padding-left:30px;"&gt;This is now &lt;a href="https://www.mstechaffiliate.com/" target="_blank"&gt;Microsoft Tech Affiliate Program&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I will continue to update you as I know new or different ideas to help get your group rolling.&lt;/p&gt;
&lt;p&gt;If you go to the &lt;a href="http://technet.microsoft.com/en-us/scriptcenter/hh182567" target="_blank"&gt;Scripting Community&lt;/a&gt; tab on the Script Center, there is a list of Ed&amp;rsquo;s upcoming engagements. Typically if Ed is there, I will be also. I cannot answer your questions about how to troubleshoot your script, but I know where to find answers. I am also happy to talk with people and remember what city they live near, then connect people as time goes by. So be sure to stop by and say, &amp;ldquo;Hello!&amp;rdquo; if you attend any of the events that Ed and I are attending.&lt;/p&gt;
&lt;p&gt;Two big events coming up are the &lt;a href="http://powershell.org/summit/" target="_blank"&gt;PowerShell Summit North America 2013&lt;/a&gt; in Redmond, Washington in April and &lt;a href="http://northamerica.msteched.com/#fbid=JnfJOgksrCb" target="_blank"&gt;TechEd North America 2013&lt;/a&gt; in New Orleans in June. I will be at the Scripting Guy booth the majority of the time. I typically only sneak off to grab a drink or a bite to eat. I love being at the booth and talking to people as they come through.&lt;/p&gt;
&lt;p&gt;As always, contact me on twitter @ScriptingWife or email me at &lt;a href="mailto:ScriptingWife@hotmail.com" target="_blank"&gt;ScriptingWife@hotmail.com&lt;/a&gt; if I can be of assistance. Have a scriptastic day.&lt;/p&gt;
&lt;p&gt;Thanks for a great blog post, Teresa, and for sharing your user group experience with the community.&lt;/p&gt;
&lt;p&gt;I invite you to follow me on &lt;a href="http://bit.ly/scriptingguystwitter" target="_blank"&gt;Twitter&lt;/a&gt; and &lt;a href="http://bit.ly/scriptingguysfacebook" target="_blank"&gt;Facebook&lt;/a&gt;. If you have any questions, send email to me at &lt;a href="mailto:scripter@microsoft.com" target="_blank"&gt;scripter@microsoft.com&lt;/a&gt;, or post your questions on the &lt;a href="http://bit.ly/scriptingforum" target="_blank"&gt;Official Scripting Guys Forum&lt;/a&gt;. See you tomorrow. Until then, peace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ed Wilson, Microsoft Scripting Guy&lt;/strong&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://blogs.technet.com/aggbug.aspx?PostID=3555130" width="1" height="1" alt="" /&gt;</description></item></channel></rss>