&lt;?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Articles from November 2013 on PowerShell.org - Welcome Automaters!</title><link>https://powershell.org/articles/2013/11/</link><description>Recent content in Articles from November 2013 on PowerShell.org - Welcome Automaters!</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://powershell.org/articles/2013/11/index.xml" rel="self" type="application/rss+xml"/><item><title>Community Book of PowerShell Practices</title><link>https://powershell.org/articles/2013-11-14-community-book-of-powershell-practices/</link><guid>https://powershell.org/articles/2013-11-14-community-book-of-powershell-practices/</guid><pubDate>Thu, 14 Nov 2013 18:36:30 +0000</pubDate><description>&lt;p&gt;Released in our new Git repo: _The Community Book of PowerShell Practices, _an ongoing book started from this past Summer&amp;rsquo;s &amp;ldquo;Great Debates&amp;rdquo; blog post series. Grab it from https://github.com/PowerShellOrg/ebooks/blob/master/Practices/2013Sep_Practices/2013Sep_Practices.doc and enjoy!&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>Released in our new Git repo: _The Community Book of PowerShell Practices, _an ongoing book started from this past Summer&rsquo;s &ldquo;Great Debates&rdquo; blog post series. Grab it from https://github.com/PowerShellOrg/ebooks/blob/master/Practices/2013Sep_Practices/2013Sep_Practices.doc and enjoy!</p>
]]></content:encoded></item><item><title>Last chance for feedback on PowerShell course 10961A/B</title><link>https://powershell.org/articles/2013-11-14-last-chance-for-feedback-on-powershell-course-10961ab/</link><guid>https://powershell.org/articles/2013-11-14-last-chance-for-feedback-on-powershell-course-10961ab/</guid><pubDate>Thu, 14 Nov 2013 17:45:34 +0000</pubDate><description>&lt;p&gt;I&amp;rsquo;m in the midst of working on 10961C, the Windows Server 2012 R2 / Windows 8.1 / PowerShell 4.0 update of Microsoft&amp;rsquo;s 10961A/B course, &amp;ldquo;Automating Administration with Windows PowerShell.&amp;rdquo; I anticipate this being closed out by the end of November, 2013, so if you&amp;rsquo;ve taken or taught this course and have any feedback - even a typo - now&amp;rsquo;s the time to tell me. Drop a comment below, or e-mail me (if you have my address). Please, no Twitter replies on this one.&lt;br&gt;
The course will not be substantially changed from the B rev; because PowerShell v4 doesn&amp;rsquo;t &lt;em&gt;change&lt;/em&gt; much, especially at the entry-level covered by 10961, there wasn&amp;rsquo;t much to alter. But I&amp;rsquo;m trying to sweep up as many lingering bugs and typos as possible. Kudos to MCT Jason Yoder for firing over a list of fixes!&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>I&rsquo;m in the midst of working on 10961C, the Windows Server 2012 R2 / Windows 8.1 / PowerShell 4.0 update of Microsoft&rsquo;s 10961A/B course, &ldquo;Automating Administration with Windows PowerShell.&rdquo; I anticipate this being closed out by the end of November, 2013, so if you&rsquo;ve taken or taught this course and have any feedback - even a typo - now&rsquo;s the time to tell me. Drop a comment below, or e-mail me (if you have my address). Please, no Twitter replies on this one.<br>
The course will not be substantially changed from the B rev; because PowerShell v4 doesn&rsquo;t <em>change</em> much, especially at the entry-level covered by 10961, there wasn&rsquo;t much to alter. But I&rsquo;m trying to sweep up as many lingering bugs and typos as possible. Kudos to MCT Jason Yoder for firing over a list of fixes!</p><p>Some fun comments from the &ldquo;A&rdquo; rev feedback:</p><blockquote/><blockquote/><blockquote/><blockquote/><blockquote><pre><code> By day 3 (5 day class) most students felt over-whelmed.</code></pre></blockquote><blockquote/><blockquote/><blockquote/><blockquote/><blockquote><pre><code> There is not enough material.</code></pre></blockquote><blockquote/><blockquote/><blockquote/><blockquote/><blockquote/><blockquote/><blockquote/><pre><code> Probably won't be reconciling those two . Fact is, it's really tough to write the perfect course for *everyone*, which is why having a live instructor who knows the material is so important to a great class.
&gt;</code></pre><blockquote/><blockquote/><blockquote/><blockquote><p>No mention of filtering functions.</p></blockquote><blockquote/><blockquote/><blockquote/><pre><code> Because they're largely "leftovers" that were succeeded by pipeline functions. That said, 10961 isn't a programming course; that's where 55039 picks up. If you've got folks who want programming taking 10961, they were placed into the wrong class.</code></pre>]]></content:encoded></item><item><title>PhillyPoSH 11/07/2013 meeting summary and presentation materials</title><link>https://powershell.org/articles/2013-11-12-phillyposh-11072013-meeting-summary-and-presentation-materials/</link><guid>https://powershell.org/articles/2013-11-12-phillyposh-11072013-meeting-summary-and-presentation-materials/</guid><pubDate>Wed, 13 Nov 2013 02:07:36 +0000</pubDate><description>&lt;ol&gt;
&lt;li&gt;&lt;a href="http://mellositmusings.com/"&gt;John Mello&lt;/a&gt; gave a presentation on a script that searches a mailbox for an email by subject and downloads any attachments it may contain. A copy of his scripts can be obtained &lt;a href="http://mellositmusings.com/2013/10/29/powershell-script-to-download-attachments-from-an-email/"&gt;here.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.jasonhelmick.com/"&gt;Jason Helmick&lt;/a&gt;, Senior Technologist at &lt;a href="http://concentratedtech.com/"&gt;Concentrated Tech&lt;/a&gt; and &lt;a href="http://mvp.microsoft.com/en-us/mvp/Jason%20Helmick-5000354"&gt;Windows PowerShell MVP&lt;/a&gt;, gave a presentation on &amp;ldquo;Understanding the Pipeline &amp;ldquo;“ Getting your one-liners to work!&amp;rdquo; A copy of his script can be found &lt;a href="https://powershell.org/wp-content/uploads/2013/11/PhillyPosh_11_07_2013_Jason_Helmick.zip"&gt;here&lt;/a&gt;.
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=uVsMbxj6188"&gt;A recording of Jason Helmick&amp;rdquo;™s presentation&lt;/a&gt; can be found on our &lt;a href="http://www.youtube.com/channel/UCAc_ow5FIJtRpvew__9Iqzg"&gt;YouTube channel&lt;/a&gt;. Due to audio issues, John Mello&amp;quot;™s portion is not included in the recording.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Announcements
&lt;ol&gt;
&lt;li&gt;Tickets are still available for the &lt;a href="https://powershell.org/community-events/summit/powershell-summit-north-america/"&gt;2014 PowerShell Summit North America&lt;/a&gt;, if you&amp;quot;™re going then make sure to say hi to &lt;a href="http://paglia.org/"&gt;Lido Paglia&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;We are still trying to arrange for a PowerShell Saturday sometime in 2014, if you are interested in presenting please let us know!&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;We are assigning homework this week! Hopefully this will be a fun task that we can discuss during our next meeting, so try your hand at the following problem:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Title&lt;/strong&gt;: On This Day in Pictures&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<ol><li><a href="http://mellositmusings.com/">John Mello</a> gave a presentation on a script that searches a mailbox for an email by subject and downloads any attachments it may contain. A copy of his scripts can be obtained<a href="http://mellositmusings.com/2013/10/29/powershell-script-to-download-attachments-from-an-email/">here.</a></li><li><a href="http://www.jasonhelmick.com/">Jason Helmick</a>, Senior Technologist at<a href="http://concentratedtech.com/">Concentrated Tech</a> and <a href="http://mvp.microsoft.com/en-us/mvp/Jason%20Helmick-5000354">Windows PowerShell MVP</a>, gave a presentation on &ldquo;Understanding the Pipeline &ldquo;“ Getting your one-liners to work!&rdquo; A copy of his script can be found<a href="https://powershell.org/wp-content/uploads/2013/11/PhillyPosh_11_07_2013_Jason_Helmick.zip">here</a>.<ol><li><a href="https://www.youtube.com/watch?v=uVsMbxj6188">A recording of Jason Helmick&rdquo;™s presentation</a> can be found on our<a href="http://www.youtube.com/channel/UCAc_ow5FIJtRpvew__9Iqzg">YouTube channel</a>. Due to audio issues, John Mello"™s portion is not included in the recording.</li></ol></li><li>Announcements<ol><li>Tickets are still available for the<a href="https://powershell.org/community-events/summit/powershell-summit-north-america/">2014 PowerShell Summit North America</a>, if you"™re going then make sure to say hi to<a href="http://paglia.org/">Lido Paglia</a>!</li><li>We are still trying to arrange for a PowerShell Saturday sometime in 2014, if you are interested in presenting please let us know!</li></ol></li><li>We are assigning homework this week! Hopefully this will be a fun task that we can discuss during our next meeting, so try your hand at the following problem:</li></ol><p><strong>Title</strong>: On This Day in Pictures</p><p><strong>Description:</strong> You have folder of photos on your computer that you take with your Smartphone or digital camera. From time to time you want to be reminded of the cool and interesting things you snapped photos of years before on this day. Being a PowerShell scripter you imagine that PowerShell would be a quick and easy tool for exploring your photo"™s meta-data to re-discover some fun memories you had by emailing yourself some pictures you took on this same day last year or any year before. You decide to format the email as HTML including the pictures and some data about them. Finally, using the task scheduler to set your script to run every morning so you can take a trip down memory lane with your photos on &ldquo;this day in history&rdquo;. As a PowerShell scripter you roll up your sleeves and get to work.</p><p><strong>Requirements:</strong></p><ul><li><p>Your script should look into a directory that may contain sub folders for image files (you may want to support .jpg, .jpeg, .png, etc.).</p></li><li><p>The script should then determine the date a photo was taken. Examining the<a href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format">EXIF</a> meta-data might be handy.</p></li><li><p>Get the date the script runs and find all the photos taken on the same day other than the current year.</p></li><li><p> Finally send an email containing the photos taken on this day in history*</p></li></ul>
]]></content:encoded></item><item><title>Login now required for comments</title><link>https://powershell.org/articles/2013-11-11-login-now-required-for-comments/</link><guid>https://powershell.org/articles/2013-11-11-login-now-required-for-comments/</guid><pubDate>Mon, 11 Nov 2013 14:49:05 +0000</pubDate><description>&lt;p&gt;A quick note and an apology: I&amp;rsquo;ve had to modify the site configuration to require users to be registered and logged in before they can comment. We&amp;rsquo;ve been taking a &lt;em&gt;ridiculous&lt;/em&gt; amount of comment spam, and it&amp;rsquo;s consuming more and more time to weed through it.&lt;br&gt;
You can register using any major social media account, so you don&amp;rsquo;t have to remember yet another username and password with us, so hopefully that&amp;rsquo;ll mitigate the inconvenience.&lt;br&gt;
Have a great week!&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>A quick note and an apology: I&rsquo;ve had to modify the site configuration to require users to be registered and logged in before they can comment. We&rsquo;ve been taking a <em>ridiculous</em> amount of comment spam, and it&rsquo;s consuming more and more time to weed through it.<br>
You can register using any major social media account, so you don&rsquo;t have to remember yet another username and password with us, so hopefully that&rsquo;ll mitigate the inconvenience.<br>
Have a great week!</p>
]]></content:encoded></item><item><title>Monitoring SQL Server Backups</title><link>https://powershell.org/articles/2013-11-06-monitoring-sql-server-backups/</link><guid>https://powershell.org/articles/2013-11-06-monitoring-sql-server-backups/</guid><pubDate>Thu, 07 Nov 2013 07:30:31 +0000</pubDate><description>&lt;p&gt;One of the most important tasks for the** **DBAs is to ensure that there is a maintenance plan to recover data from a given disaster.
 
