{"id":86010,"date":"2015-11-24T08:23:09","date_gmt":"2015-11-24T16:23:09","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/scripting\/?p=86010"},"modified":"2019-06-11T08:24:02","modified_gmt":"2019-06-11T16:24:02","slug":"automating-index-fragmentation-reports-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/automating-index-fragmentation-reports-2\/","title":{"rendered":"Automating Index Fragmentation Reports"},"content":{"rendered":"<p><b style=\"font-size:12px;\">Summary<\/b><span style=\"font-size:12px;\">: Guest blogger, Laerte Junior discusses how to use PowerShell to automate an index fragmentation report and generate an Excel file.<\/span><\/p>\n<p>One of the day-to-day tasks of a DBA is to maintain your environment. This task includes checking the fragmentation of indexes. In this post, I will show how to automate this collection and generate an Excel file.<\/p>\n<h2>Environment considerations<\/h2>\n<p>For this particular script, I am assuming that like me, you use a central &ldquo;collector&rdquo; machine. For that, you have installed SQL Server 2012 or later, Excel, and Windows PowerShell 4.0 or later. Yes! I will use some coding features that only work in Windows PowerShell 4.0 and later. So you are good to go if your checklist looks exactly like this one:<\/p>\n<ul>\n<li>Windows PowerShell 4.0 or later<\/li>\n<li><span style=\"font-size:12px;\">SQL Server 2012 or later<\/span><\/li>\n<li>Coffee and chocolate donuts<\/li>\n<li>WooHoo ! Watched the new <a href=\"https:\/\/www.youtube.com\/watch?v=sGbxmsDFVnE\" target=\"_blank\">Star Wars trailer<\/a><\/li>\n<\/ul>\n<h2>Coding considerations<\/h2>\n<p>Here are some things to consider about running this script:<\/p>\n<ul>\n<li><b>$PSItem<\/b> and <b>PipelineVariable<\/b> common parameter are being used. This is why you need PowerShell 4.0 or later. <b>$Psitem<\/b> is a new syntax to the <b>$_ <\/b>placeholder in Windows PowerShell&nbsp;3.0, and <b>PipelineVariable<\/b>an awesome new common parameter supported in Windows PowerShell&nbsp;4.0. For more information, see:\n<ul>\n<li><a href=\"http:\/\/blogs.msdn.com\/b\/powershell\/archive\/2012\/06\/14\/new-v3-language-features.aspx\" target=\"_blank\">New V3 Language Features<\/a><\/li>\n<li><a href=\"https:\/\/rkeithhill.wordpress.com\/2013\/07\/20\/powershell-v4-pipelinevariable-common-parameter\/\" target=\"_blank\">PowerShell V4 Pipeline Variable Common Parameter<\/a><\/li>\n<\/ul>\n<\/li>\n<li><b>Invoke-SQLCMD<\/b> is used. It is a cmdlet supported by the SQLPS provider. In early versions of SQL Server, SQLPS is not a module. In this code, I am importing it as a module, so that is why you need a central repository machine with SQL Server 2012 or later to collect the data.<\/li>\n<li>This script is used to automate the collection of the data, so it will be scheduled and called by the Windows Task Scheduler. This means that I need to log everything to check if something bad happened. I am using a Start\/Stop transcript for that operation.<\/li>\n<li>A list with the SQL Server instance names. The script is using a text file called <b>instancenames.txt<\/b>. It can be easily changed to query a table in the central repository with the all SQL Server instance names.<\/li>\n<li>If a SQL Server instance could not be connected, the script cannot stop. It needs to skip the instance, log, and flow the script to the next instance name. To perform this operation, I am using an&nbsp; error handle plan with <b>Try<\/b>&#8211;<b>Catch<\/b>&#8211;<b>Finally<\/b> and the <b>ErrorVariable<\/b> common parameter.<\/li>\n<li>I am not using SMO to retrieve the index fragmentation information. SMO has a known bug and I want to keep my code as simple as I can&mdash;not doing tons of conditions to check what version of SQL Server is to use SMO. For more information, see <a href=\"http:\/\/dbaduck.com\/2012\/07\/07\/smo-and-index-fragmentation\/\" target=\"_blank\">SMO and Index Fragmentation<\/a>.<\/li>\n<li>I am using T-SQL directly with <b>Invoke-SQLCMD<\/b> to gather the index fragmentation and SMO to connect and run into the databases.<\/li>\n<li>KISS&ndash;L (keep it simple, stupid Laerte). We are members of a team, and as a team, I need to remember that other people will maintain my code. There are very good best practices documented for coding in shared and corporate environments, but essentially I like to say, &ldquo;Use common sense.&rdquo;<\/li>\n<li>Tons of verbose and coding comments. Yes. Everything needs to be logged deeply and people need to understand what I did.<\/li>\n<li>Do not reinvent the wheel. Check the Windows PowerShell community channels and you will find a lot of very good functions, scripts, and ideas already posted by the top of the PowerShell heroes. Believe me, I live (virtually) with them. They are the best. Literally, the Council Jedi.<\/li>\n<\/ul>\n<h2>Coding flow<\/h2>\n<p>The idea of this script is to automate the report of index fragmentation. The control flow is:<\/p>\n<ul>\n<li>Run into the SQL Server instance names<\/li>\n<li>Connect to the instance<\/li>\n<li>Run into the databases<\/li>\n<li>Retrieve the index fragmentation to each table<\/li>\n<li>Export to CSV files by database<\/li>\n<li>Generate an Excel file with the databases from the instance as worksheets. The Excel name will have the name of the instance.<\/li>\n<\/ul>\n<p>To generate the Excel file from the CSV files, I am using the awesome function from my fellow MVP, Luc Dekens. Check it out: <a href=\"http:\/\/www.lucd.info\/2010\/05\/29\/beyond-export-csv-export-xls\/\" target=\"_blank\">Beyond Export-Csv: Export-Xls<\/a>.<\/p>\n<h2>Here&#8217;s the code<\/h2>\n<p><strong>Note<\/strong> &nbsp;You can download this code from GitHub:&nbsp;<a href=\"https:\/\/github.com\/LaerteJunior\/ScriptingGuysNov2015\" target=\"_blank\">LaerteJunior\/ScriptingGuysNov2015<\/a>.<\/p>\n<p>Let&#8217;s get deep into the code&#8230;<\/p>\n<p><strong>Check and configure the location of the script and initial configurations<\/strong><\/p>\n<p style=\"margin-left:30px;\">#getting the location of the script to create the log and instance directories.<\/p>\n<p style=\"margin-left:30px;\">#if error , need to stop the script<\/p>\n<p style=\"margin-left:30px;\">$scriptRoot = <b>Split-Path<\/b> <i>-Parent<\/i> $MyInvocation.MyCommand.Definition<\/p>\n<p style=\"margin-left:30px;\">$PSScriptRoot = $scriptRoot<\/p>\n<p style=\"margin-left:30px;\"><b>Set-Location<\/b> $PSScriptRoot<\/p>\n<ul>\n<li style=\"list-style-type:none;\">\n<ul>\n<li>Create the paths<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p style=\"margin-left:30px;\">try {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Creator = @{<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $True = { $null}<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $False = {$null = <b>New-Item<\/b> <i>-Path<\/i> $Path <i>-ItemType<\/i> Directory }<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Path = &#8220;$($PSScriptRoot)\\Log&#8221;<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp; $Creator[(<b>Test-Path<\/b> $Path)]<\/p>\n<p style=\"margin-left:30px;\">} catch {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw &#8220;Could not create the LOG directory&#8221;<\/p>\n<p style=\"margin-left:30px;\">}<\/p>\n<p><strong style=\"font-size:12px;\">Test to start the script<\/strong><\/p>\n<p style=\"margin-left:30px;\">#Trying to import SQLPS module. If could not, need to stop the script<\/p>\n<p style=\"margin-left:30px;\">try {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <b>import-module<\/b> SQLPS <i>-DisableNameChecking<\/i><\/p>\n<p style=\"margin-left:30px;\">} catch {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw &#8220;Could not import the SQLPS module&#8221;<\/p>\n<p style=\"margin-left:30px;\">}<\/p>\n<p style=\"margin-left:30px;\">#Check to SMO. If could not, need to stop the script<\/p>\n<p style=\"margin-left:30px;\">if ([Reflection.Assembly]::LoadWithPartialName(&#8220;Microsoft.SqlServer.SMO&#8221;) -eq $null -or ([System.Reflection.Assembly]::LoadWithPartialName(&#8220;Microsoft.SqlServer.ConnectionInfo&#8221;)&nbsp; -eq $null)) {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Throw &#8220;SMO not avaliable&#8221;<\/p>\n<p style=\"margin-left:30px;\">}<\/p>\n<p><strong>Define some variables<\/strong><\/p>\n<p style=\"margin-left:30px;\">#TSQL index fragmentation<\/p>\n<p style=\"margin-left:30px;\">$SQLIndex = &#8220;<\/p>\n<p style=\"margin-left:30px;\">SELECT object_name(IPS.object_id) AS [TableName],<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp; SI.name AS [IndexName],<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp; IPS.Index_type_desc,<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp; IPS.avg_fragmentation_in_percent<\/p>\n<p style=\"margin-left:30px;\">FROM sys.dm_db_index_physical_stats(db_id(), NULL, NULL, NULL , &#8216;DETAILED&#8217;) IPS<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp; JOIN sys.tables ST WITH (nolock) ON IPS.object_id = ST.object_id<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp; JOIN sys.indexes SI WITH (nolock) ON IPS.object_id = SI.object_id AND IPS.index_id = SI.index_id<\/p>\n<p style=\"margin-left:30px;\">WHERE ST.is_ms_shipped = 0 &#8220;#and IPS.page_count &gt; 1000&#8221;<\/p>\n<p style=\"margin-left:30px;\">#variable to use to store the instance CSV created. Will use to generate the Excel files.<\/p>\n<p style=\"margin-left:30px;\">$PathCSV = @()<\/p>\n<p style=\"margin-left:30px;\">#Variable to load the instance names<\/p>\n<p style=\"margin-left:30px;\">$InputInstances = &#8220;$($PSScriptRoot)\\InstanceNames.txt&#8221;<\/p>\n<p style=\"margin-left:30px;\">#Verbose preference to show evertything<\/p>\n<p style=\"margin-left:30px;\">$VerbosePreference = &#8216;Continue&#8217;<\/p>\n<p><strong style=\"font-size:12px;\">Load the instance names and check the connection<\/strong><\/p>\n<p style=\"margin-left:30px;\">Try {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Loading the Instance Names and storing in the InstanceName Variable by the awesome <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pipelinevariable common parameter<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <b>Get-Content<\/b> $InputInstances <i>-PipelineVariable<\/i> InstanceName <i>-ErrorAction<\/i> Stop&nbsp; |<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #foreach in the instances<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <b>ForEach-Object<\/b> {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <b>Write-Verbose<\/b> &#8220;Connecting instance $($InstanceName)&#8221;<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #clean the InstanceSkipped variable. It is stored in the write error to skip the instances <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; with error<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $InstanceSkipped.Clear()<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Connection = <b>new-object<\/b> (&#8220;Microsoft.SqlServer.Management.Common.ServerConnection&#8221;) $InstanceName&nbsp;<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Connection.Connect()<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <b>Write-Error<\/b>&nbsp; &#8220;Could not connect on instance $($InstanceName) . Error : Error $($_.Exception.Message)&#8221; <i>-ErrorVariable<\/i> InstanceSkipped<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #if the instance was not skipped by any error<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!($InstanceSkipped)) {<\/p>\n<p><strong>Define some variables and collect the data<\/strong><\/p>\n<p style=\"margin-left:30px;\">#replacing the &#8220;\\\\&#8221; by _ to create the paths and csv files<\/p>\n<p style=\"margin-left:30px;\">$InstanceNamePath = $InstanceName -replace &#8220;\\\\&#8221;,&#8221;_&#8221;<span style=\"font-size:12px;\">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<\/span><\/p>\n<p style=\"margin-left:30px;\">#acumulating the paths to the $pathCSV to use to generate the Excel file and<\/p>\n<p style=\"margin-left:30px;\"># storing the current path to the $path variable<\/p>\n<p style=\"margin-left:30px;\">$PathCSV += $Path = &#8220;$($PSScriptRoot)\\Instances\\$($InstanceNamePath)&#8221;<\/p>\n<p style=\"margin-left:30px;\">#removing the path and all inside it if it exits. I am not handling error here or checking if exists do remove, I dont need it<\/p>\n<p style=\"margin-left:30px;\">#if not exists and try to remove will generate error that will be supressed and if exists will be removed<\/p>\n<p style=\"margin-left:30px;\">Remove-Item -Recurse -Path $Path -Force -ErrorAction SilentlyContinue<\/p>\n<p style=\"margin-left:30px;\">New-Item -Path $Path -ItemType Directory -Force<\/p>\n<p style=\"margin-left:30px;\">#connecting to the Instance. At this point I know that the instance is online<\/p>\n<p style=\"margin-left:30px;\">#and storing the database enumeration to&nbsp; the DatabaseName Variable using the awesome<\/p>\n<p style=\"margin-left:30px;\">#pipelinevariable common parameter<\/p>\n<p style=\"margin-left:30px;\">$SQLServer = new-object (&#8220;Microsoft.SqlServer.Management.Smo.Server&#8221;)&nbsp; $Connection<\/p>\n<p style=\"margin-left:30px;\">$SQLServer.Databases&nbsp; |<\/p>\n<p style=\"margin-left:30px;\">Where-Object {!($PSItem.IsSystemObject)} -PipelineVariable DatabaseName |<\/p>\n<p style=\"margin-left:30px;\">foreach-object {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #running the TSQL and saving to a CSV<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke-sqlcmd -ServerInstance $InstanceName -Query $SQLIndex -Database $DatabaseName.name <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -verbose:$false |<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Select-Object &nbsp;&nbsp;&nbsp; @{N=&#8217;Table Name&#8217;;E={$_.TableName}},<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @{N=&#8217;Index Name&#8217;;E={$_.IndexName}},<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @{N=&#8217;Index Type&#8217;;E={$_.Index_type_desc}},<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @{N=&#8217;Fragmentation&#8217;;E={$_.avg_fragmentation_in_percent}} |<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Export-Csv &#8220;$($Path)\\$($DatabaseName.name).csv&#8221; -NoClobber -NoTypeInformation<\/p>\n<p><strong>Generate the Excel file<\/strong><\/p>\n<p style=\"margin-left:30px;\">try {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($PathCSV) {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $PathCSV |<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForEach-Object {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $PathToSave = &#8220;$($Psitem)\\$(($Psitem -split &#8216;\\\\&#8217;)[-1]).xlsx&#8221;<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dir &#8220;$($Psitem)\\*.csv&#8221; |<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForEach-Object {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $data = Import-Csv $Psitem.fullname<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Export-Xls $data $PathToSave -WorksheetName $Psitem.name -AppendWorksheet<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Verbose &#8220;Excel created for $($PathToSave)&#8221;<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-Error &#8220;Oh Boy..something bad happened. Error : Error $($_.Exception.Message)&#8221;<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<span style=\"font-size:12px;\">&nbsp; &nbsp;<\/span><\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"margin-left:30px;\">} catch {<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-Error &#8220;Oh Boy..something bad happened. Error : Error $($_.Exception.Message)&#8221;<\/p>\n<p style=\"margin-left:30px;\">}<\/p>\n<h2>Schedule and register the script<\/h2>\n<p>I am using scheduled jobs in Windows PowerShell&nbsp;3.0, so it just creates the trigger:<\/p>\n<p style=\"margin-left:30px;\">$trigger = New-JobTrigger -Daily -At 1am<\/p>\n<p style=\"margin-left:30px;\">Register the job in the Windows Task Scheduler by pointing to the .ps1 file:<\/p>\n<p style=\"margin-left:30px;\">Register-ScheduledJob -Name EnergyAnalysisJob -Trigger $trigger -FilePath &#8216;C:\\laerte\\scripting guys\\indexes.ps1&#8217;<\/p>\n<p>For more information, see <a href=\"http:\/\/blogs.msdn.com\/b\/powershell\/archive\/2012\/03\/19\/scheduling-background-jobs-in-windows-powershell-3-0.aspx\" target=\"_blank\">Scheduling Background Jobs in Windows PowerShell 3.0<\/a>.<\/p>\n<p>That is it. Thanks to my good friend, Ed Wilson, for allowing me to talk a little bit about my passion: automation!<\/p>\n<p>~Laerte<\/p>\n<p>Thanks, Laerte. Awesome post.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Guest blogger, Laerte Junior discusses how to use PowerShell to automate an index fragmentation report and generate an Excel file. One of the day-to-day tasks of a DBA is to maintain your environment. This task includes checking the fragmentation of indexes. In this post, I will show how to automate this collection and generate [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-86010","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting"],"acf":[],"blog_post_summary":"<p>Summary: Guest blogger, Laerte Junior discusses how to use PowerShell to automate an index fragmentation report and generate an Excel file. One of the day-to-day tasks of a DBA is to maintain your environment. This task includes checking the fragmentation of indexes. In this post, I will show how to automate this collection and generate [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/86010","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=86010"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/86010\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=86010"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=86010"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=86010"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}