{"id":933,"date":"2010-07-08T00:00:00","date_gmt":"2010-07-08T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/gathering-perfmon-data-with-powershell\/"},"modified":"2021-08-24T13:40:27","modified_gmt":"2021-08-24T13:40:27","slug":"gathering-perfmon-data-with-powershell","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/database-administration-sql-server\/gathering-perfmon-data-with-powershell\/","title":{"rendered":"Gathering Perfmon Data with Powershell"},"content":{"rendered":"<div id=\"pretty\">\n<p class=\"START\">I was reading an excellent article by <strong>Allen White\u00a0<\/strong>(<a href=\"http:\/\/twitter.com\/SQLRunr\">Twitter<\/a>|<a href=\"http:\/\/sqlblog.com\/blogs\/allen_white\/default.aspx\">Blog<\/a>) on <a href=\"http:\/\/sqlblog.com\/blogs\/allen_white\/archive\/2009\/10\/09\/performance-data-gathering.aspx\">Performance Data Gathering<\/a> (to which I give all the credit for inspiring this module), and that&#8217;s when a PowerShell apple fell on my head: &#8220;<em>Why not make a function that facilitates this?<\/em>&#8221; As a DBA, one of my almost-daily tasks is to capture and analyze Perfmon counters. You may wonder to yourself, &#8220;<em>but you can do that with the <strong>get-counter<\/strong> cmdlet in PowerShell 2.0.<\/em>&#8220;<\/p>\n<p>Yes you can, and it is very helpful. However, I need multiple counters, and the results displayed in line with all values separated by commas (which is usually used to facilitate insertion into SQL Server), and\u00a0that&#8217;s when <strong>get-counter<\/strong> gets a little trickier to use. I tried to think of an easy way to choose which counters you want, save this configuration for later use, and then insert the output data into a SQL Server table for further analysis. As a result of my tinkering, I believe I&#8217;ve got something pretty useful to share with you.<\/p>\n<p>Before I go on, I want to give a shout out to the people who helped me solve some issues I encountered; as always, my friend <strong>MVP Shay Levy<\/strong> (<a href=\"http:\/\/twitter.com\/ShayLevy\">Twitter<\/a>|<a href=\"http:\/\/blogs.microsoft.co.il\/blogs\/ScriptFanatic\/\">Blog<\/a>), and also <strong>MVP JVierra<\/strong> , <strong>Trevor Sullivan<\/strong> (<a href=\"http:\/\/twitter.com\/pcgeek86\">Twitter<\/a>|<a href=\"http:\/\/trevorsullivan.net\">Blog<\/a>), and <strong>Lauri Kotilainen<\/strong> (<a href=\"http:\/\/twitter.com\/rytmis\">Twitter<\/a>|<a href=\"http:\/\/blog.rytmis.net\/\">Blog<\/a>) . A special thank-you goes to <strong>MVP Pinal Dave <\/strong>(<a href=\"http:\/\/twitter.com\/pinaldave\">Twitter<\/a>|<a href=\"http:\/\/blog.sqlauthority.com\/\">Blog<\/a>), who invited me to be a guest blogger on <a href=\"http:\/\/blog.sqlauthority.com\/\">SQLAuthority.com<\/a>, and <strong>MVP Grant Fritchey<\/strong> (<a href=\"http:\/\/twitter.com\/GFritchey\">Twitter<\/a>|<a href=\"http:\/\/scarydba.wordpress.com\/\">Blog<\/a>) for the kind words on his blog.<\/p>\n<p>This article will cover how to use this new module in a variety of situations, with some clear and every-day examples to hopefully make everything obvious. To start with, I&#8217;ll walk you through how to find out more information on the various Perfmon counters, so that you can choose which ones you want to use, as well as how to save that configuration so that you can reuse it later (and on different servers). Once we&#8217;ve covered that, we&#8217;ll take a look at how to get the data collected, and two ways to store it once we&#8217;ve got it.<\/p>\n<h1>Performance Counters<\/h1>\n<p>A polished version of this whole module will be available in the next release of <a href=\"http:\/\/sqlpsx.codeplex.com\/\">SQLPSX &#8211; SQL Server PowerShell Extensions<\/a>. For now, you can download it from <a href=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-perfcounters.psm1\">the top of this article<\/a>, and I should point out that this module is a V1, so it might (and probably will) have some issues, and you can <a href=\"https:\/\/twitter.com\/laertesqldba?lang=en\">contact me anytime<\/a> if you need a hand. Alternatively, you can use the built-in help to see all of the parameters and some examples:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-Help Get-PerfCounterCategory -examples<\/pre>\n<p>All tests were done on two Hyper-V 64-bit Virtual Machines;\u00a0 a Windows 2008 Server R2 domain controller with SQL Server 2008 R2 (Obiwan), and a Windows 7 machine with SQL Server 2008 (Chewie). Before you get started, if you want to work with multiple servers, you need to enable the RemoteRegistry Service in the remote machines , as you can see :<\/p>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure1.gif\" alt=\"1081-figure1.gif\" width=\"629\" height=\"502\" \/><\/p>\n<p class=\"caption\">Figure 1.Ensuring the RemoteRegistry Service is active on the remote machines.<\/p>\n<p>For further reading on why this is necessary, I suggest you take a look at &#8220;<a href=\"https:\/\/blogs.msdn.com\/b\/bgroth\/archive\/2004\/10\/05\/238440.aspx\">Why run the RemoteRegistry Service?<\/a>&#8221; by Brian Groth.<\/p>\n<p class=\"note\"><strong>Top Tip:<\/strong> If you want to know which information (properties) are returned by a given functions, type: <strong>Function | get-member -membertype noteproperty.<\/strong> For example: <strong>Get-PerfCounterCategory<\/strong><strong> | <\/strong><strong>Get-Member<\/strong> <strong><em>-MemberType<\/em><\/strong> <strong>NoteProperty<\/strong><\/p>\n<h1>Finding the Information<\/h1>\n<p>The thing that most bothered me at the start of this project was that, for some counters in Perfmon, I knew their names but could not remember exactly which category they were in. I&#8217;ll give you a few examples. Let&#8217;s say you remember that <strong>Buffer Cache Hit Ratio<\/strong> is in one of the SQL Server categories, but which one? We know that it&#8217;s painful to look in IDE for the answer, so now it&#8217;s much easier; if you want to discover all the registered categories, you can use this command:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PerfCounterCategory<\/pre>\n<p>Alternatively, if you want to be more fine-grained and only discover the categories starting with &#8220;<em>SQLServer<\/em>&#8220;, ordering by Category Name, then use this command:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PerfCounterCategory -CategoryName \"SQLServer*\" | Sort-Object \r\nCategory_name | Format-list Machine_Name,Category_Name,Category_Type,\r\nCategory_Description <\/pre>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure2.gif\" alt=\"1081-figure2.gif\" width=\"630\" height=\"227\" \/><\/p>\n<p class=\"caption\">Figure 2. Results for the Get-PerfCounterCategory cmdlet.<\/p>\n<p>Each Performance Counter category has a number of instances, or it can have just a single instance. For example, with the Processor Counter, you can have one instance for each processor, and with Buffer Manager you have only a single instance. You can see the information for, as an example, all instances in the <strong>Processor<\/strong> category by typing:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PerfCounterCategory -CategoryName \"PROCESSOR*\" | Get-PerfCounterInstance\r\n| Sort-Object Category_name | Format-list Machine_Name,Category_Name,\r\nInstance_name <\/pre>\n<p>What&#8217;s that I hear you ask? Can you get all counters in all instances and categories? Yes, of course you can&#8230; and with some help information about each counter, too:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PerfCounterCategory | Get-PerfCounterInstance | Get-PerfCounterCounters\u00a0\r\n| Format-List Machine_Name,Category_Name,Counter_Name,Counter_Type,\r\nCounter_Help <\/pre>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure3.gif\" alt=\"1081-figure3.gif\" width=\"630\" height=\"263\" \/><\/p>\n<p class=\"caption\">Figure 3. All counters in all instances and categories, with information.<\/p>\n<p>How about if you want to see all the counters from Buffer Manager category? Just use:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PerfCounterCategory -CategoryName \"*Buffer Manager*\" | \r\nGet-PerfCounterInstance\u00a0| Get-PerfCounterCounters | Format-List \r\nMachine_Name,Category_Name,Counter_Name,Counter_Type,Counter_Help <\/pre>\n<p>And if I want to work with multiple servers? Simple, just pipe the servers names into the cmdlet:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\"Obiwan\", \"Chewie\"| Get-PerfCounterCategory -CategoryName \"*Buffer Manager*\" \r\n| Get-PerfCounterInstance\u00a0| Get-PerfCounterCounters | Format-List \r\nMachine_Name,Category_Name,Counter_Name,Counter_Type,Counter_Help <\/pre>\n<p>&#8230; Or use a flat text file with the servers&#8217; names inside it:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-content servers.txt | Get-PerfCounterCategory -CategoryName \r\n\"*Buffer Manager*\" | Get-PerfCounterInstance\u00a0| Get-PerfCounterCounters | \r\nFormat-List Machine_Name,Category_Name,Counter_Name,Counter_Type,Counter_Help<\/pre>\n<p>As you can see , we can perform the search for missing information in various ways, facilitating the process of selecting the appropriate counters .<\/p>\n<h1>Setting an XML Configure File<\/h1>\n<p>When I started writing this module, my big goal was that I should somehow be able to be mobile with the counters that I chose. That is, I should be able to save and then later use \u00a0the same configurations as easily within the original server as any another. After thinking about it, I decided that the gathering of data should start with reading an XML configuration file containing all the counters I&#8217;m interested in, and that I should have one file for memory counters, one for processor counters, and so on, to segment the data gathering .<\/p>\n<p>It seems like it might be a really complicated solution, especially when XML is involved, but thankfully it&#8217;s not too bad, as you&#8217;ll see in a moment. To start with, creating an XML file with all the counters from the <strong>Processor<\/strong> category and <strong>_Total<\/strong> instance is as simple as running:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PerfCounterCategory -CategoryName \"Processor*\" | Get-PerfCounterInstance\r\n -InstanceName \"_Total\" | Get-PerfCounterCounters | Save-ConfigPerfCounter\r\n -PathConfigFile c:\\temp\\TemplateProcessor.XML -NewFile <\/pre>\n<p>If you then look in your <em>C:\\temp<\/em> folder, an XML file called <strong>TemplateProcessor_MACHINENAME.XML<\/strong> will be there, ready to be used.<\/p>\n<div class=\"note\">\n<p class=\"note\"><strong>Top Tip<\/strong> To facilitate the ability to identify and use multiple servers in your data-gathering process, the name of the target machine is added to the name of both the output file and the XML config file.<\/p>\n<\/div>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-1081-figure4A.gif\" alt=\"1081-1081-figure4A.gif\" \/><\/p>\n<p class=\"caption\">Figure 4. Generating an XML file containing the Perfmon configuration<\/p>\n<p>As you can see, in this example I used the <strong>-NewFile<\/strong>switch parameter which, naturally, creates a new .XML file. Perhaps you&#8217;re wondering whether there are situations where I would <em>not<\/em> use this parameter? Let&#8217;s say we have a file specifying just the <strong>Buffer Cache Hit Ratio<\/strong> counter from the <strong>Buffer Manager<\/strong> category:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PerfCounterCategory -CategoryName \"*Buffer Manager*\" | \r\nGet-PerfCounterInstance | Get-PerfCounterCounters -CounterName \r\n\"*cache hit ratio\" | Save-ConfigPerfCounter -PathConfigFile \r\nc:\\temp\\TemplateBufferManager.XML -NewFile <\/pre>\n<p>However, now we need to add the <strong>Page Life Expectancy<\/strong> counter to the already-existing file, so we just omit the\u00a0 <strong>-NewFile<\/strong>\u00a0 parameter, and the selected counters will be added to the XML file, rather than overwriting it:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PerfCounterCategory -CategoryName \"*Buffer Manager*\" | \r\nGet-PerfCounterInstance | Get-PerfCounterCounters -CounterName \"page life*\" \r\n| Save-ConfigPerfCounter -PathConfigFile c:\\temp\\TemplateBufferManager.XML<\/pre>\n<p>To create the configuration file in such a way that multiple servers can use it, we just need to specify the desired machines&#8230;<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\"ObiWan\", \"Chewie\" |\u00a0Get-PerfCounterCategory -CategoryName \r\n\"*Buffer Manager*\" | Get-PerfCounterInstance | Get-PerfCounterCounters | \r\nSave-ConfigPerfCounter -PathConfigFile c:\\temp\\BufferManager.XML -NewFile <\/pre>\n<p>&#8230; and a separate file will be created <em>for each server<\/em>, using the name passed in the <strong>-PathConfigFile<\/strong> parameter \u00a0and adding the server name:<\/p>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure5.gif\" alt=\"1081-figure5.gif\" width=\"608\" height=\"214\" \/><\/p>\n<p class=\"caption\">Figure 5. Creating configuration files for multiple servers.<\/p>\n<h1>Gathering Data<\/h1>\n<p>With all that set up, the next step, starting to actually gather information, is a bit more complicated. Let&#8217;s take a look:<\/p>\n<p>To start with, the command below allows us to gather data using the counters defined in <em>C:\\temp\\TemplateBufferManager_Obiwan.XML<\/em> , starting the collection job on 05\/24\/2010 08:00:00 AM, ending it on 05\/30\/2010 22:00:00 PM, with an interval of 10 seconds\u00a0 between each data collection, and outputting the values to <em>C:\\temp\\ TemplateBufferManager.txt<\/em>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Set-CollectPerfCounter -DateTimeStart\u00a0\"05\/24\/2010 08:00:00\" -DateTimeEnd \r\n\"05\/30\/2010 22:00:00\" -Interval 10 -PathConfigFile \r\nc:\\temp\\TemplateBufferManager_Obiwan.XML\u00a0-PathOutputFile \r\nc:\\temp\\TemplateBufferManager.txt<\/pre>\n<p>When you run this command, you will notice that the PowerShell session will be locked; the function is in a loop to gather the data, and while this loop is running the session will be locked. Thankfully, we can resolve this by simply adding the <strong>-RunAsJob<\/strong>parameter, which tells PowerShell to perform this procedure asynchronously:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Set-CollectPerfCounter -DateTimeStart\u00a0\"05\/24\/2010 08:00:00\" -DateTimeEnd \r\n\"05\/30\/2010 22:00:00\" -Interval 10 -PathConfigFile \r\nc:\\temp\\TemplateBufferManager_Obiwan.XML\u00a0-PathOutputFile\r\nc:\\temp\\TemplateBufferManager.txt -RunAsJob<\/pre>\n<p>As you may have guessed, this parameter creates a Job, and when you&#8217;re working with Jobs there are some things you have to take into consideration: \u00a0 The job created will be called &#8220;PERFCOUNTERS_&#8221; plus the name of the XML file and the current time (YYYYMMDDHHMMSS). In the case of my example, the name will be: <strong>PERFCOUNTERS_TemplateBufferManager_OBIWAN_20100306193300.<\/strong><\/p>\n<p>Of course, if you&#8217;re working with Jobs, then you&#8217;ll want to see which jobs are running:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-job -state Running<\/pre>\n<p>To call the specific data-gathering Job, use ID or Name (which you have discovered using the command above):<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">get-job -name PERFCOUNTERS_TemplateBufferManager_OBIWAN_20100306193300 | \r\nformat-list<\/pre>\n<p>To see if the job is running without errors, run the <strong>Receive-Job<\/strong>\u00a0 cmdlet, and heed <strong>Marco Shaw&#8217;s<\/strong> (<a href=\"http:\/\/twitter.com\/MarcoShaw\">Twitter<\/a> | <a href=\"http:\/\/marcoshaw.blogspot.com\/\">Blog<\/a>) excellent advice:<\/p>\n<p class=\"INDENTED\">&#8220;<em>&#8230; when using <strong>receive-job,<\/strong> one may want to use the switch parameter <strong>-keep<\/strong>. Otherwise, any associated output is lost if <strong>receive-job<\/strong> is run again.<\/em>&#8220;<\/p>\n<p>With the <strong>-keep<\/strong> parameter, the output is retained on the screen when you next run the <strong>receive-job<\/strong> cmdlet. So, with that in mind, our investigative command is now:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">get-job -name PERFCOUNTERS_TemplateBufferManager_OBIWAN_20100306193300 | \r\nreceive-job -keep<\/pre>\n<p>Alternatively, if we want to see <em>all<\/em> jobs used by the PerfCounters Module, we just need to return all jobs starting with &#8220;<em>PERFCOUNTERS&#8230;<\/em>&#8220;, so we can use <strong>where-object<\/strong> to find what we need:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">get-job -State running | Where-Object {$_.name -like \"PerfCounters*\"} <\/pre>\n<p>And finally, if I want to stop the job before the date set in the <strong>Set-CollectPerfCounter <\/strong>command, I just need to type:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">stop-job -name PERFCOUNTERS_TemplateBufferManager_OBIWAN_20100306193300 \r\nor\r\nstop-job -id &lt;job id&gt; (The Job ID can be found using Get-Job)<\/pre>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure6.gif\" alt=\"1081-figure6.gif\" width=\"630\" height=\"461\" \/><\/p>\n<p class=\"caption\">Figure 6. Finding out what state the PerfCounter jobs are in.<\/p>\n<h1>Uploading Data to a SQL Server Table<\/h1>\n<p>We can do this in one of two ways; the first method is bulk inserting the .txt file, and the other is, when the data is being gathered, to save it directly into a SQL Server Table. Let&#8217;s take a closer look:<\/p>\n<h2>Bulk Inserting<\/h2>\n<p>After you&#8217;ve run your data-gathering job, you will see that the .txt file is ready to be inserted into SQL Server using a simple T-SQL bulk insert, and the <strong>Save-PerfCounterSQLTable<\/strong> function will help you do that. The command below will upload the output .txt file, and create a new table to receive the data (using <strong>-NewTable<\/strong> switch parameter):<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Save-PerfCounterSQLTable -ServerName Vader -DatabaseName Master\u00a0-NewTable\u00a0\r\n-PathConfigFile c:\\temp\\TemplateBufferManager_ObiWan.xml -PathOutputFile \r\nc:\\temp\\TemplateBufferManager.txt <\/pre>\n<p>Alternatively, if you want to upload the output .txt file into an existing Table, simply omit the <strong>-NewTable<\/strong> \u00a0switch parameter and pass the target table name in the <strong>-TableName<\/strong>parameter:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Save-PerfCounterSQLTable -ServerName Vader -DatabaseName Master -TableName \r\nPerfCounterSQLTable_20100528100655\u00a0-PathConfigFile\u00a0\r\nc:\\temp\\TemplateBufferManager.xml -PathOutputFile\u00a0\r\nc:\\temp\\TemplateBufferManager.txt <\/pre>\n<p>If you prefer to have a bit more control of your tables, it&#8217;s a simple matter to combine the two previously mentioned switches to upload the .txt file and create a new table to receive it, with a name chosen by you :<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Save-PerfCounterSQLTable -ServerName Vader -DatabaseName Master -TableName \r\nMyTableName -NewTable\u00a0-PathConfigFile c:\\temp\\TemplateBufferManager.xml\r\n-PathOutputFile c:\\temp\\TemplateBufferManager.txt <\/pre>\n<p>As you may have noticed, the <strong>PathConfigFile<\/strong>\u00a0 and <strong>PathOutputFile<\/strong> parameters, which contain the full paths of the XML configuration file and output file respectively, are required. If you&#8217;d like to learn more about the <strong>Save-PerfCounterSQLTable<\/strong> command, use :<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-Help Save-PerfCounterSQLTable -full<\/pre>\n<h2>Saving\u00a0 directly into SQL Server Table:<\/h2>\n<p>To best demonstrate this, let&#8217;s create a complete example. First, we choose the counters that we want to use. In case, this is the whole <strong>SQL Server Buffer Manager<\/strong> category on the Chewie and ObiWan machines, as well as the <strong>Processor<\/strong> category on Chewie. We save this configuration into <em>C:\\temp\\BufferManager.XML and c:\\temp\\Processor.XML<\/em><\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\"ObiWan\", \"Chewie\" |\u00a0Get-PerfCounterCategory -CategoryName \"*Buffer Manager*\"\r\n | Get-PerfCounterInstance | Get-PerfCounterCounters | Save-ConfigPerfCounter\r\n -PathConfigFile c:\\temp\\BufferManager.XML -NewFile \r\n\"Chewie\" |\u00a0Get-PerfCounterCategory -CategoryName \"Processor*\" | \r\nGet-PerfCounterInstance | Get-PerfCounterCounters | Save-ConfigPerfCounter \r\n-PathConfigFile c:\\temp\\Processor.XML -NewFile<\/pre>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure7.gif\" alt=\"1081-figure7.gif\" width=\"630\" height=\"254\" \/><\/p>\n<p class=\"caption\">Figure 7. The demo configuration files for Obiwan and Chewie.<\/p>\n<p>Now, with the XML configured, we can now start the gathering of data using background Jobs and saving their output directly into a SQL Server Table. We do not pass the target SQL Server table name as a parameter, so one table will be created for each server, using the naming format of <strong>PERFCOUNTERS_XMLFileName_YYYYmmDDhhMMss<\/strong>. Even though you&#8217;re using a SQL Table as a data repository, you <em>must<\/em> pass the path to an output file into your command, because the output file always will be created. Why, you ask? Let&#8217;s say you lose your connection to the SQL Server repository; this way, you don&#8217;t also lose the data, because it will also be stored in the .txt file. In this case, as we using several different XML files, we&#8217;ll only pass the target path, without the file name, and will be creating output files in this location using <strong>XMLNAME_MACHINENAME.TXT<\/strong> as a naming convention.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">dir \"c:\\temp\\*.Xml\" | Set-CollectPerfCounter\u00a0-DateTimeStart\u00a0\r\n\"05\/24\/2010 08:00:00\" -DateTimeEnd \"06\/30\/2010 22:00:00\" -Interval 10\u00a0\r\n-PathOutputFile c:\\temp\\ -ServerName ObiWan -DatabaseName Testes -NewTable \r\n-RunAsJob <\/pre>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure8.gif\" alt=\"1081-figure8.gif\" width=\"630\" height=\"395\" \/><\/p>\n<p class=\"caption\">Figure 8. Creating the jobs to gather data, and sending the collected data directly to a SQL Server table.<\/p>\n<p>As you can see from figure 8, three jobs are created, and their names all start with PERFCOUNTER, so you can use <strong>where-object<\/strong> to quickly and easily find all jobs used by the PerfCounters Module:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-Job -State Running | Where-Object { $_.name -like \"Perfcounter*\" } <\/pre>\n<p>Now, if we look in ObiWan&#8217;s SQL Server, we can see that there are three tables with the collected data: one for each machine we gathered data from (i.e. one for each XML file):<\/p>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure9.gif\" alt=\"1081-figure9.gif\" width=\"630\" height=\"397\" \/><\/p>\n<p class=\"caption\">Figure 9. Investigating the gathered data in SQL Server.<\/p>\n<p>&#8230; And the .txt files containing the same gathered output are created as well:<\/p>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure10.gif\" alt=\"1081-figure10.gif\" width=\"630\" height=\"274\" \/><\/p>\n<p class=\"caption\">Figure 10. The gathered data, stored in .txt files.<\/p>\n<p>When you&#8217;re setting this up, you can use your own table name to make things easy to find; I am passing the <strong>-TableName<\/strong> parameter with &#8220;<strong>BufferManager<\/strong>&#8220;, and so for each machine, a table called <strong>BufferManager_MACHINENAME<\/strong> will be created. In this case, <strong>BufferManager_Chewie<\/strong> and <strong>BufferManager_ObiWan<\/strong>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">dir \"c:\\temp\\BufferManager*.Xml\" | Set-CollectPerfCounter\u00a0-DateTimeStart\u00a0\r\n\"05\/24\/2010 08:00:00\" -DateTimeEnd \"06\/30\/2010 22:00:00\" -Interval 10\u00a0\r\n-PathOutputFile c:\\temp\\BufferManager.txt -ServerName ObiWan -DatabaseName \r\nTests -NewTable -RunAsJob -TableName \"BufferManager\" <\/pre>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1081-figure11.gif\" alt=\"1081-figure11.gif\" width=\"630\" height=\"486\" \/><\/p>\n<p class=\"caption\">Figure 11. Investigating the data stored in our custom-named tables.<\/p>\n<p>Perhaps you&#8217;re wondering why it&#8217;s so useful to be able to specify the target table name? Let&#8217;s say you stop the gathering, and want to continue on a completely different day, but outputting the data to the same table. Just Pass the <strong>-TableName<\/strong> parameter with the name of the original table, and don&#8217;t pass the <strong>-newtable<\/strong> switch parameter:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Set-CollectPerfCounter\u00a0-PathConfigFile c:\\Temp\\BufferManager_Chewie.XML \r\n-DateTimeStart\u00a0\"05\/24\/2010 08:00:00\" -DateTimeEnd \"06\/30\/2010 22:00:00\" \r\n-Interval 10\u00a0-PathOutputFile c:\\temp\\BufferManager.txt -ServerName ObiWan \r\n-DatabaseName Testes\u00a0-RunAsJob -TableName \"BufferManager_Chewie\" <\/pre>\n<p>Remember, in this case you have to explicitly declare the XML file and, in the case of the code snippet above, I will restart the data gathering to Chewie, with <em>C:\\temp\\BufferManager_Chewie.xml<\/em> as the configuration file, and the <strong>BufferManager_Chewie<\/strong> table as the SQL Server repository. The data is saved without creating a new table, and the output .txt file is always created as a data backup.<\/p>\n<p>In these examples I use Windows Authentication, but you can pass the Username and Password as parameters. If you get stuck at any point and want some more information, just type <strong>get-help &lt;FunctionName&gt;\u00a0 -examples<\/strong>.<\/p>\n<p>Well folks, I hope you can get some \u00a0good use out of this module, as I am. Once again, PowerShell wins.<\/p>\n<div class=\"note\">\n<p class=\"note\"><strong>Top Tip<\/strong><\/p>\n<p>When I was doing this article, I accidentally created 857 tables in SQL Server, and I had to drop them. Is that complicated? Not at all &#8211; here&#8217;s a hint:<\/p>\n<p><code>dir |% {$ _.drop ()}<\/code><\/p>\n<p>&#8230;where <code>%<\/code> is an alias for a foreach-object<strong>. <\/strong><\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>When you have to routinely collect  data from Performance Monitor Counters, it soon becomes easier and more convenient to use  PowerShell. SQL Server MVP Laerte Junior was inspired to create a script, and guides us through its useful functions.&hellip;<\/p>\n","protected":false},"author":221715,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143527],"tags":[4170,4364,4782,4206,5243,4635,4150,4151],"coauthors":[6819],"class_list":["post-933","post","type-post","status-publish","format-standard","hentry","category-database-administration-sql-server","tag-database-administration","tag-monitoring","tag-perfmon","tag-performance","tag-performance-monitor","tag-powershell","tag-sql","tag-sql-server"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/933","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221715"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=933"}],"version-history":[{"count":9,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/933\/revisions"}],"predecessor-version":[{"id":74511,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/933\/revisions\/74511"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=933"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=933"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=933"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=933"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}