As a DBA we need to design a maintenance plan according to our scenario and business requirements. Do we want to be able to recover data at any point of time? How much data loss can we accept? All these questions and many more must be answered before designing the plan. In this post we will assume a basic daily full backup to keep our data safe, we will assume that there is a job performing full backups to our databases every day at midnight.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>One of the most important tasks for the** **DBAs is to ensure that there is a maintenance plan to recover data from a given disaster.
 
As a DBA we need to design a maintenance plan according to our scenario and business requirements. Do we want to be able to recover data at any point of time? How much data loss can we accept? All these questions and many more must be answered before designing the plan. In this post we will assume a basic daily full backup to keep our data safe, we will assume that there is a job performing full backups to our databases every day at midnight.</p><p>The next step after we have defined and implemented the maintenance plan is to monitor that all backups are being executed. In order to reach our goal it will be necessary to know whether a backup has been done or not and that could be possible by monitoring the backup job or querying the msdb database metadata among many other options. For this post we will use the second option, we will query msdb to check databases backup information. The main reason why we choose this option is because of the variability of backup maintenance plan definitions. The backup job is defined by every DBA and we cannot assume that all databases are included in the maintenance plan, on the other hand by querying msdb we will know for sure the databases which have been backed up and those that have not been backed up.</p><h1 id="" class="ps-heading"><a class="ps-heading-anchor" href="#" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>Querying msdb database</p><p>As it has been explained before querying msdb database will give us the truth about database backups. Running the following query we will know how many days have happened since the last full backup of every database:</p><p>Use</p><p>msdb
;</p><p> </p><p>with</p><p>backup_info</p><p>as</p><p>(</p><p>   </p><p>select</p><p>       
bck
.
database_name
,</p><p>       
bck
.
database_guid
,</p><p>       
bck
.
backup_start_date
,</p><p>       
bck
.
backup_finish_date
,</p><p>       
bckmf
.
physical_device_name
as
BackupFile_Path
,</p><h1 id="backuptype" class="ps-heading">       
BackupType<a class="ps-heading-anchor" href="#backuptype" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>       </p><p>case</p><p>           </p><h1 id="type" class="ps-heading">when
bck
.
[type]<a class="ps-heading-anchor" href="#type" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>&lsquo;I&rsquo;</p><p>then</p><p>&lsquo;Differential&rsquo;</p><p>           </p><p>when</p><p>type</p><p>=</p><p>&lsquo;D&rsquo;</p><p>then</p><p>&lsquo;Full&rsquo;</p><p>           </p><p>when</p><p>type</p><p>=</p><p>&lsquo;L&rsquo;</p><p>then</p><p>&lsquo;Log&rsquo;</p><p>           </p><p>else</p><p>&lsquo;Unknown&rsquo;</p><p>       </p><p>end</p><p>   </p><p>from
backupset
as
bck</p><p>   </p><p>inner</p><p>join
backupmediafamily
as
bckmf</p><p>       </p><h1 id="media_set_id" class="ps-heading">on
bck
.
media_set_id<a class="ps-heading-anchor" href="#media_set_id" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>bckmf
.
media_set_id</p><p>),</p><p>Last_Backups</p><p>as</p><p>(</p><p>     </p><p>select</p><ul><li/></ul><p>     </p><p>from</p><p>     </p><p>(</p><p>           </p><p>select</p><p>                 </p><p>ROW_NUMBER</p><p>()</p><p>over</p><p>(</p><p>PARTITION</p><p>BY
V
.
database_guid, V.BackupType 
order</p><p>by
V
.
backup_start_date
desc</p><p>)</p><p>as
r
,</p><p>                 </p><ul><li/></ul><p>           </p><p>from
backup_info
as
V</p><p>     </p><p>)</p><p>as
VV</p><p>     </p><h1 id="r" class="ps-heading">where
VV
.
r<a class="ps-heading-anchor" href="#r" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><h1 id="backuptype-1" class="ps-heading">1
and
VV
.
BackupType<a class="ps-heading-anchor" href="#backuptype-1" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>&lsquo;FULL&rsquo;</p><p>),</p><p>dbs</p><p>as</p><p>(</p><p>     </p><p>select</p><p>   
name
,
database_guid
,
state_desc</p><p>     </p><p>from</p><p>sys</p><p>.</p><p>databases</p><p>as
dbs</p><p>     </p><p>inner</p><p>join</p><p>sys</p><p>.</p><p>database_recovery_status</p><p>as
dbrs</p><p>           </p><h1 id="database_id" class="ps-heading">on
dbrs
.
database_id<a class="ps-heading-anchor" href="#database_id" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>dbs
.
database_id</p><p>)</p><p>select</p><p>   
name
,</p><p>   </p><p>case</p><p>when
V
.
database_name
is</p><p>null</p><p>then
365
else</p><p>DATEDIFF</p><p>(</p><p>day</p><p>,
backup_start_date
,</p><p>GETDATE</p><p>())</p><p>end</p><p>as
DaysSinceLastBackup</p><p>from</p><p>dbs</p><p>left</p><p>join
Last_Backups
as
V</p><p>   </p><h1 id="database_guid" class="ps-heading">on
V
.
database_guid<a class="ps-heading-anchor" href="#database_guid" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>dbs
.
database_guid</p><p>where</p><h1 id="state_desc" class="ps-heading">dbs
.
state_desc<a class="ps-heading-anchor" href="#state_desc" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>&lsquo;ONLINE&rsquo;</p><p>and
name
&lt;&gt;</p><p>&lsquo;TempDB&rsquo;</p><p>order</p><p>by
2
desc</p><p>;</p><p> </p><p>Notice that databases that never have been backed up will return 365 days as the number of days since the last full backup.</p><p>This query returns the desired information like follows:</p><p><a href="https://powershell.org/wp-content/uploads/2013/11/image.png"><img src="https://powershell.org/wp-content/uploads/2013/11/image_thumb.png" alt="image"/></p><p>In this case we can see a basic example with system databases with 0 days since last full backup, which means that all databases are up to date with full backups. Another possible result could be:</p><p><a href="https://powershell.org/wp-content/uploads/2013/11/image1.png"><img src="https://powershell.org/wp-content/uploads/2013/11/image_thumb1.png" alt="image"/></p><p>In this case databases last full backup was four days ago. This second example could be a reason to be alarmed because in case of a disaster we only can recover data until four days ago, all changes made during the last four days would be lost.</p><p>Notice that databases that never have been backed up will return 365 days as the number of days since the last full backup.</p><p>As it was shown before, the query could help us to monitor backups in a single instance but what happen when the DBA has to monitor and manage more than one instance? And what if those instances are from different SQL Server Versions? Things start to get complicated and doing it one by one manually is not an option! I"™m currently facing that situation; I"™m managing more than 80 SQL Server instances from different versions. Here is when PowerShell comes to help the DBA.</p><h1 id="" class="ps-heading"><a class="ps-heading-anchor" href="#" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>PowerShell Solution</p><p>With PowerShell we will be able to query all msdb databases from all the desired SQL Server instances. The solution will have two files:</p><p>              1. Xml file with Server information</p><p>a.
      </p><p>SQL Server instance, user name, password"¦</p><p>              2. PowerShell script</p><p>The idea is to run the query to msdb for every server registered in the xml file. For instance the XML file structure could like follows:</p><p><a href="https://powershell.org/wp-content/uploads/2013/11/image5.png"><img src="https://powershell.org/wp-content/uploads/2013/11/image_thumb5.png" alt="image"/></p><p>For this demonstration we only need to provide the instance name, the SQL Server user name and the password to connect. The reason why I"™m using SQL Server authentication is because not all my SQL Server instances are in the same domain so I need to be able to connect to all of them from a single point (where the script is running). Anyway the script can always be modified to connect with integrated authentication easily.</p><p>With the xml file ready the only thing missing is the script file which will read the xml file and execute the query for every server. The script looks like follows:</p><p>Param</p><p>(</p><p> 
