<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Operations Manager Cross-Group Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/omx/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/omx/feed.xml</link>
    <description>Tips and tricks from the Microsoft Operations Manager Cross-Group Team Members</description>
    <lastBuildDate>Tue, 16 Apr 2019 06:12:59 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>What is my App Pool Actually Doing?</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/what-is-my-app-pool-actually-doing</link>
      <pubDate>Fri, 09 Nov 2018 21:07:01 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/?p=515</guid>
      <description><![CDATA[Much ink (both physical and virtual) has been spent on configuring application pools in IIS.  I'm...]]></description>
      <content:encoded><![CDATA[Much ink (both physical and virtual) has been spent on configuring application pools in IIS.  I'm not going to attempt to surpass that wisdom on how application pools are configured and how they should be configured.  Probably the best, single source I'm personally aware of is Thomas Marquardt's blog.  <a href="https://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx" rel="noopener" target="_blank">https://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx</a>

However where I will make an attempt; is what an application pool is actually doing.  Over the years different versions of IIS, the .Net Framework, and the CLR have stored and used different configuration settings in different places.  They also have different default behaviors.  This has led me to attach debuggers to worker processes to get the running values of the thread pools in various attempts to determine what is actually going on.  Often somebody has made a change to aspnet.config, web.config, machine.config, or the registry and is confused that what they thought would happen isn't happening.  And not everybody is comfortable with attaching debuggers to running processes.

So I made a very primitive, simple tool that I hope can allow people to see what their application pools are actually doing.  It is a single ASPX page, in plain next.  No .DLL needed.  Nothing to install.  You can just copy the file into the web root of your application, hit it with a browser, and then delete the file.

I'm attaching the full ASPX page in the .ZIP file here: <a href="https://msdnshared.blob.core.windows.net/media/2018/11/W3WPDetails.zip">DOWNLOAD-ZIP-FILE</a>

Here is the bulk of the C# code if you want to look at it separately.

<code>// Get process information.

    System.Diagnostics.Process myProcess = System.Diagnostics.Process.GetCurrentProcess();

    Session["myProcessThreadCount"]   = myProcess.Threads.Count;
    Session["myProcessId"]            = myProcess.Id;
    Session["myProcessName"]          = myProcess.ProcessName;

// Get thread pool information.  ASPX didn't like declaring the variables as they were used in the methods.

    int maxWorkerThreads       = -1;
    int maxIOThreads           = -1;
    int minWorkerThreads       = -1;
    int minIOThreads           = -1;
    int availableWorkerThreads = -1;
    int availableIOThreads     = -1;

    System.Threading.ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIOThreads);
    System.Threading.ThreadPool.GetMinThreads(out minWorkerThreads, out minIOThreads);
    System.Threading.ThreadPool.GetAvailableThreads(out availableWorkerThreads, out availableIOThreads);
    int usedWorkerThreads = maxWorkerThreads - availableWorkerThreads;
    int usedIOThreads = maxIOThreads - availableIOThreads;

    Session["maxWorkerThreads"]       = maxWorkerThreads;
    Session["maxIOThreads"]           = maxIOThreads;
    Session["minWorkerThreads"]       = minWorkerThreads;
    Session["minIOThreads"]           = minIOThreads;
    Session["availableWorkerThreads"] = availableWorkerThreads;
    Session["availableIOThreads"]     = availableIOThreads;
    Session["usedWorkerThreads"]      = usedWorkerThreads;
    Session["usedIOThreads"]          = usedIOThreads;

// Get HttpRuntime information

    Session["machConfDir"]     = System.Web.HttpRuntime.MachineConfigurationDirectory;
    Session["targetFramework"] = System.Web.HttpRuntime.TargetFramework;
    Session["appDomainAppId"]  = System.Web.HttpRuntime.AppDomainAppId;
    Session["appDomainId"]     = System.Web.HttpRuntime.AppDomainId;
    Session["iisVersion"]  = System.Web.HttpRuntime.IISVersion;

// Get Configuration Runtime Information

    System.Configuration.Configuration myWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
    System.Object preCast = myWebConfig.GetSection("system.web/httpRuntime");    
    System.Web.Configuration.HttpRuntimeSection myHttpRuntime = preCast as System.Web.Configuration.HttpRuntimeSection;

    Session["AppReqQueueLim"]      = myHttpRuntime.AppRequestQueueLimit;
    Session["minFreeThreads"]      = myHttpRuntime.MinFreeThreads;
    Session["minLocalFreeThreads"] = myHttpRuntime.MinLocalRequestFreeThreads;</code>]]></content:encoded>
    </item>
    <item>
      <title>Orphaned Service Broker Queues in the SCOM Database</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/orphaned-service-broker-queues-in-the-scom-database</link>
      <pubDate>Sat, 14 Apr 2018 00:43:59 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/?p=495</guid>
      <description><![CDATA[We recently ran into an issue where our Operations Manager database was full. But the on-call...]]></description>
      <content:encoded><![CDATA[We recently ran into an issue where our Operations Manager database was full. But the on-call engineer couldn't figure out why. He ran the "Disk Usage By Top Tables" report in SQL Server Management Studio. But the top tables didn't add up to the used space in the database. The missing free space was in SQL Service Broker Queues, and the problem is that a SCOM management server creates a fresh service broker queue every time the SDK service starts. This leads to abandoned service broker queues in the Operations Manager database that build up over time.

<em>NOTE: System Center Service Manager (SCSM) does the same thing.</em>

<a href="https://msdnshared.blob.core.windows.net/media/2018/04/Queues.png"><img width="279" height="300" class="alignnone size-medium wp-image-505" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/04/Queues-279x300.png" /></a>

The first four numbers are the IP address of the management server that created the queue. And the next number is the process ID of the SDK process on that management server. At any given time, only one service broker queue is in use by each management server. So if you have more than one management server, there will be more than one queue in use at a time.

To see if we have a database space problem caused by service broker queues, run the following TSQL query against the Operations Manager database:

<code>SELECT
[a].used_pages, [s].name AS [SchemaName], [o].name AS [ObjectName], [o].type_desc
FROM sys.allocation_units [a]
JOIN sys.partitions [p] ON [a].container_id = [p].partition_id
JOIN sys.objects [o] ON [o].object_id = [p].object_id
JOIN sys.schemas [s] ON [s].schema_id = [o].schema_id
ORDER BY used_pages DESC</code>

Check if you see any of the following SYSTEM_TABLE values near the top.
<ul>
 	<li>sys.sysdercv</li>
 	<li>sys.sysdesend</li>
 	<li>sys.sysconvgroup</li>
</ul>
You can read more about those here: <a href="https://msdn.microsoft.com/en-us/library/ms179503.aspx">https://msdn.microsoft.com/en-us/library/ms179503.aspx</a>

Those indicate that service broker queues are some of the top users of space in the database. There may also be individual queues that are very large. Those will show up as INTERNAL_TABLE type and will be named something like queue_messages_448173538.

<em>NOTE: The cleanup may take hours or even days. I had to end about 20 million conversations and had to leave the cleanup running overnight.</em>

<strong>STEP 1 - Clean the Service Queues</strong>

Run this query to see which queues have the most conversations in them. If one of the largest is active, meaning the IP address and Process ID match the SDK service on an active management server, you can simple reboot the management server. The SDK service will abandon the old service broker queue and start a new one.

<code>SELECT
SCHEMA_NAME(q.schema_id) AS SchemaName
,q.name AS QueueName
,p.rows AS QueueRows
,q.modify_date
FROM sys.service_queues AS q
JOIN sys.objects AS o ON
o.object_id = q.object_id
JOIN sys.objects AS i ON
i.parent_object_id = q.object_id
JOIN sys.partitions p ON
p.object_id = i.object_id
AND p.index_id IN(0,1)
ORDER BY p.rows DESC</code>

To run a cleanup, substitute the name of the queue you want to clean into the SQL query below. Also update the <strong>while(@a</strong> line to however many conversations you want ended per pass. You can make it as large as the number of rows in the queue from the above query if you want to do it all at once.

<code>declare @c uniqueidentifier
declare @a int
SET @a = 1
while(@a &lt; 10000)
begin
SET @c = (select top 1 conversation_handle from dbo.Queue_mid10_223_23_219_pid1700_adid2_r630771674)
end conversation @c with cleanup
SET @a = @a + 1
end</code>

<strong>STEP 2 - Clean the Conversation Endpoints</strong>

Use the following command to see which services have the most conversation endpoints.  If one of the largest is active, meaning the IP address and Process ID match the SDK service on an active management server, you can simple reboot the management server. The SDK service will abandon the old service broker queue and start a new one.

<code>select far_service, COUNT(*) from sys.conversation_endpoints
group by far_service ORDER BY COUNT(*) DESC</code>

To run a cleanup, substitute the name of the service you want to clean into the SQL query below. Also update the <strong>while(@a</strong> line to however many conversations you want ended per pass. You can make it as large as the number of rows in the queue from the above query if you want to do it all at once.

<code>declare @c uniqueidentifier
declare @a int
SET @a = 1
while(@a &lt; 10000)
begin
    SET @c = (select top 1 conversation_handle from sys.conversation_endpoints WHERE far_service = &#039;Service_mid10_223_23_219_pid5644_adid2_r633159110&#039;)
    end conversation @c with cleanup
       SET @a = @a + 1
end</code>

<strong>STEP 3 - Clean the Services and Queues</strong>

This is the only part you can do with the SQL Server Management Studio user interface.  You can also use the TSQL commands

<code>DROP SERVICE</code> <a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-service-transact-sql">https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-service-transact-sql</a>
and
<code>DROP QUEUE</code> <a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-queue-transact-sql">https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-queue-transact-sql</a>

<em>NOTE: You cannot drop a queue until you drop the service first.  As with everything else, they are named with the IP address and process ID's of the SDK services on the management servers.</em>]]></content:encoded>
    </item>
    <item>
      <title>Replacement Azure Management Certificate Monitoring</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/replacement-azure-management-certificate-monitoring</link>
      <pubDate>Wed, 24 Jan 2018 19:25:38 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/?p=475</guid>
      <description><![CDATA[We replaced one of the monitors for Azure Management Certificates, and I had a few requests to share...]]></description>
      <content:encoded><![CDATA[We replaced one of the monitors for Azure Management Certificates, and I had a few requests to share it with the public.

We disabled this monitor:
 - Management Pack: Microsoft.SystemCenter.WindowsAzure
 - Monitor System Name: Microsoft.SystemCenter.WindowsAzure.Subscription.Certificate.Monitor
 - Monitor Display Name: Windows Azure Subscription Certificate Expiration Monitor
 - Monitor Description: Windows Azure Subscription Certificate Expiration Monitor
 - Alert Title: Management Certificates will expire soon

We didn't like that monitor for several reasons.  First, it doesn't say which certificates.  It just lets you know that one or more are expired or expiring.  And it doesn't give us a way to filter out known certificates that we don't want to monitor.  For example, we had a large number of self-signed certs "CN=Windows Azure Tools" which did not need to be monitored.

So we created a very simple, replacement management pack, which I'm attaching to this post.  It has one class, one relationship, one discovery, one monitor type (two alerts, one at 30 days and one at 7 days), and overrides the previously mentioned monitor.

The new class, Microsoft.SystemCenter.WindowsAzure.ManagementCertificate, has a separate instance for each certificate for each Azure subscription.  So you can get separate alerts for separate certificates.  Also, since the discovery is in PowerShell, in an unsealed MP, you can easily edit the logic to exclude certificates you don't want.  Here's what we did:

<code>  If ( $myCert.Subject -ne 'CN=Windows Azure Tools' )
  {

    $myTimeSpan = New-TimeSpan $(Get-Date) $myCert.NotAfter
    $DaysRemaining =  $myTimeSpan.Days

    $sInst = $discoveryData.CreateClassInstance("$MPElement[Name='Microsoft.SystemCenter.WindowsAzure.ManagementCertificate']$")</code>

Obviously this is not an officially supported MP, so use at your own risk.

Download the Management Pack here: <a href="https://msdnshared.blob.core.windows.net/media/2018/01/ManagementCertificates.zip">ManagementCertificates</a>
]]></content:encoded>
    </item>
    <item>
      <title>NetBIOS Domain Name Incorrect in SCOM 2016</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/netbios-domain-name-incorrect-in-scom-2016</link>
      <pubDate>Thu, 03 Aug 2017 23:46:11 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/?p=455</guid>
      <description><![CDATA[I noticed this when we upgraded to SCOM 2016.  After we applied UR3 the issue still persisted.  The...]]></description>
      <content:encoded><![CDATA[I noticed this when we upgraded to SCOM 2016.  After we applied UR3 the issue still persisted.  The NetBIOS Domain Name property of the Windows Computer class was not correct.  You can see this through the UI or by querying the database.
<pre>SELECT PrincipalName, DomainDnsName, ForestDnsName, NetbiosDomainName FROM OperationsManager.dbo.MTV_Computer</pre>
Correct:
<table width="100%">
<thead>
<tr>
<th>PrincipalName</th>
<th>DomainDnsName</th>
<th>ForestDnsName</th>
<th>NetbiosDomainName</th>
</tr>
</thead>
<tbody>
<tr>
<td>ComputerABC.redmond.corp.microsoft.com</td>
<td>redmond.corp.microsoft.com</td>
<td>corp.microsoft.com</td>
<td>REDMOND</td>
</tr>
</tbody>
</table>
<P>
Incorrect:
<table width="100%">
<thead>
<tr>
<th>PrincipalName</th>
<th>DomainDnsName</th>
<th>ForestDnsName</th>
<th>NetbiosDomainName</th>
</tr>
</thead>
<tbody>
<tr>
<td>ComputerABC.redmond.corp.microsoft.com</td>
<td>redmond.corp.microsoft.com</td>
<td>corp.microsoft.com</td>
<td>redmond.corp.microsoft.com</td>
</tr>
</tbody>
</table>
<P>
The issue appears here
<ul>
 	<li>Data Source: Microsoft.SystemCenter.WindowsComputerPropertyDiscovery</li>
 	<li>Discovery: Microsoft.SystemCenter.DiscoverWindowsComputerProperties</li>
 	<li>Management Pack: Microsoft.SystemCenter.Internal</li>
</ul>
I checked versions 7.0.8433.0 and 6.1.7221.0 (Yes, I keep copies of the SCOM 2007 R2 Management Packs) and they both use a JScript called DiscoverWindowsComputerProperties.js which correctly identifies the NetBIOS Domain Name.

I found that later versions 7.0.8437.0 and 7.0.8437.7 of the management pack had switched to a PowerShell script called DiscoverWindowsComputerProperties.ps1 which incorrectly returns the Domain property of the Win32_ComputerSystem class in WMI as the NetBIOS domain name.

While I am hopeful that this issue will be corrected in future Update Rollup, I have created a management pack that disables the PowerShell discovery and replaces it with the JScript discovery from version 7.0.8433.0 of the management pack.  I am attaching the unsealed management pack to this post which you may use or evaluate if you so choose.  This management pack is not officially supported or endorsed by Microsoft, so use at your own risk.
<pre>Link to download management pack: <a href="https://msdnshared.blob.core.windows.net/media/2017/08/UnsealedMP.zip">UnsealedMP</a></pre>]]></content:encoded>
    </item>
    <item>
      <title>Doing "Math" on Performance Counters in SCOM</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/doing-math-on-performance-counters-in-scom</link>
      <pubDate>Thu, 22 Oct 2015 12:27:29 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/2015/10/22/doing-math-on-performance-counters-in-scom/</guid>
      <description><![CDATA[If you look at the dashboard of a car, most of the instruments have&nbsp;obvious good and bad values...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size:small;">If you look at the dashboard of a car, most of the instruments have&nbsp;obvious <em>good</em> and <em>bad</em> values without requiring the driver to need additional information.&nbsp; Ideally performance counters would be this way, but this isn&#39;t always the case.&nbsp; Here are some real world examples I&#39;ve encountered where the data provided by the performance counter by itself wasn&#39;t enough to make a value judgment.</span></p>
<ul>
<li><span style="font-size:small;">Is the number of 404&#39;s per second on a web server excessive?</span>
<ul>
<li>I need to know that as a percentage of the total method requests per second</li>
</ul>
</li>
<li><span style="font-size:small;">Is a network adapter saturated?<br /></span>
<ul>
<li>I&nbsp;need to convert the Bytes/sec performance counters into Bits/sec and then divide by the bandwidth.</li>
</ul>
</li>
<li><span style="font-size:small;">Is a single process using too much CPU time on a server?<br /></span>
<ul>
<li>I need to divide the Process\% Processor Time counter by the number of logical cores in the machine (assuming the process is multi-threaded)</li>
</ul>
</li>
<li><span style="font-size:small;">Is a single process using too much memory on a server?<br /></span>
<ul>
<li>I need to divide the working set of the process into the server&#39;s physical memory</li>
</ul>
</li>
<li><span style="font-size:small;">Is the non-paged pool approaching its limit?<br /></span>
<ul>
<li>Okay, I&#39;m dating myself to Windows 2003 here, but you get the idea.</li>
</ul>
</li>
</ul>
<p><span style="font-size:small;">So how do we deal with a situation where we need to monitor the health of a performance counter, but the information provided by that performance counter is not independently adequate to make a judgment?</span></p>
<p><span style="font-size:small;">In my Library MP I am providing</span></p>
<p><span style="font-size:small;text-decoration:underline;"><strong>Two Probe Actions</strong></span></p>
<ol>
<li><span style="font-size:small;">Microsoft.PerfCounter.Two.Counters.Probe - This probe runs a PowerShell script that queries two performance counters and returns their values in a Property Bag.</span></li>
<li><span style="font-size:small;">Microsoft.PerfCounter.Create.PerfData.Probe - This probe runs a PowerShell script that divides two numbers, and multiplies the result by a third.&nbsp; If any of the inputs are 0.0, it will return 0.0 without risking division by zero.</span></li>
</ol>
<p><span style="font-size:small;text-decoration:underline;"><strong>Two Data Sources</strong></span></p>
<ol>
<li><span style="font-size:small;">Microsoft.PerfCounter.One.Counter.Plus.Denominator.Perf.DS&nbsp;- This data source uses System.Performance.DataProvider from the System.Performance.Library to sample a single performance counter.&nbsp; The results are then passed to&nbsp;Microsoft.PerfCounter.Create.PerfData.Probe.</span></li>
<li><span style="font-size:small;">Microsoft.PerfCounter.Two.Counters.Perf.DS&nbsp;- This data source uses a PowerShell script to query two performance counters.&nbsp; The results are then passed to&nbsp;Microsoft.PerfCounter.Create.PerfData.Probe.</span></li>
</ol>
<p><span style="font-size:small;text-decoration:underline;"><strong>Six Monitor Types</strong></span></p>
<ol>
<li><span style="font-size:small;">Microsoft.PerfCounter.Math.One.AverageThreshold.MonitorType</span></li>
<li><span style="font-size:small;">Microsoft.PerfCounter.Math.One.ConsecutiveThreshold.MonitorType</span></li>
<li><span style="font-size:small;">Microsoft.PerfCounter.Math.One.SimpleThreshold.MonitorType</span></li>
<li><span style="font-size:small;">Microsoft.PerfCounter.Math.Two.AverageThreshold.MonitorType</span></li>
<li><span style="font-size:small;">Microsoft.PerfCounter.Math.Two.ConsecutiveThreshold.MonitorType</span></li>
<li><span style="font-size:small;">Microsoft.PerfCounter.Math.Two.SimpleThreshold.MonitorType</span></li>
</ol>
<p><span style="font-size:small;">The monitor types are deliberately designed to closely match some types you will find in System.Performance.Library.</span></p>
<ol>
<li><span style="font-size:small;">System.Performance.AverageThreshold</span></li>
<li><span style="font-size:small;">System.Performance.ConsecutiveSamplesThreshold</span></li>
<li><span style="font-size:small;">System.Performance.ThresholdMonitorType</span></li>
</ol>
<p><span style="font-size:small;"><span style="color:#ff0000;text-decoration:underline;"><strong>CAUTION!</strong></span> - There are&nbsp;several things you should be aware of before using this Library.</span></p>
<ol>
<li><span style="font-size:small;">Using either of the data sources will result in a PowerShell script being run that &quot;does math.&quot;&nbsp; Having a SCOM agent run a few scripts at a slow interval should not cause any problems.&nbsp; But if you use a very short sampling interval and/or query a large number of performance counters you do risk impacting agent performance.</span></li>
<li><span style="font-size:small;">For sampling non-instantaneous type of performance counters Microsoft.PerfCounter.Two.Counters.Probe will sleep for three seconds to get two samples.&nbsp; As with Caution #1, running a large number of scripts can impact the agent.&nbsp; In addition to this, the data is only accurate during the three second window that the samples were taken.&nbsp; If your performance counter has large, brief spikes they might get missed.</span></li>
<li><span style="font-size:small;">I do not allow you to use the &quot;All Instances&quot; feature of System.Performance.DataProvider and I do not allow the two counter probe to query all instances of a counter.</span></li>
</ol>
<p><span style="font-size:small;">So what are some real-world examples of how this can be both safe and useful?&nbsp; For your convenience I have included an example MP that implements these examples.&nbsp; I have also included both sealed and unsealed copies of the Library.</span></p>
<ol>
<li><span style="font-size:small;">Collect uptime in days - ((System()\System UpTime / 86400.0) * 1.0)</span></li>
<li><span style="font-size:small;">Collect the private bytes of a process as a percentage of the system commit limit - ((Process(TestLimit)\Private Bytes / Memory()\Commit Limit) * 100.0)</span></li>
<li><span style="font-size:small;">Alert when Network Adapter is more than 50% used - ((NetworkAdapter(&lt;object property&gt;)Bytes Received/sec / NetworkAdapter(&lt;same object&gt;)\Current Bandwidth) * 800.0)</span></li>
<li><span style="font-size:small;">Alert when a process us using more than 20% of total CPU on the system - ((Process(CPUStress)\% Processor Time / &lt;Logical Cores&gt;) * 1.0)</span></li>
<li><span style="font-size:small;">Alert when 404/sec &gt; 50% of all web requests - ((Web Service(Default Web Site)\Not Found Errors/sec / Web Service(Default Web Site)\Total Method Requests/sec) * 100.0)</span></li>
</ol>
<p><span style="font-size:small;">NOTE: You can get CPUStress and TestLimit here: <a href="https://live.sysinternals.com/Files">https://live.sysinternals.com/Files</a></span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9752/00/00/03/65/46/52/Microsoft.PerfCounter.Math.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9752-00-00-03-65-46-52/Microsoft.PerfCounter.Math.zip">Microsoft.PerfCounter.Math.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Extra Monitor Type for TCP and HTTP(S) Synthetic Transactions</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/extra-monitor-type-for-tcp-and-https-synthetic-transactions</link>
      <pubDate>Fri, 28 Aug 2015 14:45:00 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/2015/08/28/extra-monitor-type-for-tcp-and-https-synthetic-transactions/</guid>
      <description><![CDATA[NOTE: I authored this MP in the SCOM 2007 R2 Authoring Console.&nbsp; This MP should work in both...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size:small;"><span style="text-decoration:underline;"><strong>NOTE:</strong></span> I authored this MP in the SCOM 2007 R2 Authoring Console.&nbsp; This MP should work in both SCOM 2007 and SCOM 2012.&nbsp; I have only tested it in SCOM 2012 R2, so if you are using it with a different version of SCOM you may want to verify that it properly works.</span></p>
<p><span style="font-size:small;">The SCOM Operations Console provides a way to author TCP and HTTP(S) synthetic transactions.&nbsp; But sometimes it is handy to be able to author these checks directly into a Management Pack.</span></p>
<p><span style="font-size:small;">Some common reasons to do this would be:</span></p>
<ol>
<li><span style="font-size:small;">You need all members of a class to run the transaction.</span></li>
<li><span style="font-size:small;">Authoring Web Application and TCP Port monitors in the Operations Console requires that you explicitly pick agents and/or resource pools from which to run the test.&nbsp; This means you must manually keep up with configuration churn.</span></li>
<li><span style="font-size:small;">You want to use object properties in the monitor configuration.</span></li>
<li><span style="font-size:small;">You want to put these monitors into MP&#39;s that can be shared or distributed across SCOM deployments.</span></li>
</ol>
<p><span style="font-size:small;">To meet this need I have created two, very simple monitor types.</span></p>
<p><span style="font-size:small;text-decoration:underline;"><strong>Microsoft.Extra.Synthetic.Transactions.TCP.Port.MonitorType</strong></span></p>
<p><span style="font-size:small;">This monitor uses the existing Microsoft.SystemCenter.SyntheticTransactions.TCPPortCheckProbe probe found in the Microsoft.SystemCenter.SyntheticTransactions.Library.&nbsp; You can read more about it on MSDN.&nbsp; <a href="https://msdn.microsoft.com/en-us/library/jj130214.aspx">https://msdn.microsoft.com/en-us/library/jj130214.aspx</a></span></p>
<p><span style="font-size:small;">I just used a Simple Scheduler and a couple of Expression Filters to turn it into a monitor type.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/97/52/TCP.JPG" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-97-52/TCP.JPG"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/97/52/TCP.JPG" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-97-52/TCP.JPG" border="0" /></a></p>
<p><span style="font-size:small;">The monitor takes three configuration settings.</span></p>
<ol>
<li><span style="font-size:small;">Destination &ndash; the IP address or DNS name of the destination</span></li>
<li><span style="font-size:small;">TCPPort &ndash; The TCP port you want to check</span></li>
<li><span style="font-size:small;">IntervalSeconds &ndash; How frequently you want it to run</span></li>
</ol>
<p><span style="font-size:small;">If you want to put its output into an Alert Description, you can do something like this:</span></p>
<ul>
<li><span style="font-size:small;">Server or IP Address: $Data/Context/DataItem/ServerName$</span></li>
<li><span style="font-size:small;">TCP Port: $Data/Context/DataItem/Port$</span></li>
<li><span style="font-size:small;">Connection Time: $Data/Context/DataItem/ConnectionTime$</span></li>
<li><span style="font-size:small;">Status Code: $Data/Context/DataItem/StatusCode$</span></li>
</ul>
<p><span style="font-size:small;text-decoration:underline;"><strong>Microsoft.Extra.Synthetic.Transactions.Basic.URL.MonitorType</strong></span></p>
<p><span style="font-size:small;">For this monitor type I did write a custom data source in PowerShell.&nbsp; I could have used VBScript, but that would have prevented me from allowing the option to make the call, automatically using the credentials of the Run As user account, without needing to pass the user name and password as parameters.</span></p>
<p><span style="font-size:small;">These are the monitor type&#39;s configuration settings:</span></p>
<ol>
<li><span style="font-size:small;">URL &ndash; The URL you want to test.&nbsp; HTTP and HTTPS are both fine.</span></li>
<li><span style="font-size:small;">IntervalSeconds &ndash; How frequently you want it to run.</span></li>
<li><span style="font-size:small;">UseDefaultCredentials &ndash; false will make an ANONYMOUS request.&nbsp; true will have it use the credentials of the SCOM Action Account.</span></li>
<li><span style="font-size:small;">Proxy &ndash; Leave it blank to not use a proxy server.&nbsp; Otherwise fill it in.&nbsp; You can use IPAddress:PORT or Hostname:PORT</span></li>
<li><span style="font-size:small;">CertThumbprint &ndash; Leave it blank to not use a client cert.&nbsp; Otherwise give it the thumbprint of a cert installed in the Local Computer&rsquo;s Personal certificate store.</span></li>
</ol>
<p><span style="font-size:small;">The PowerShell script itself is nothing fancy.&nbsp; I just create a [System.Net.HttpWebRequest] and then optionally set the UseDefaultCredentials, Proxy, and ClientCertificates properties if I need to.&nbsp; You can read more about this on MSDN here: <a href="https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest(v=vs.110).aspx">https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest(v=vs.110).aspx</a></span></p>
<p><span style="font-size:small;">For your convenience I will place the PowerShell script in the ZIP file attached to this blog post so you can easily see it outside of the SCOM MP.&nbsp; If you want to use the script outside of SCOM you will need to update the QuitTheScript to output something besides a SCOM property bag.</span></p>
<p><span style="font-size:small;">I am also including a sealed and unsealed copy of the library and an example MP that uses the library.&nbsp; The example MP demonstrates some possible ways to use the monitor types and data that can be included in alert descriptions.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/97/52/Examples.JPG" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-97-52/Examples.JPG"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/97/52/Examples.JPG" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-97-52/Examples.JPG" border="0" /></a></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9752/00/00/03/65/40/31/Extra.Synthetic.Transactions.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9752-00-00-03-65-40-31/Extra.Synthetic.Transactions.zip">Extra.Synthetic.Transactions.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>SCOM does not properly groom all MT*_Log tables</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/scom-does-not-properly-groom-all-mt_log-tables</link>
      <pubDate>Wed, 08 Apr 2015 17:38:33 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/2015/04/08/scom-does-not-properly-groom-all-mt_log-tables/</guid>
      <description><![CDATA[UPDATE: This issue has been resolved in SCOM 2012 R2 UR7.


I was asked to look at&nbsp;a very...]]></description>
      <content:encoded><![CDATA[<p><strong><span style="font-size:small;"><span style="text-decoration:underline;">UPDATE:</span> This issue has been resolved in SCOM 2012 R2 UR7.<br /></span></strong></p>
<p><span style="font-size:small;"></span></p>
<hr style="width:100%;" />
<p><span style="font-size:small;">I was asked to look at&nbsp;a very large&nbsp;OperationsManager database.&nbsp; One of the MT*_Log tables had over 53 million rows.&nbsp; This lead me to a bug in one of SCOM&#39;s grooming stored procedures.</span></p>
<p><span style="font-size:large;text-decoration:underline;"><strong>Background</strong></span></p>
<p><span style="font-size:small;">Whenever you discover a class instance in SCOM it is added to the appropriate MT_ table, along with the discovered properties.&nbsp; It is also added to the matching MT_Log table with all of the Pre columns set to NULL.&nbsp; If the properties of a discovered class instance change the MT_ table is updated to reflect the current values and the MT_Log table for that class is updated with the Pre and Post columns for each property set to the old and new values.</span></p>
<p><span style="font-size:small;">When there are class instances with properties that do not change, or very rarely change, these MT*_Log tables are small, and tie back to the EntityChangeLog table.&nbsp; Once an EntityChangeLogId is deleted from the EntityChangeLog table, any rows with the now deleted EntityChangeLogId may be deleted from the MT*_Log tables.</span></p>
<p><span style="font-size:small;">There is a stored procedure called [dbo].[p_GroomTypeSpecificLogTables] that loops through the MT*_Log tables and grooms them.</span></p>
<p><span style="font-size:large;text-decoration:underline;"><strong>Problem</strong></span></p>
<p><span style="font-size:small;">The [dbo].[p_GroomTypeSpecificLogTables] has a mistake.&nbsp; The ASCII value for the &quot;$&quot; character is 36.&nbsp; The ASCII value for the &quot;_&quot; character is 95.&nbsp; This simple bit of TSQL will illustrate the problem.</span></p>
<p style="margin-left:30px;"><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">IF (&#39;A$B$C&#39; &gt; &#39;A$B_Log&#39;)</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">&nbsp; PRINT &#39;Yes&#39;</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">ELSE</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">&nbsp; PRINT &#39;No&#39;</span></strong></span></p>
<p style="margin-left:30px;"><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">IF (&#39;A$D$C&#39; &gt; &#39;A$B_Log&#39;)</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">&nbsp; PRINT &#39;Yes&#39;</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">ELSE</span></strong></span><br /><span style="font-family:courier new,courier;font-size:small;">&nbsp; <strong>PRINT &#39;No&#39;</strong></span></p>
<p><span style="font-size:small;">I ran into this problem with the SQL Server 2012 Analysis Services Management Pack.&nbsp; My MT_Microsoft$SQLServer$2012$AnalysisServices$MultidimensionalPartition_Log table is over 1.3 million rows.</span></p>
<p><span style="font-size:small;">If you run this query you see the MT_ tables for that MP</span></p>
<p style="margin-left:30px;"><span style="font-family:courier new,courier;font-size:small;"><strong>SELECT ManagedTypeTableName FROM ManagedType where ManagedTypeTableName LIKE &#39;MT_Microsoft$SQLServer$2012$Analysis%&#39;</strong></span></p>
<p><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices</span><br /><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices$MultidimensionalPartition</span><br /><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices$PowerPivotInstance</span><br /><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices$TabularInstance</span><br /><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices$TabularDatabase</span><br /><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices$InstanceGroup</span><br /><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices$Seed</span><br /><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices$MultidimensionalInstance</span><br /><span style="font-size:small;">MT_Microsoft$SQLServer$2012$AnalysisServices$MultidimensionalDatabase</span></p>
<p><span style="font-size:small;">But if you use the grooming stored procedures logic, after you groom the first log, you skip the rest of the managed type logs.&nbsp; Try this:</span></p>
<p style="margin-left:30px;"><span style="font-family:courier new,courier;font-size:small;"><strong>SELECT * FROM ManagedType where ManagedTypeTableName LIKE &#39;MT_Microsoft$SQLServer$2012$Analysis%&#39;</strong></span><br /><span style="font-family:courier new,courier;font-size:small;"><strong>AND ManagedTypeTableName &gt; &#39;MT_Microsoft$SQLServer$2012$AnalysisServices_Log&#39;</strong></span></p>
<p><span style="font-size:large;text-decoration:underline;"><strong>Workaround</strong></span></p>
<p><span style="font-size:small;"><em><strong><span style="color:#ff0000;">WARNING</span></strong></em>: Editing the SCOM DB by hand is not supported.&nbsp; Do this at your own risk.&nbsp; Microsoft does not officially suggest doing anything like this.&nbsp; You get the idea...</span></p>
<p><span style="font-size:small;">If you script [dbo].[p_GroomTypeSpecificLogTables] as &quot;Alter To&quot; look at lines 73-78.&nbsp; It should look like this:</span></p>
<p style="margin-left:30px;"><span style="font-family:courier new,courier;font-size:small;"><strong>-- Get next table to groom.</strong></span><br /><span style="font-family:courier new,courier;font-size:small;"><strong>SELECT TOP 1 @TableName = MT.ManagedTypeTableName</strong></span><br /><span style="font-family:courier new,courier;font-size:small;"><strong>FROM ManagedType MT</strong></span><br /><span style="font-family:courier new,courier;font-size:small;"><strong>WHERE MT.ManagedTypeTableName IS NOT NULL</strong></span><br /><span style="font-family:courier new,courier;font-size:small;"><strong>AND MT.ManagedTypeTableName &gt; <span style="background-color:#ffff00;">@LogTableName</span></strong></span><br /><span style="font-family:courier new,courier;font-size:small;"><strong>ORDER BY MT.ManagedTypeTableName</strong></span></p>
<p><span style="font-size:small;">The problem is&nbsp;@LogTableName ends with &quot;_Log&quot;&nbsp; and the &quot;_&quot; character has an ASCII value higher than &quot;$&quot; and also higher than any capital letter.</span></p>
<p><span style="font-size:small;">If you alter line 77 of the stored procedure to use @TableName instead of @LogTableName, the MT_Log tables that were not groomed before will groom during the next scheduled run.</span></p>
<p style="margin-left:30px;"><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">-- Get next table to groom.</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">SELECT TOP 1 @TableName = MT.ManagedTypeTableName</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">FROM ManagedType MT</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">WHERE MT.ManagedTypeTableName IS NOT NULL</span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">AND MT.ManagedTypeTableName &gt; <span style="background-color:#ffff00;">@TableName</span></span></strong></span><br /><span style="font-size:small;"><strong><span style="font-family:courier new,courier;">ORDER BY MT.ManagedTypeTableName</span></strong></span></p>]]></content:encoded>
    </item>
    <item>
      <title>Updating SQL Server Analysis Services Via PowerShell</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/updating-sql-server-analysis-services-via-powershell</link>
      <pubDate>Thu, 18 Dec 2014 17:18:24 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/2014/12/18/updating-sql-server-analysis-services-via-powershell/</guid>
      <description><![CDATA[If you use the GUI install both the SQL Database Engine and SQL Analysis Services in the same server...]]></description>
      <content:encoded><![CDATA[<p>If you use the GUI install both the SQL Database Engine and SQL Analysis Services in the same server by clicking &quot;Ok&quot; and &quot;Next&quot; a lot, the default memory settings used by the DB Engine and SSAS allow for a risk of them starving each other and/or the operating system of memory.&nbsp; This can be especially risky if SQL runs as an account that can lock pages in memory; because it will.</p>
<p>I recently needed to deploy the SCOM MP&#39;s for SQL SSAS for the first time.&nbsp; They include monitors that validate the memory settings of SSAS to ensure that they don&#39;t conflict with the SQL Database Engine or the operating system.&nbsp; However they don&#39;t include recovery tasks.&nbsp; I&#39;d prefer not to bother my DBA&#39;s with alerts that I can have SCOM auto-fix, so I set out to write Recovery&nbsp;Tasks for the SCOM Monitors.&nbsp; Scripting against the SQL Database Engine is extensively documented, but I had trouble finding example scripts for SSAS.</p>
<p>So here&#39;s a script that changes SSAS&#39;s Low Memory Limit and Total Memory Limit settings.</p>
<p style="margin-left:30px;"><strong><span style="font-family:courier new,courier;">[Reflection.Assembly]::LoadWithPartialName(&quot;Microsoft.AnalysisServices&quot;)</span></strong><br /><strong><span style="font-family:courier new,courier;">$myServer = New-Object Microsoft.AnalysisServices.Server</span></strong><br /><strong><span style="font-family:courier new,courier;">$myServer.connect(&quot;localhost&quot;)</span></strong></p>
<p style="margin-left:30px;"><strong><span style="font-family:courier new,courier;">$lml = $myServer.ServerProperties | WHERE {$_.Name -eq &#39;Memory\LowMemoryLimit&#39;}</span></strong><br /><strong><span style="font-family:courier new,courier;">$tml = $myServer.ServerProperties | WHERE {$_.Name -eq &#39;Memory\TotalMemoryLimit&#39;}</span></strong></p>
<p style="margin-left:30px;"><strong><span style="font-family:courier new,courier;">$lml.Value = 20</span></strong><br /><strong><span style="font-family:courier new,courier;">$tml.Value = 40</span></strong></p>
<p style="margin-left:30px;"><br /><strong><span style="font-family:courier new,courier;">$myServer.Update()</span></strong></p>
<p>Obviously I have no error handling here, and I hard-coded the connection string to &quot;localhost&quot; but&nbsp;I hope this serves as a&nbsp;basic example.</p>
<p>I tested the script on the following versions of SSAS.</p>
<ol>
<li>10.50.4319.0 (2008 R2)</li>
<li>11.0.5058.0 (2012)</li>
<li>12.0.2381.0 (2014)</li>
</ol>
<p>For additional reading:</p>
<p>https://msdn.microsoft.com/en-us/library/microsoft.analysisservices.server.aspx</p>
<p>https://msdn.microsoft.com/en-us/library/ms174514.aspx</p>]]></content:encoded>
    </item>
    <item>
      <title>Azure Storage Analytics Metrics Management Pack</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/azure-storage-analytics-metrics-management-pack</link>
      <pubDate>Fri, 15 Aug 2014 15:39:00 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/2014/08/15/azure-storage-analytics-metrics-management-pack/</guid>
      <description><![CDATA[This is a draft of a SCOM management pack I made for Azure Storage Analytics Metrics.&nbsp; It&#39;s...]]></description>
      <content:encoded><![CDATA[<p><span style="font-family:verdana,geneva;font-size:medium;">This is a draft of a SCOM management pack I made for Azure Storage Analytics Metrics.&nbsp; It&#39;s not up to the quality of an officially released MP, but feel free to use/share/dissect at your own discretion.</span></p>
<p><span style="font-family:verdana,geneva;font-size:medium;">This MP requires&nbsp;version 1.1.42.0 or higher of the Windows Azure MP found here:</span></p>
<p><span style="font-family:verdana,geneva;font-size:medium;"><a href="https://www.microsoft.com/en-us/download/details.aspx?id=38414">https://www.microsoft.com/en-us/download/details.aspx?id=38414</a> </span></p>
<p><span style="font-family:verdana,geneva;font-size:medium;">It will <span style="text-decoration:underline;"><strong>not</strong></span> work with the earlier&nbsp;Windows Azure MP version 6.1.7724.0 found here:</span></p>
<p><span style="font-family:verdana,geneva;font-size:medium;"><a href="https://www.microsoft.com/en-us/download/details.aspx?id=11324">https://www.microsoft.com/en-us/download/details.aspx?id=11324</a> </span></p>
<p style="margin:0in 0in 0pt;"><span style="font-family:verdana,geneva;font-size:medium;"><b><span style="color:black;">NOTE: You are on your own to turn Azure storage metrics on.&nbsp; This MP will not turn them on for you.</span></b></span></p>
<p><span style="font-family:verdana,geneva;font-size:medium;">For additional reading on the topic:</span></p>
<p><span style="font-family:verdana,geneva;font-size:medium;"><a href="https://msdn.microsoft.com/en-us/library/hh343264.aspx">https://msdn.microsoft.com/en-us/library/hh343264.aspx</a> </span></p>
<p><span style="font-family:verdana,geneva;font-size:medium;">By default this MP will discover if Blob, Queue, and/or Table metrics are enabled on any if your Monitored Azure Storage services.&nbsp; If metrics are enabled it will start collecting the following hourly metrics into the Ops DB and the Data Warehouse:</span></p>
<ul>
<li><span style="font-family:verdana,geneva;font-size:medium;">Availability</span></li>
<li><span style="font-family:verdana,geneva;font-size:medium;">AverageE2ELatency</span></li>
<li><span style="font-family:verdana,geneva;font-size:medium;">AverageServerLatency</span></li>
<li><span style="font-family:verdana,geneva;font-size:medium;">PercentSuccess</span></li>
<li><span style="font-family:verdana,geneva;font-size:medium;">PercentThrottlingError</span></li>
<li><span style="font-family:verdana,geneva;font-size:medium;">ThrottlingError</span></li>
<li><span style="font-family:verdana,geneva;font-size:medium;">TotalEgress</span></li>
<li><span style="font-family:verdana,geneva;font-size:medium;">TotalIngress</span></li>
<li><span style="font-family:verdana,geneva;font-size:medium;">TotalRequests</span></li>
</ul>
<p><span style="font-family:verdana,geneva;font-size:medium;">In addition to that, it will alert if Availability drops below 98% and/or PercentThrottlingError rises above 1%.</span></p>
<p><span style="font-family:verdana,geneva;font-size:medium;">There are views for state, script events, and performance.</span></p>
<p><span style="font-family:arial,helvetica,sans-serif;font-size:medium;"><span style="font-family:verdana,geneva;">If you have any questions, comments, or requests, feel free to run them by me.&nbsp; I may add to this MP over time</span>.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9752/00/00/03/63/60/87/Microsoft.SystemCenter.WindowsAzure.StorageAnalyticsMetrics.xml" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9752-00-00-03-63-60-87/Microsoft.SystemCenter.WindowsAzure.StorageAnalyticsMetrics.xml">Microsoft.SystemCenter.WindowsAzure.StorageAnalyticsMetrics.xml</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Read the Azure Storage Analytics Metrics Table with PowerShell</title>
      <link>https://docs.microsoft.com/archive/blogs/omx/read-the-azure-storage-analytics-metrics-table-with-powershell</link>
      <pubDate>Fri, 08 Aug 2014 16:05:04 GMT</pubDate>
      <dc:creator><![CDATA[Michael Repperger]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/omx/2014/08/08/read-the-azure-storage-analytics-metrics-table-with-powershell/</guid>
      <description><![CDATA[Another script I recently needed to read Azure Storage Analytics Metrics.
Here is the table schema...]]></description>
      <content:encoded><![CDATA[<p>Another script I recently needed to read Azure Storage Analytics Metrics.</p>
<p>Here is the table schema if you need additional or different information.</p>
<p><a href="https://msdn.microsoft.com/en-us/library/azure/hh343264.aspx">https://msdn.microsoft.com/en-us/library/azure/hh343264.aspx</a></p>
<p>Please note that metrics are calculated when an aggregation period ends and are not available immediately.&nbsp; If you run my script as-is, it will attempt to get blob metrics from the previous hour.&nbsp; If you run it &quot;early&quot; in the hour, the data from the previous hour may not yet be ready.&nbsp; You can comment out my filter line to get all data.</p>
<p>Please note that you are on your own to turn storage metrics on.&nbsp; My script will not enable storage metrics for you.</p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Hard-coded Parameters</span><br /><span style="font-family:courier new,courier;"># Set $proxyAddr = &#39;&#39; if you don&#39;t need a proxy server</span><br /><span style="font-family:courier new,courier;"># Change $BlobOrQueueOrTable to &#39;Queue&#39; or &#39;Table&#39; if you like.</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$mgmtUri = &#39;https://management.core.windows.net&#39;</span><br /><span style="font-family:courier new,courier;">$subId = &#39;12345678-1234-1234-1234-123456789ABC&#39;</span><br /><span style="font-family:courier new,courier;">$msApiVer = &#39;2012-08-01&#39;</span><br /><span style="font-family:courier new,courier;">$servName = &#39;asdfgh&#39;</span><br /><span style="font-family:courier new,courier;">$tableEP = &#39;https://asdfgh.table.core.windows.net/&#39;</span><br /><span style="font-family:courier new,courier;">$certPW = &#39;&lt;PFX Password&gt;&#39;</span><br /><span style="font-family:courier new,courier;">$certPath = &#39;C:\myCert.pfx&#39;</span><br /><span style="font-family:courier new,courier;">$proxyAddr = &#39;https://proxy:80&#39;</span></p>
<p><span style="font-family:courier new,courier;">$HourOrMinute = &#39;Hour&#39;</span><br /><span style="font-family:courier new,courier;">$PrimaryOrSecondary = &#39;Primary&#39;</span><br /><span style="font-family:courier new,courier;">$BlobOrQueueOrTable = &#39;Blob&#39;</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Create a X509 Certificate from the byte array</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$flags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]&quot;MachineKeySet&quot;</span><br /><span style="font-family:courier new,courier;">$clientCert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $certPath, $certPW, $flags</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Call the management service to get the storage keys</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$keysUri = $mgmtUri + &#39;/&#39; + $subId + &#39;/services/storageservices/&#39; + $servName + &#39;/keys&#39;</span><br /><span style="font-family:courier new,courier;">$mgmtWebRequest = [System.Net.HttpWebRequest]::Create($keysUri)</span><br /><span style="font-family:courier new,courier;">$mgmtWebRequest.Timeout = 15000</span><br /><span style="font-family:courier new,courier;">$mgmtWebRequest.ClientCertificates.Add($clientCert)</span><br /><span style="font-family:courier new,courier;">$mgmtWebRequest.Method = &quot;GET&quot;</span><br /><span style="font-family:courier new,courier;">$mgmtWebRequest.Headers.Add(&quot;x-ms-version&quot;, $msApiVer)</span><br /><span style="font-family:courier new,courier;">If ($proxyAddr -eq &#39;&#39;)</span><br /><span style="font-family:courier new,courier;">{</span><br /><span style="font-family:courier new,courier;">&nbsp; $mgmtWebRequest.Proxy = $null</span><br /><span style="font-family:courier new,courier;">}</span><br /><span style="font-family:courier new,courier;">Else</span><br /><span style="font-family:courier new,courier;">{</span><br /><span style="font-family:courier new,courier;">&nbsp; $myWebProxy = New-Object System.Net.WebProxy($proxyAddr)</span><br /><span style="font-family:courier new,courier;">&nbsp; $mgmtWebRequest.Proxy = $myWebProxy</span><br /><span style="font-family:courier new,courier;">}</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Get the storage service keys from the response</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$response = $mgmtWebRequest.GetResponse()</span><br /><span style="font-family:courier new,courier;">$responseReader = New-Object System.IO.StreamReader($response.GetResponseStream())</span><br /><span style="font-family:courier new,courier;">[xml]$xmlResponseBody = $responseReader.ReadToEnd()</span><br /><span style="font-family:courier new,courier;">$responseReader.Close()</span><br /><span style="font-family:courier new,courier;">$primaryKey = $xmlResponseBody.StorageService.StorageServiceKeys.Primary</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Create a hasher and seed it with the storage key</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$sharedKey = [System.Convert]::FromBase64String($primaryKey)</span><br /><span style="font-family:courier new,courier;">$myHasher = New-Object System.Security.Cryptography.HMACSHA256</span><br /><span style="font-family:courier new,courier;">$myHasher.Key = $sharedKey</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Construct the Storage Analytics Metrics Table and URI</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$myInvariantCulture = New-Object System.Globalization.CultureInfo(&quot;&quot;)</span><br /><span style="font-family:courier new,courier;">$strTable = &#39;$Metrics&#39; + $HourOrMinute + $PrimaryOrSecondary + &#39;Transactions&#39; + $BlobOrQueueOrTable</span><br /><span style="font-family:courier new,courier;">$strTableUri = $tableEP + $strTable</span></p>
<p><span style="font-family:courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br /><span style="font-family:courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Get the current date/time and format it properly</span><br /><span style="font-family:courier new,courier;"># The culture &quot;&quot; is the invariant culture</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$myDateObj = Get-Date</span><br /><span style="font-family:courier new,courier;">$strDate = $myDateObj.ToUniversalTime().ToString(&quot;R&quot;, $myInvariantCulture)</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># This will get only the metrics from the previous hour.&nbsp; Metrics are not</span><br /><span style="font-family:courier new,courier;"># available immediately when an hour ends.&nbsp; If you want to change this</span><br /><span style="font-family:courier new,courier;"># try either subtracting more than 1 hour from the current time or</span><br /><span style="font-family:courier new,courier;"># removing the filter from the URI.&nbsp; You can comment out the next two</span><br /><span style="font-family:courier new,courier;"># lines if you like.</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$strPartition = $myDateObj.AddHours(-1).ToUniversalTime().ToString(&quot;yyyyMMddTHH00&quot;)</span><br /><span style="font-family:courier new,courier;">$strTableUri = $strTableUri + &#39;?$filter=PartitionKey%20eq%20&#39;&#39;&#39; + $strPartition + &#39;&#39;&#39;&#39;</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Preare the HttpWebRequest</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$tableWebRequest = [System.Net.HttpWebRequest]::Create($strTableUri)</span><br /><span style="font-family:courier new,courier;">$tableWebRequest.Timeout = 15000</span><br /><span style="font-family:courier new,courier;">$tableWebRequest.ContentType = &quot;application/xml&quot;</span><br /><span style="font-family:courier new,courier;">$tableWebRequest.Method = &quot;GET&quot;</span><br /><span style="font-family:courier new,courier;">$tableWebRequest.Headers.Add(&quot;x-ms-date&quot;, $strDate)</span><br /><span style="font-family:courier new,courier;">If ($proxyAddr -eq &#39;&#39;)</span><br /><span style="font-family:courier new,courier;">{</span><br /><span style="font-family:courier new,courier;">&nbsp; $tableWebRequest.Proxy = $null</span><br /><span style="font-family:courier new,courier;">}</span><br /><span style="font-family:courier new,courier;">Else</span><br /><span style="font-family:courier new,courier;">{</span><br /><span style="font-family:courier new,courier;">&nbsp; $tableWebProxy = New-Object System.Net.WebProxy($proxyAddr)</span><br /><span style="font-family:courier new,courier;">&nbsp; $tableWebRequest.Proxy = $tableWebProxy</span><br /><span style="font-family:courier new,courier;">}</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Create the Authorization header</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$strToSign = $tableWebRequest.Method + &quot;`n&quot; `</span><br /><span style="font-family:courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + $tableWebRequest.Headers.Get(&quot;Content-MD5&quot;) + &quot;`n&quot; `</span><br /><span style="font-family:courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + $tableWebRequest.Headers.Get(&quot;Content-Type&quot;) + &quot;`n&quot; `</span><br /><span style="font-family:courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + $tableWebRequest.Headers.Get(&quot;x-ms-date&quot;) + &quot;`n&quot; `</span><br /><span style="font-family:courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + &#39;/&#39; + $servName + &#39;/&#39; + $strTable</span><br /><span style="font-family:courier new,courier;">$bytesToSign = [System.Text.Encoding]::UTF8.GetBytes($strToSign)</span><br /><span style="font-family:courier new,courier;">$strSignedStr = [System.Convert]::ToBase64String($myHasher.ComputeHash($bytesToSign))</span><br /><span style="font-family:courier new,courier;">$strAuthHeader = &quot;SharedKey &quot; + $servName + &quot;:&quot; + $strSignedStr</span><br /><span style="font-family:courier new,courier;">$tableWebRequest.Headers.Add(&quot;Authorization&quot;, $strAuthHeader)</span></p>
<p></p>
<p><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;"># Read the results</span><br /><span style="font-family:courier new,courier;">##########################################################################</span><br /><span style="font-family:courier new,courier;">$tableResponse = $tableWebRequest.GetResponse()</span><br /><span style="font-family:courier new,courier;">$tableResponseReader = New-Object System.IO.StreamReader($tableResponse.GetResponseStream())</span><br /><span style="font-family:courier new,courier;">[xml]$xmlMetricsData = $tableResponseReader.ReadToEnd()</span><br /><span style="font-family:courier new,courier;">$entries = $xmlMetricsData.feed.entry</span></p>
<p><span style="font-family:courier new,courier;">Foreach ($entry in $entries)</span><br /><span style="font-family:courier new,courier;">{</span><br /><span style="font-family:courier new,courier;">&nbsp; Write-Host &#39;Row Key:&#39; $entry.content.properties.RowKey</span><br /><span style="font-family:courier new,courier;">&nbsp; Write-Host &#39;Partition Key:&#39; $entry.content.properties.PartitionKey</span><br /><span style="font-family:courier new,courier;">&nbsp; Write-Host &#39;Total Requests:&#39; $entry.content.properties.TotalRequests.innertext</span><br /><span style="font-family:courier new,courier;">&nbsp; Write-Host &#39;Total Ingress:&#39; $entry.content.properties.TotalIngress.innertext</span><br /><span style="font-family:courier new,courier;">&nbsp; Write-Host &#39;Total Egress:&#39; $entry.content.properties.TotalEgress.innertext</span><br /><span style="font-family:courier new,courier;">&nbsp; Write-Host &#39;---------------------&#39;</span><br /><span style="font-family:courier new,courier;">}</span></p>
<p><span style="font-family:courier new,courier;">$tableResponseReader.Close()</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9752/00/00/03/63/56/98/GetMetricsData.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9752-00-00-03-63-56-98/GetMetricsData.zip">GetMetricsData.zip</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>