[</p><p>int</p><p>]</p><p>$DaysSinceLastBackup</p><p>=-</p><p>1,</p><p> 
[</p><p>string</p><p>]</p><p>$serversPath</p><p>=</p><p>&ldquo;C:\tmp\Servers.xml&rdquo;</p><p> 
)</p><p> </p><p>Function</p><p>Get-SQLServer-DataTable</p><p>([</p><p>string</p><p>]</p><p>$conn</p><p>, [</p><p>string</p><p>]</p><p>$query</p><p>)</p><p> 
{</p><p>    </p><p>$SqlConnection</p><p>=</p><p>New-Object</p><p>System.Data.SqlClient.SqlConnection</p><p>;</p><p>    </p><p>$SqlConnection</p><p>.</p><p>ConnectionString</p><p>=</p><p>$conn</p><p>    </p><p>$SqlCmd</p><p>=</p><p>New-Object</p><p>System.Data.SqlClient.SqlCommand</p><p>;</p><p>    </p><p>$SqlCmd</p><p>.</p><p>CommandText</p><p>=</p><p>$query</p><p>;</p><p>    </p><p>$SqlCmd</p><p>.</p><p>Connection</p><p>=</p><p>$SqlConnection</p><p>;</p><p>    </p><p>$SqlAdapter</p><p>=</p><p>New-Object</p><p>System.Data.SqlClient.SqlDataAdapter</p><p>;</p><p>    </p><p>$SqlAdapter</p><p>.</p><p>SelectCommand</p><p>=</p><p>$SqlCmd</p><p>;</p><p>    </p><p>$DataTable</p><p>=</p><p>New-Object</p><p>System.Data.DataTable</p><p>;</p><p>    </p><p>$SqlAdapter</p><p>.</p><p>Fill</p><p>(</p><p>$DataTable</p><p>)</p><p>|</p><p>out</p><ul><li/></ul><p>Null;</p><p>    </p><p>$SqlConnection</p><p>.</p><p>Close</p><p>()</p><p>;</p><p>    </p><p>    </p><p>return</p><p>$DataTable</p><p>;</p><p>}</p><p> </p><p>Function</p><p>Get-SQLDatabaseBackupsInfo</p><p>([</p><p>string</p><p>]</p><p>$conn</p><p>)</p><p>{</p><p>     </p><p>$query</p><p>=</p><p>"</p><p>           </p><p>Use</p><p>msdb;</p><p>           </p><p>           </p><p>with</p><p>backup_info</p><p>           </p><p>as</p><p>           
(</p><p>                 </p><p>select</p><p>                       </p><p>bck.database_name</p><p>,</p><p>                       </p><p>bck.database_guid</p><p>,</p><p>                       </p><p>bck.backup_start_date</p><p>,</p><p>                       </p><p>bck.backup_finish_date</p><p>,</p><p>                       </p><p>bckmf.physical_device_name</p><p>as</p><p>BackupFile_Path</p><p>,</p><p>                       </p><p>BackupType</p><p>=</p><p>                       </p><p>case</p><p>                            </p><p>when</p><p>bck</p><p>.[</p><p>type</p><p>]</p><p>=</p><p>&lsquo;I&rsquo;</p><p>then</p><p>&lsquo;Differential&rsquo;</p><p>                            </p><p>when</p><p>type</p><p>=</p><p>&lsquo;D&rsquo;</p><p>then</p><p>&lsquo;Full&rsquo;</p><p>                            </p><p>when</p><p>type</p><p>=</p><p>&lsquo;L&rsquo;</p><p>then</p><p>&lsquo;Log&rsquo;</p><p>                            </p><p>else</p><p>&lsquo;Unknown&rsquo;</p><p>                       </p><p>end</p><p>                 </p><p>from</p><p>backupset</p><p>as</p><p>bck</p><p>                 </p><p>inner</p><p>join</p><p>backupmediafamily</p><p>as</p><p>bckmf</p><p>                       </p><p>on</p><p>bck.media_set_id</p><p>=</p><p>bckmf.media_set_id</p><p>           
),</p><p>Last_Backups</p><p>           </p><p>as</p><p>           
(</p><p>                 </p><p>select</p><ul><li/></ul><p>                 </p><p>from</p><p>                 
(</p><p>                       </p><p>select</p><p>                            </p><p>ROW_NUMBER</p><p>()</p><p>over</p><p>(</p><p>PARTITION </p><p>BY </p><p>V.database_guid, V.BackupType </p><p>order </p><p>by </p><p>V.backup_start_date </p><p>desc</p><p>)</p><p>as</p><p>r</p><p>,</p><p>                            </p><ul><li/></ul><p>                       </p><p>from </p><p>backup_info </p><p>as </p><p>V</p><p>                 
)</p><p>as </p><p>VV</p><p>                 </p><p>where </p><p>VV.r</p><p>=</p><p>1</p><p>and </p><p>VV.BackupType</p><p>=</p><p>&lsquo;FULL&rsquo;</p><p>           
),</p><p>dbs</p><p>           </p><p>as</p><p>           
(</p><p>                 </p><p>select</p><p>                 </p><p>name</p><p>,</p><p>database_guid</p><p>,</p><p>state_desc</p><p>                 </p><p>from </p><p>sys.databases </p><p>as </p><p>dbs</p><p>                 </p><p>inner </p><p>join </p><p>sys.database_recovery_status </p><p>as </p><p>dbrs</p><p>                       </p><p>on </p><p>dbrs.database_id</p><p>=</p><p>dbs.database_id</p><p>           </p><p>)</p><p>           </p><p>select</p><p>                 </p><p>@@</p><p>SERVERNAME </p><p>as </p><p>ServerName</p><p>,</p><p>                 </p><p>name</p><p>as</p><p>DbName</p><p>,</p><p>                 </p><p>case </p><p>when </p><p>V.database_name </p><p>is </p><p>null </p><p>then</p><p>365</p><p>else </p><p>DATEDIFF</p><p>(</p><p>day</p><p>,</p><p>backup_start_date</p><p>,</p><p>GETDATE</p><p>())</p><p>end </p><p>as </p><p>DaysSinceLastBackup</p><p>           </p><p>from </p><p>dbs</p><p>           </p><p>left </p><p>join </p><p>Last_Backups </p><p>as </p><p>V</p><p>                 </p><p>on </p><p>V.database_guid</p><p>=</p><p>dbs.database_guid</p><p>           </p><p>where </p><p>dbs.state_desc</p><p>=</p><p>&lsquo;ONLINE&rsquo; </p><p>and </p><p>name</p><p>&lt;&gt;</p><p>&lsquo;TempDB&rsquo;</p><p>           </p><p>order </p><p>by</p><p>2</p><p>desc;</p><p>                 
"</p><p>;</p><p>     </p><p>return </p><p>Get</p><ul><li/></ul><p>SQLServer</p><ul><li/></ul><p>DataTable </p><p>$conn </p><p>$query</p><p>;</p><p>}</p><p> </p><p>   </p><p> 
[</p><p>xml</p><p>]</p><p>$xml</p><p>=</p><p>Get-Content </p><p>$serversPath</p><p> </p><p>$xml</p><p>.</p><p>Servers</p><p>.</p><p>server</p><p>|</p><p>foreach</p><ul><li/></ul><p>object</p><p>{</p><p>   </p><p>$it</p><p>=</p><p>$_</p><p>;</p><p>   </p><p>$instance</p><p>=</p><p>$it</p><p>.</p><p>InstanceName</p><p>;</p><p>   </p><p>$user</p><p>=</p><p>$it</p><p>.</p><p>username</p><p>;</p><p>   </p><p>$pass</p><p>=</p><p>$it</p><p>.</p><p>password</p><p>;</p><p>   </p><p>   </p><p>$conn</p><p>=</p><p>&ldquo;Server = $instance; Database = master; User=$user;Password=$pass;&rdquo;</p><p>;</p><p>     </p><p>     </p><p>Get-SQLDatabaseBackupsInfo </p><p>$conn
|</p><p>where-object</p><p>{</p><p>$_</p><p>.</p><p>DaysSinceLastBackup </p><p>-gt </p><p>$DaysSinceLastBackup</p><p>}</p><p> </p><p>|</p><p> </p><p>select</p><p>ServerName</p><p>,</p><p>DbName</p><p>,</p><p>DaysSinceLastBackup</p><p>;</p><p> </p><p> </p><p>}</p><p>The script has two parameters:</p><p> 
        </p><p>**
DaysSinceLastBackup
**
: A threshold to filter result. The result will show all databases which latest full backups are older than the parameter value. The value by default is -1, a negative value that will make to show all results.</p><p> 
         </p><dl><dt>**</dt><dt>ServersPath</dt><dt>**</dt><dd>The path where the XML file with all servers is allocated.</dd></dl><p>So we can execute the script like follows:</p><p><a href="https://powershell.org/wp-content/uploads/2013/11/image6.png"><img src="https://powershell.org/wp-content/uploads/2013/11/image_thumb6.png" alt="image"/></p><p>The example shown before executes the script passing the two parameters, the first one is the xml file and the second one is the Threshold. In this case we have used the value 2, which means that the script will return all databases which latest full backups are older than 2 days. In this case only the database<strong>test</strong> matches the condition, the result shows 365 days since the last full backup which means that this database has never been backed up.</p><p>On the other hand, if we execute the script without parameters we will see the information of all databases, this is what it will look like :</p><p><a href="https://powershell.org/wp-content/uploads/2013/11/image7.png"><img src="https://powershell.org/wp-content/uploads/2013/11/image_thumb7.png" alt="image"/></p><h1 id="" class="ps-heading"><a class="ps-heading-anchor" href="#" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h1><p>Conclusion</p><p>As it has been shown during this post, is very easy to monitor SQL Server Backups over different servers in a very fast and efficient way by using PowerShell. Once we have this script we can implement a scheduled task and use it to generate HTML reports or alarms to notify the DBAs and System administrators about the databases backup status. Once again PowerShell comes up to save the day and make our working life easier.</p>
]]></content:encoded></item><item><title>Configuring a Desired State Configuration Client</title><link>https://powershell.org/articles/2013-11-06-configuring-a-desired-state-configuration-client/</link><guid>https://powershell.org/articles/2013-11-06-configuring-a-desired-state-configuration-client/</guid><pubDate>Wed, 06 Nov 2013 23:47:22 +0000</pubDate><description>&lt;p&gt;Once we have our pull server in place and we&amp;rsquo;re starting to create configurations, we need to set up our client nodes to be able to connect to the pull server and how we want the node to behave.&lt;/p&gt;
&lt;h2 id="the-high-points" class="ps-heading"&gt;The High Points&lt;a class="ps-heading-anchor" href="#the-high-points" aria-label="Link to this section" title="Link to this section"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://powershell.org/2013/10/02/building-a-desired-state-configuration-infrastructure/"&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://powershell.org/2013/10/03/building-a-desired-state-configuration-pull-server/"&gt;Configuring the Pull Server (REST version)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Creating Configurations (&lt;a href="https://powershell.org/2013/10/08/building-a-desired-state-configuration-configuration/"&gt;one of two&lt;/a&gt;, &lt;a href="https://powershell.org/2013/10/14/building-a-desired-state-configuration-configuration-part-2/"&gt;two of two&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Configuring Clients (this post)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://powershell.org/2014/03/13/building-desired-state-configuration-custom-resources/"&gt;Building Custom Resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Packaging Custom Resources&lt;/li&gt;
&lt;li&gt;Advanced Client Targeting&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="examining-the-local-configuration-manager" class="ps-heading"&gt;Examining the Local Configuration Manager&lt;a class="ps-heading-anchor" href="#examining-the-local-configuration-manager" aria-label="Link to this section" title="Link to this section"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;The Desired State Configuration agent included in Windows Management Framework 4 (or natively on Server 2012 R2 / Windows 8.1) is exposed through the Local Configuration Manager.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>Once we have our pull server in place and we&rsquo;re starting to create configurations, we need to set up our client nodes to be able to connect to the pull server and how we want the node to behave.</p><h2 id="the-high-points" class="ps-heading">The High Points<a class="ps-heading-anchor" href="#the-high-points" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><ul><li><a href="https://powershell.org/2013/10/02/building-a-desired-state-configuration-infrastructure/">Overview</a></li><li><a href="https://powershell.org/2013/10/03/building-a-desired-state-configuration-pull-server/">Configuring the Pull Server (REST version)</a></li><li>Creating Configurations (<a href="https://powershell.org/2013/10/08/building-a-desired-state-configuration-configuration/">one of two</a>,<a href="https://powershell.org/2013/10/14/building-a-desired-state-configuration-configuration-part-2/">two of two</a>)</li><li>Configuring Clients (this post)</li><li><a href="https://powershell.org/2014/03/13/building-desired-state-configuration-custom-resources/">Building Custom Resources</a></li><li>Packaging Custom Resources</li><li>Advanced Client Targeting</li></ul><h3 id="examining-the-local-configuration-manager" class="ps-heading">Examining the Local Configuration Manager<a class="ps-heading-anchor" href="#examining-the-local-configuration-manager" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h3><p>The Desired State Configuration agent included in Windows Management Framework 4 (or natively on Server 2012 R2 / Windows 8.1) is exposed through the Local Configuration Manager.</p><p><code>PS&gt; Get-DscLocalConfigurationManager AllowModuleOverwrite : False CertificateID : ConfigurationID : ConfigurationMode : ApplyAndMonitor ConfigurationModeFrequencyMins : 30 Credential : DownloadManagerCustomData : DownloadManagerName : RebootNodeIfNeeded : False RefreshFrequencyMins : 15 RefreshMode : PUSH PSComputerName :</code>This is where we can configure the behavior of DSC for a particular node.  So, how do we configure it?  With DSC of course!<br>
There is a configuration option LocalConfigurationManager that allows us to set values for the Local Configuration Manager.  A sample configuration looks something like this:</p><p><code>configuration LetsGetConfiguring { param ($NodeId, $PullServer) LocalConfigurationManager { AllowModuleOverwrite = 'True' ConfigurationID = $NodeId ConfigurationModeFrequencyMins = 60 ConfigurationMode = 'ApplyAndAutoCorrect' RebootNodeIfNeeded = 'True' RefreshMode = 'PULL' DownloadManagerName = 'WebDownloadManager' DownloadManagerCustomData = (@{ServerUrl = "https://$PullServer/psdscpullserver.svc"}) } }</code>While this configuration looks similar to other configurations we might create, we need to apply it with a different command - Set-DscLocalConfigurationManager.</p><p><code>LetsGetConfiguring -NodeId 71defb7f-232b-4213-b289-08c3d424e162 -PullServer pullserver.somedomain.com Set-DscLocalConfigurationManager -path LetsGetConfiguring</code>The Local Configuration Manager offers a number of options, which we&rsquo;ll examine.</p><h4 id="allowmoduleoverwrite" class="ps-heading">AllowModuleOverwrite<a class="ps-heading-anchor" href="#allowmoduleoverwrite" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>This one is pretty straight-forward and only impacts configurations where you are using a pull server.  If you allow module overwrite, newer versions of modules can replace existing modules.  If you don&rsquo;t enable this, you&rsquo;ll have to manually remove modules if you want a new copy to pull down.</p><h4 id="certificateid" class="ps-heading">CertificateID<a class="ps-heading-anchor" href="#certificateid" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>CertficateID is a thumbprint of a certificate in the machine certificate store that will be used to decrypt any secrets present in the configuration.  DSC allows PSCredential objects to be marshaled through a MOF file, but requires them (without explicit authorization) to be encrypted. (There is another option as well, if you use the ConfigurationData feature, you can also supply the path to a certificate file to use - I&rsquo;ll be blogging that scenario later when I cover some more advanced scenarios.)</p><h4 id="configurationid" class="ps-heading">ConfigurationID<a class="ps-heading-anchor" href="#configurationid" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>The ConfigurationID is a GUID which uniquely identifies what configuration a node should retrieve from a pull server.  If you haven&rsquo;t had to generate GUIDs before, a really easy way to do so is:</p><p><code>PS&gt; [guid]::NewGuid().Guid</code>#### ConfigurationMode</p><p>ConfigurationMode defines how the DSC client operates.  There are three valid values:</p><ul><li>Apply</li><li>ApplyAndMonitor</li><li>ApplyAndAutoCorrect</li></ul><p>(NOTE:  These descriptions of functionality are based on limited testing - the TechNet documentation is not up to date yet, but should be in the near future.)<br>
Apply will apply the configuration once and after a successful run is logged, it will stop attempting to apply configuration or checking the configuration.  ApplyAndMonitor will apply a configuration as in Apply, but will continue to validate that a node is configured as described.  No corrective action will take place if there is configuration drift.  Finally, ApplyAndAutoCorrect is what most of us think of when looking at DSC as a configuration management tool.  This setting applies a configuration and checks it regularly.  If configuration drift is detected, the configuration manager will attempt to return the machine to the<em>desired state</em> (see how I worked the product name in there..).</p><h4 id="configurationmodefrequencymins" class="ps-heading">ConfigurationModeFrequencyMins<a class="ps-heading-anchor" href="#configurationmodefrequencymins" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>This setting determines how frequently the configured method (the RefreshMode) will be run.  In the case of a pull server, this is how frequently the pull server will be checked for updated configurations.  The minimum value for this is 30.  This value needs to be a multiple of the RefreshFrequencyMins.  If it is not, the engine will treat it as if it was a multiple (rounded up).</p><h4 id="credential" class="ps-heading">Credential<a class="ps-heading-anchor" href="#credential" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>The Credential supplied can be used for accessing remote resources.</p><h4 id="downloadmanagercustomdata" class="ps-heading">DownloadManagerCustomData<a class="ps-heading-anchor" href="#downloadmanagercustomdata" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>DownloadManagerCustomData is a hashtable of values that is passed to the specified download manager.  In the case of a a pull server, the two possible keys are ServerUrl and AllowUnsecureConnection.</p><h4 id="downloadmanagername" class="ps-heading">DownloadManagerName<a class="ps-heading-anchor" href="#downloadmanagername" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>Here is where we specify which download manager to use.  DSC ships with two options, the WebDownloadManager (for the web-based pull server) and the DSCFileDownloadManager (for using an SMB share).</p><h4 id="rebootnodeifneeded" class="ps-heading">RebootNodeIfNeeded<a class="ps-heading-anchor" href="#rebootnodeifneeded" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>Here&rsquo;s another pretty self-explanatory setting.  DSC offers a method for resources to request a reboot.  If this setting is $true, then DSC will reboot the node when it is requested.  If it is set to $false, DSC will notify (via the verbose stream and the DSC log) that a reboot is required, but not actually reboot the node.</p><h4 id="refreshfrequencymins" class="ps-heading">RefreshFrequencyMins<a class="ps-heading-anchor" href="#refreshfrequencymins" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>The RefreshFrequencyMins setting determines how often DSC runs an integrity check against the cached configuration value (or if the check falls on the ConfigurationModeFrequencyMins interval against the pull server if one is configured).  The minimum value for this setting is 15 minutes.</p><h4 id="refreshmode" class="ps-heading">RefreshMode<a class="ps-heading-anchor" href="#refreshmode" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h4><p>RefreshMode is either PUSH or PULL.  If you set the RefreshMode to PULL, you&rsquo;ll need to configure a download manager (via DownloadManagerName).<br>
Next up, we&rsquo;ll look at how we can build custom resources.</p>
]]></content:encoded></item></channel></rss>