Blake Drumm - Technical BlogThis is the personal technical blog for Blake Drumm. I am a Senior Support Escalation Engineer at Microsoft.
https://blakedrumm.com/
Fri, 20 Mar 2026 18:42:18 -0400Fri, 20 Mar 2026 18:42:18 -0400Jekyll v4.3.2Sending Emails with Azure Communication Services (ACS) — A C# Console Application with Custom Headers/assets/img/posts/acs-email-console-app.png<h2 id="-introduction">💡 Introduction</h2>
<p>Azure Communication Services (ACS) provides a powerful Email API that allows developers to send transactional and notification emails directly from applications without managing SMTP infrastructure.</p>
<p>While the official SDK documentation demonstrates the basic steps required to send an email, real-world implementations often require additional capabilities such as:</p>
<ul>
<li>Custom email headers</li>
<li>Reply-to address handling</li>
<li>HTML email templates</li>
<li>Tracking identifiers for correlation</li>
<li>Logging and troubleshooting visibility</li>
<li>Automation-friendly execution behavior</li>
</ul>
<p>To explore these scenarios, I built a small <strong>C# console application</strong> that demonstrates sending a formatted email using the ACS Email SDK while implementing several practical features that are commonly required in production environments.</p>
<p>This post explains how the application works, how to run it, and includes a deeper look at the internal logic used to send and track emails through ACS.</p>
<hr />
<h2 id="-download-the-code">💾 Download the Code</h2>
<p>You can download the full source code used in this article here:</p>
<blockquote>
<p>🔗 <strong>Download the Email Quickstart Console Application</strong><br />
<a href="https://files.blakedrumm.com/EmailQuickstart-ACS.zip">https://files.blakedrumm.com/EmailQuickstart-ACS.zip</a></p>
</blockquote>
<p>After downloading, extract the archive and open the project folder in your preferred IDE such as <strong>Visual Studio</strong> or <strong>VS Code</strong>.</p>
<hr />
<h2 id="-what-the-application-does">📬 What the Application Does</h2>
<p>This console application sends a formatted HTML email using the Azure Communication Services Email SDK.</p>
<p>Key capabilities include:</p>
<ul>
<li>Sending <strong>HTML and plain-text email bodies</strong></li>
<li>Adding <strong>custom email headers</strong></li>
<li>Supporting <strong>reply-to addresses</strong></li>
<li>Generating a <strong>tracking identifier for correlation</strong></li>
<li>Polling the <strong>EmailSendOperation</strong> until completion</li>
<li>Logging timestamps and send duration</li>
<li>Supporting <strong>interactive and automated execution modes</strong></li>
</ul>
<p>Because of this functionality, the tool can be used as both:</p>
<ul>
<li>a <strong>developer testing utility</strong></li>
<li>a <strong>troubleshooting tool</strong></li>
<li>a <strong>validation tool for ACS email configuration</strong></li>
</ul>
<hr />
<h2 id="️-high-level-architecture">🏗️ High-Level Architecture</h2>
<p>The application flow mirrors how the ACS Email service processes messages.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Console Application
↓
Azure.Communication.Email SDK
↓
Azure Communication Services
↓
Recipient Mail Server
</code></pre></div></div>
<p>The console application constructs an email message, submits it through the ACS Email SDK, and waits for the asynchronous send operation to complete.</p>
<hr />
<h2 id="️-prerequisites">⚙️ Prerequisites</h2>
<p>Before running the application, ensure the following requirements are met.</p>
<h3 id="1-install-net">1. Install .NET</h3>
<p>The application requires the .NET SDK.</p>
<p><a href="https://dotnet.microsoft.com/download">https://dotnet.microsoft.com/download</a></p>
<hr />
<h3 id="2-create-an-azure-communication-services-resource">2. Create an Azure Communication Services Resource</h3>
<p>In the Azure Portal:</p>
<ol>
<li>Create an <strong>Azure Communication Services resource</strong></li>
<li>Navigate to <strong>Keys</strong></li>
<li>Copy the <strong>connection string</strong></li>
</ol>
<p>Example format:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>endpoint=https://<resource>.communication.azure.com/;accesskey=<key>
</code></pre></div></div>
<hr />
<h3 id="3-configure-acs-email">3. Configure ACS Email</h3>
<p>Your ACS resource must have:</p>
<ul>
<li>An <strong>email domain configured</strong></li>
<li>A <strong>verified sender address</strong></li>
</ul>
<p>Without this configuration, email sends will fail.</p>
<hr />
<h3 id="4-install-the-required-sdk">4. Install the Required SDK</h3>
<p>The project references the ACS Email SDK.</p>
<p>If you are creating a new project manually, install it using:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet add package Azure.Communication.Email
</code></pre></div></div>
<hr />
<h2 id="-configure-the-connection-string">🔑 Configure the Connection String</h2>
<p>The application reads the ACS connection string from an environment variable.</p>
<p>Environment variable name:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>COMMUNICATION_SERVICES_CONNECTION_STRING
</code></pre></div></div>
<h3 id="windows-command-prompt">Windows (Command Prompt)</h3>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">setx</span><span class="w"> </span><span class="nx">COMMUNICATION_SERVICES_CONNECTION_STRING</span><span class="w"> </span><span class="s2">"endpoint=https://<resource>.communication.azure.com/;accesskey=<key>"</span><span class="w">
</span></code></pre></div></div>
<h3 id="powershell">PowerShell</h3>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">COMMUNICATION_SERVICES_CONNECTION_STRING</span><span class="o">=</span><span class="s2">"endpoint=https://<resource>.communication.azure.com/;accesskey=<key>"</span><span class="w">
</span></code></pre></div></div>
<p>When the application starts, it validates that this variable exists before attempting to send an email.</p>
<hr />
<h2 id="️-build-the-application">▶️ Build the Application</h2>
<p>Navigate to the project directory and run:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet build
</code></pre></div></div>
<hr />
<h2 id="️-run-the-application">▶️ Run the Application</h2>
<p>You can run the application using:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet run
</code></pre></div></div>
<p>Or execute the compiled binary:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>EmailQuickstart-WithCustomHeaders.exe
</code></pre></div></div>
<p>When executed, the application sends a test email and logs progress in the console.</p>
<hr />
<h2 id="️-interactive-mode">🖥️ Interactive Mode</h2>
<p>If the application detects it is running in a terminal session, it enters <strong>interactive mode</strong>.</p>
<p>Available commands:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Ctrl + R → resend email
Enter → exit application
</code></pre></div></div>
<p>This allows rapid testing without restarting the program.</p>
<p>If the application runs in <strong>non-interactive mode</strong>, it sends a single email and exits automatically.</p>
<hr />
<h2 id="-email-template-and-message-content">📧 Email Template and Message Content</h2>
<p>The application constructs both:</p>
<ul>
<li>an <strong>HTML message body</strong></li>
<li>a <strong>plain-text fallback body</strong></li>
</ul>
<p>The HTML template includes common elements used in production email layouts:</p>
<ul>
<li>Responsive layout</li>
<li>Preheader text</li>
<li>Call-to-action button</li>
<li>Tracking identifier</li>
<li>Optional “view in browser” link</li>
</ul>
<p>The template contains placeholder tokens that are dynamically replaced before sending.</p>
<p>Examples include:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>##TRACKING_ID##
##VIEW_IN_BROWSER_URL##
##REPLY_TO_EMAILS##
</code></pre></div></div>
<hr />
<h2 id="️-custom-email-headers">🏷️ Custom Email Headers</h2>
<p>The project demonstrates the use of <strong>custom email headers</strong> to include metadata with each email.</p>
<p>Examples include:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Importance: normal
X-Mailer
X-Campaign
X-Environment
</code></pre></div></div>
<p>Custom headers can help with:</p>
<ul>
<li>campaign tracking</li>
<li>environment identification</li>
<li>message classification</li>
</ul>
<hr />
<h2 id="-tracking-and-correlation">🔎 Tracking and Correlation</h2>
<p>Each email send generates a unique tracking identifier.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Guid</span><span class="p">.</span><span class="nf">NewGuid</span><span class="p">()</span>
</code></pre></div></div>
<p>This identifier can be inserted into:</p>
<ul>
<li>email headers</li>
<li>message body</li>
<li>console logs</li>
</ul>
<p>This allows correlation between:</p>
<ul>
<li>application logs</li>
<li>Azure Monitor diagnostics</li>
<li>external email systems</li>
</ul>
<hr />
<h2 id="️-how-it-works-internally-deep-dive">⚙️ How It Works Internally (Deep Dive)</h2>
<h3 id="step-1--initialize-the-email-client">Step 1 — Initialize the Email Client</h3>
<p>The application creates an EmailClient using the ACS connection string.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">emailClient</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">EmailClient</span><span class="p">(</span><span class="n">connectionString</span><span class="p">);</span>
</code></pre></div></div>
<hr />
<h3 id="step-2--build-the-email-message">Step 2 — Build the Email Message</h3>
<p>An <code class="language-plaintext highlighter-rouge">EmailMessage</code> object is constructed containing:</p>
<ul>
<li>sender</li>
<li>recipients</li>
<li>subject</li>
<li>HTML body</li>
<li>text body</li>
<li>reply-to addresses</li>
<li>custom headers</li>
</ul>
<hr />
<h3 id="step-3--submit-the-send-request">Step 3 — Submit the Send Request</h3>
<p>The EmailClient submits the message to Azure Communication Services.</p>
<p>ACS returns an <strong>EmailSendOperation</strong>, which represents the asynchronous send request.</p>
<hr />
<h3 id="step-4--poll-the-operation">Step 4 — Poll the Operation</h3>
<p>Because email sends are asynchronous, the application polls the operation until completion.</p>
<p>During this process it logs:</p>
<ul>
<li>operation state</li>
<li>elapsed time</li>
<li>completion status</li>
</ul>
<hr />
<h3 id="step-5--log-the-results">Step 5 — Log the Results</h3>
<p>Structured logs are written to the console including timestamp and execution duration.</p>
<p>Example output:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[2026-01-16T20:03:14Z +2.31s] [INFO] Email send operation started.
</code></pre></div></div>
<hr />
<h2 id="-when-this-tool-is-useful">🧪 When This Tool Is Useful</h2>
<p>This console application is helpful for:</p>
<ul>
<li>validating ACS email configuration</li>
<li>testing custom headers</li>
<li>troubleshooting delivery failures</li>
<li>verifying domain and sender configuration</li>
<li>generating diagnostic logs</li>
<li>validating HTML email templates</li>
</ul>
<p>It effectively acts as a <strong>developer testing harness for Azure Communication Services Email</strong>.</p>
<hr />
<h2 id="️-common-issues-when-testing-acs-email">⚠️ Common Issues When Testing ACS Email</h2>
<h3 id="401-unauthorized">401 Unauthorized</h3>
<p>Usually caused by:</p>
<ul>
<li>incorrect connection string</li>
<li>expired or regenerated access key</li>
</ul>
<hr />
<h3 id="sender-not-verified">Sender Not Verified</h3>
<p>The sender address must belong to a <strong>verified domain configured in ACS</strong>.</p>
<hr />
<h3 id="email-never-arrives">Email Never Arrives</h3>
<p>Possible causes include:</p>
<ul>
<li>recipient spam filtering</li>
<li>missing SPF or DKIM records</li>
<li>invalid recipient address</li>
<li>message size or attachment restrictions</li>
</ul>
<hr />
<h2 id="-final-thoughts">🧠 Final Thoughts</h2>
<p>Azure Communication Services makes it easy to send email programmatically, but real-world implementations often require more than minimal SDK examples.</p>
<p>This console application demonstrates several useful capabilities including:</p>
<ul>
<li>HTML email construction</li>
<li>custom header support</li>
<li>reply-to handling</li>
<li>asynchronous operation polling</li>
<li>structured logging</li>
</ul>
<p>Tools like this make it easier to validate deployments, troubleshoot issues, and experiment with ACS email functionality before integrating it into larger systems.</p>
<hr />
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/acs-email-console-application/" alt="PageViews" /></p>
March 6, 2026
https://blakedrumm.com/blog/acs-email-console-application/
https://blakedrumm.com/blog/acs-email-console-application/Deep-Dive Email Delivery Analysis with KQL - Azure Communication Services (ACS)/assets/img/posts/acs-email-delivery-kql.png<h2 id="-introduction">💡 Introduction</h2>
<p>Email troubleshooting in <strong>Azure Communication Services (ACS)</strong> can be deceptively complex.</p>
<p>A message may appear to be sent successfully, yet arrive late, get quarantined, bounce with minimal explanation, or fail silently due to downstream mail server policies. While ACS exposes rich diagnostics in Azure Monitor, those signals are spread across multiple tables and often require correlation to tell a complete story.</p>
<p>This post introduces a <strong>production-ready KQL query</strong> that joins ACS email send and status logs to provide a <strong>single, enriched view of email delivery behavior</strong> — including latency, message characteristics, sender and recipient context, and clear interpretations of SMTP and enhanced SMTP failure codes.</p>
<hr />
<h2 id="-prerequisites">📋 Prerequisites</h2>
<p>To use this query, you’ll need:</p>
<ul>
<li>Access to Azure Monitor Log Analytics workspace with ACS diagnostic logs enabled</li>
<li>At least <strong>Log Analytics Reader</strong> role on the workspace</li>
<li>ACS Email diagnostic logs flowing to the workspace (both <code class="language-plaintext highlighter-rouge">ACSEmailSendMailOperational</code> and <code class="language-plaintext highlighter-rouge">ACSEmailStatusUpdateOperational</code> tables)</li>
<li>Basic familiarity with KQL (Kusto Query Language)</li>
</ul>
<hr />
<h2 id="-the-problem-with-raw-acs-email-logs">📩 The Problem with Raw ACS Email Logs</h2>
<p>Out of the box, ACS email diagnostics present a few challenges:</p>
<ul>
<li>Send and delivery status events live in <strong>separate tables</strong></li>
<li>Correlating send and delivery events requires understanding MessageId/CorrelationId relationships</li>
<li>SMTP codes are numeric and often unclear without protocol knowledge</li>
<li>Enhanced SMTP codes are easy to miss or misinterpret</li>
<li>Message size and attachment details are not immediately obvious</li>
<li>Bounce behavior (hard vs. soft) requires manual interpretation</li>
<li>Correlating events across systems is difficult without message IDs</li>
</ul>
<p>When customers ask questions like:</p>
<ul>
<li><em>“Why did this email bounce?”</em></li>
<li><em>“Why did delivery take 30 seconds instead of 2?”</em></li>
<li><em>“Is this a content issue, a mailbox issue, or a policy block?”</em></li>
</ul>
<p>You need more than raw logs — you need <strong>context</strong>.</p>
<hr />
<h2 id="-what-this-query-does">🔍 What This Query Does</h2>
<p>This KQL query was built to answer those questions directly.</p>
<p>At a high level, it:</p>
<ul>
<li>Joins <strong>send events</strong> with <strong>final delivery status events</strong></li>
<li>Measures <strong>end-to-end delivery latency</strong></li>
<li>Enriches results with sender, recipient, and message metadata</li>
<li>Classifies bounces and failures</li>
<li>Translates SMTP and enhanced SMTP codes into readable explanations</li>
</ul>
<p>All results are returned in a <strong>single, sortable dataset</strong>.</p>
<hr />
<h2 id="️-data-sources-used">⚙️ Data Sources Used</h2>
<p>The query relies on two ACS diagnostic tables:</p>
<h3 id="1️⃣-acsemailsendmailoperational">1️⃣ ACSEmailSendMailOperational</h3>
<p>Used to capture:</p>
<ul>
<li>Send timestamp</li>
<li>Message correlation ID</li>
<li>Message size (in <strong>megabytes</strong>, not bytes)</li>
<li>Attachment count</li>
<li>Recipient counts (To, Cc, Bcc, unique)</li>
</ul>
<h3 id="2️⃣-acsemailstatusupdateoperational">2️⃣ ACSEmailStatusUpdateOperational</h3>
<p>Used to capture:</p>
<ul>
<li>Final delivery status</li>
<li>SMTP and enhanced SMTP status codes</li>
<li>Sender identity</li>
<li>Failure reason and message</li>
<li>Bounce classification</li>
<li>Recipient mail server details</li>
<li>InternetMessageId for cross-system correlation</li>
</ul>
<hr />
<h2 id="-the-complete-query">📜 The Complete Query</h2>
<p>Here’s the full KQL query. You can copy and paste this directly into Azure Monitor Log Analytics:</p>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// -----------------------------------------------</span><span class="w">
</span><span class="c1">// Description: Analyzes Azure Communication Services email delivery by</span><span class="w">
</span><span class="c1">// joining send and status logs to measure delivery latency </span><span class="w">
</span><span class="c1">// and surface clear explanations for SMTP and enhanced SMTP</span><span class="w">
</span><span class="c1">// failure codes.</span><span class="w">
</span><span class="c1">//</span><span class="w">
</span><span class="c1">// Created by: Blake Drumm ([email protected])</span><span class="w">
</span><span class="c1">// Date Created: January 21st, 2026</span><span class="w">
</span><span class="c1">// Enhanced: February 10th, 2026</span><span class="w">
</span><span class="c1">// Enhancements:</span><span class="w">
</span><span class="c1">// - Added sender information (SenderUsername, SenderDomain)</span><span class="w">
</span><span class="c1">// - Added message characteristics (Size in MB, AttachmentsCount, recipient counts)</span><span class="w">
</span><span class="c1">// - Added detailed failure information (FailureMessage, FailureReason)</span><span class="w">
</span><span class="c1">// - Added bounce classification (IsHardBounce, BounceType)</span><span class="w">
</span><span class="c1">// - Added recipient domain extraction and mail server tracking</span><span class="w">
</span><span class="c1">// - Added InternetMessageId for cross-system correlation</span><span class="w">
</span><span class="c1">// - Corrected Size field interpretation (megabytes, not bytes)</span><span class="w">
</span><span class="c1">// -----------------------------------------------</span><span class="w">
</span><span class="p">(</span><span class="n">ACSEmailSendMailOperational</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">project</span><span class="w">
</span><span class="n">SendTime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TimeGenerated</span><span class="p">,</span><span class="w">
</span><span class="n">MessageId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CorrelationId</span><span class="p">,</span><span class="w">
</span><span class="n">MessageSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Size</span><span class="p">,</span><span class="w"> </span><span class="c1">// Size is in megabytes (MB)</span><span class="w">
</span><span class="n">AttachmentsCount</span><span class="p">,</span><span class="w">
</span><span class="n">ToRecipientsCount</span><span class="p">,</span><span class="w">
</span><span class="n">CcRecipientsCount</span><span class="p">,</span><span class="w">
</span><span class="n">BccRecipientsCount</span><span class="p">,</span><span class="w">
</span><span class="n">UniqueRecipientsCount</span><span class="p">,</span><span class="w">
</span><span class="n">_ResourceId</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">join</span><span class="w"> </span><span class="k">kind</span><span class="o">=</span><span class="n">inner</span><span class="w"> </span><span class="p">(</span><span class="w">
</span><span class="n">ACSEmailStatusUpdateOperational</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">isnotempty</span><span class="p">(</span><span class="n">RecipientId</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">DeliveryStatus</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="p">(</span><span class="s2">"Delivered"</span><span class="p">,</span><span class="s2">"Failed"</span><span class="p">,</span><span class="s2">"Bounced"</span><span class="p">,</span><span class="s2">"Suppressed"</span><span class="p">,</span><span class="s2">"Quarantined"</span><span class="p">,</span><span class="s2">"FilteredSpam"</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">summarize</span><span class="w"> </span><span class="nb">arg_max</span><span class="p">(</span><span class="n">TimeGenerated</span><span class="p">,</span><span class="w"> </span><span class="n">DeliveryStatus</span><span class="p">,</span><span class="w"> </span><span class="n">SmtpStatusCode</span><span class="p">,</span><span class="w"> </span><span class="n">EnhancedSmtpStatusCode</span><span class="p">,</span><span class="w">
</span><span class="n">SenderDomain</span><span class="p">,</span><span class="w"> </span><span class="n">SenderUsername</span><span class="p">,</span><span class="w"> </span><span class="n">FailureMessage</span><span class="p">,</span><span class="w"> </span><span class="n">FailureReason</span><span class="p">,</span><span class="w">
</span><span class="n">IsHardBounce</span><span class="p">,</span><span class="w"> </span><span class="n">RecipientMailServerHostName</span><span class="p">,</span><span class="w"> </span><span class="n">InternetMessageId</span><span class="p">)</span><span class="w">
</span><span class="k">by</span><span class="w"> </span><span class="n">MessageId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CorrelationId</span><span class="p">,</span><span class="w"> </span><span class="n">RecipientId</span><span class="p">,</span><span class="w"> </span><span class="n">_ResourceId</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">project</span><span class="w">
</span><span class="n">MessageId</span><span class="p">,</span><span class="w">
</span><span class="n">RecipientId</span><span class="p">,</span><span class="w">
</span><span class="n">_ResourceId</span><span class="p">,</span><span class="w">
</span><span class="n">FinalStatusTime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TimeGenerated</span><span class="p">,</span><span class="w">
</span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">DeliveryStatus</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tostring</span><span class="p">(</span><span class="n">SmtpStatusCode</span><span class="p">),</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tostring</span><span class="p">(</span><span class="n">EnhancedSmtpStatusCode</span><span class="p">),</span><span class="w">
</span><span class="n">SenderDomain</span><span class="p">,</span><span class="w">
</span><span class="n">SenderUsername</span><span class="p">,</span><span class="w">
</span><span class="n">FailureMessage</span><span class="p">,</span><span class="w">
</span><span class="n">FailureReason</span><span class="p">,</span><span class="w">
</span><span class="n">IsHardBounce</span><span class="p">,</span><span class="w">
</span><span class="n">RecipientMailServerHostName</span><span class="p">,</span><span class="w">
</span><span class="n">InternetMessageId</span><span class="w">
</span><span class="p">)</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">MessageId</span><span class="p">,</span><span class="w"> </span><span class="n">_ResourceId</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">FinalStatusTime</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">SendTime</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">DurationMilliseconds</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">datetime_diff</span><span class="p">(</span><span class="s2">"millisecond"</span><span class="p">,</span><span class="w"> </span><span class="n">FinalStatusTime</span><span class="p">,</span><span class="w"> </span><span class="n">SendTime</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">DurationSeconds</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">round</span><span class="p">(</span><span class="nb">todouble</span><span class="p">(</span><span class="n">DurationMilliseconds</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mf">1000.0</span><span class="p">,</span><span class="w"> </span><span class="mf">3</span><span class="p">)</span><span class="w">
</span><span class="c1">// Extract recipient domain for analysis</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">RecipientDomain</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tolower</span><span class="p">(</span><span class="n">extract</span><span class="p">(</span><span class="s2">@"@(.+)$"</span><span class="p">,</span><span class="w"> </span><span class="mf">1</span><span class="p">,</span><span class="w"> </span><span class="n">RecipientId</span><span class="p">))</span><span class="w">
</span><span class="c1">// Categorize message size (Size field is in megabytes)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">MessageSizeCategory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">case</span><span class="p">(</span><span class="w">
</span><span class="n">MessageSize</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mf">0.1</span><span class="p">,</span><span class="w"> </span><span class="s2">"Tiny (<100KB)"</span><span class="p">,</span><span class="w">
</span><span class="n">MessageSize</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mf">1.0</span><span class="p">,</span><span class="w"> </span><span class="s2">"Small (100KB-1MB)"</span><span class="p">,</span><span class="w">
</span><span class="n">MessageSize</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mf">5.0</span><span class="p">,</span><span class="w"> </span><span class="s2">"Medium (1-5MB)"</span><span class="p">,</span><span class="w">
</span><span class="n">MessageSize</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mf">10.0</span><span class="p">,</span><span class="w"> </span><span class="s2">"Large (5-10MB)"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Very Large (>10MB)"</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="c1">// Categorize bounce type (handle both "True"/"False" and "true"/"false")</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">BounceType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">case</span><span class="p">(</span><span class="w">
</span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Delivered"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Not Applicable"</span><span class="p">,</span><span class="w">
</span><span class="nb">tolower</span><span class="p">(</span><span class="n">IsHardBounce</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"true"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Hard Bounce"</span><span class="p">,</span><span class="w">
</span><span class="nb">tolower</span><span class="p">(</span><span class="n">IsHardBounce</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"false"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Soft Bounce"</span><span class="p">,</span><span class="w">
</span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="p">(</span><span class="s2">"Bounced"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Failed"</span><span class="p">)</span><span class="w"> </span><span class="k">and</span><span class="w"> </span><span class="n">isempty</span><span class="p">(</span><span class="n">IsHardBounce</span><span class="p">),</span><span class="w"> </span><span class="s2">"Unknown (not populated)"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Unknown"</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">=</span><span class="w">
</span><span class="nb">iff</span><span class="p">(</span><span class="n">isempty</span><span class="p">(</span><span class="n">SmtpStatusCode</span><span class="p">)</span><span class="w"> </span><span class="k">and</span><span class="w"> </span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Delivered"</span><span class="p">,</span><span class="w"> </span><span class="s2">"<not applicable>"</span><span class="p">,</span><span class="w"> </span><span class="n">SmtpStatusCode</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">=</span><span class="w">
</span><span class="nb">iff</span><span class="p">(</span><span class="n">isempty</span><span class="p">(</span><span class="n">EnhancedSmtpStatusCode</span><span class="p">)</span><span class="w"> </span><span class="k">and</span><span class="w"> </span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Delivered"</span><span class="p">,</span><span class="w"> </span><span class="s2">"<not applicable>"</span><span class="p">,</span><span class="w"> </span><span class="n">EnhancedSmtpStatusCode</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">SmtpStatusCodeDetails</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">case</span><span class="p">(</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"<not applicable>"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Not applicable (Delivered)"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"421"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Service not available; try again later (temporary failure)"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"450"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Mailbox unavailable (temporary); retry expected"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"451"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Local error in processing (temporary); retry expected"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"452"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Insufficient system storage (temporary); retry expected"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"500"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Syntax error; command unrecognized"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"501"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Syntax error in parameters or arguments"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"502"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Command not implemented"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"503"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Bad sequence of commands"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"504"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Command parameter not implemented"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"550"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Mailbox unavailable / policy / access denied (permanent failure)"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"551"</span><span class="p">,</span><span class="w"> </span><span class="s2">"User not local; please try forwarding address"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"552"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Storage allocation exceeded (mailbox full or message too large)"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"553"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Mailbox name not allowed / invalid recipient"</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"554"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Transaction failed (often policy/content rejection)"</span><span class="p">,</span><span class="w">
</span><span class="n">isempty</span><span class="p">(</span><span class="n">SmtpStatusCode</span><span class="p">),</span><span class="w"> </span><span class="s2">"Unknown / not provided"</span><span class="p">,</span><span class="w">
</span><span class="nb">strcat</span><span class="p">(</span><span class="s2">"Unmapped SMTP code: "</span><span class="p">,</span><span class="w"> </span><span class="n">SmtpStatusCode</span><span class="p">)</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">EnhancedSmtpStatusCodeDetails</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">case</span><span class="p">(</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"<not applicable>"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Not applicable (Delivered)"</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"5.1.1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Bad destination mailbox address (recipient doesn't exist)"</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"5.1.0"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Bad destination mailbox address"</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"5.2.2"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Mailbox full"</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"5.2.1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Mailbox disabled / not accepting mail"</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"5.4.1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Cannot route / no answer from host / destination routing issue"</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"5.7.1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Rejected by policy (SPF/DKIM/DMARC/reputation/policy)"</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"4.7.1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Temporary policy/reputation issue; retry expected"</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"4.4.1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Connection timed out / temporary network issue; retry expected"</span><span class="p">,</span><span class="w">
</span><span class="n">isempty</span><span class="p">(</span><span class="n">EnhancedSmtpStatusCode</span><span class="p">),</span><span class="w"> </span><span class="s2">"Unknown / not provided"</span><span class="p">,</span><span class="w">
</span><span class="nb">strcat</span><span class="p">(</span><span class="s2">"Unmapped enhanced code: "</span><span class="p">,</span><span class="w"> </span><span class="n">EnhancedSmtpStatusCode</span><span class="p">)</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">project</span><span class="w">
</span><span class="n">MessageId</span><span class="p">,</span><span class="w">
</span><span class="n">InternetMessageId</span><span class="p">,</span><span class="w">
</span><span class="n">RecipientId</span><span class="p">,</span><span class="w">
</span><span class="n">RecipientDomain</span><span class="p">,</span><span class="w">
</span><span class="n">SenderUsername</span><span class="p">,</span><span class="w">
</span><span class="n">SenderDomain</span><span class="p">,</span><span class="w">
</span><span class="n">FinalDeliveryStatus</span><span class="p">,</span><span class="w">
</span><span class="n">BounceType</span><span class="p">,</span><span class="w">
</span><span class="n">SendTime</span><span class="p">,</span><span class="w">
</span><span class="n">FinalStatusTime</span><span class="p">,</span><span class="w">
</span><span class="n">DurationSeconds</span><span class="p">,</span><span class="w">
</span><span class="n">DurationMilliseconds</span><span class="p">,</span><span class="w">
</span><span class="n">MessageSize</span><span class="p">,</span><span class="w">
</span><span class="n">MessageSizeCategory</span><span class="p">,</span><span class="w">
</span><span class="n">AttachmentsCount</span><span class="p">,</span><span class="w">
</span><span class="n">ToRecipientsCount</span><span class="p">,</span><span class="w">
</span><span class="n">CcRecipientsCount</span><span class="p">,</span><span class="w">
</span><span class="n">BccRecipientsCount</span><span class="p">,</span><span class="w">
</span><span class="n">UniqueRecipientsCount</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCode</span><span class="p">,</span><span class="w">
</span><span class="n">SmtpStatusCodeDetails</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCode</span><span class="p">,</span><span class="w">
</span><span class="n">EnhancedSmtpStatusCodeDetails</span><span class="p">,</span><span class="w">
</span><span class="n">FailureReason</span><span class="p">,</span><span class="w">
</span><span class="n">FailureMessage</span><span class="p">,</span><span class="w">
</span><span class="n">RecipientMailServerHostName</span><span class="p">,</span><span class="w">
</span><span class="n">_ResourceId</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">order</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">SendTime</span><span class="w"> </span><span class="k">desc</span><span class="w">
</span></code></pre></div></div>
<hr />
<h2 id="️-delivery-latency-measurement">⏱️ Delivery Latency Measurement</h2>
<p>The query calculates delivery latency using:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">SendTime</code> (from send logs)</li>
<li><code class="language-plaintext highlighter-rouge">FinalStatusTime</code> (from status logs)</li>
</ul>
<p>It then derives:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">DurationMilliseconds</code></li>
<li><code class="language-plaintext highlighter-rouge">DurationSeconds</code></li>
</ul>
<p>This makes it easy to:</p>
<ul>
<li>Identify delayed deliveries</li>
<li>Compare performance across recipient domains</li>
<li>Spot transient vs. systemic delays</li>
</ul>
<hr />
<h2 id="-message-characteristics-and-size-handling">📦 Message Characteristics and Size Handling</h2>
<p>One common pitfall is assuming the ACS <code class="language-plaintext highlighter-rouge">Size</code> field is reported in bytes.</p>
<p><strong>It is not.</strong></p>
<p>This query correctly treats <code class="language-plaintext highlighter-rouge">Size</code> as <strong>megabytes (MB)</strong> and adds:</p>
<ul>
<li>A <code class="language-plaintext highlighter-rouge">MessageSizeCategory</code> field:
<ul>
<li>Tiny (<100KB)</li>
<li>Small (100KB–1MB)</li>
<li>Medium (1–5MB)</li>
<li>Large (5–10MB)</li>
<li>Very Large (>10MB)</li>
</ul>
</li>
</ul>
<p>Combined with attachment and recipient counts, this helps identify:</p>
<ul>
<li>Messages that may trigger size-based rejections</li>
<li>Large fan-out sends with higher delivery latency</li>
</ul>
<p><strong>Note:</strong> ACS has a default maximum email size of 10MB (including attachments), though this can be increased to 30MB via support request. Messages exceeding limits will fail before logging.</p>
<hr />
<h2 id="-bounce-classification">💥 Bounce Classification</h2>
<p>The query explicitly categorizes bounce behavior:</p>
<ul>
<li><strong>Hard Bounce</strong> – permanent failure (invalid mailbox, policy block, etc.)</li>
<li><strong>Soft Bounce</strong> – temporary failure (mailbox full, throttling, transient policy)</li>
<li><strong>Not Applicable</strong> – delivered successfully</li>
</ul>
<p>This makes it trivial to separate:</p>
<ul>
<li>Retry-worthy failures</li>
<li>Permanent delivery issues</li>
<li>Clean deliveries</li>
</ul>
<hr />
<h2 id="-smtp-and-enhanced-smtp-code-translation">📜 SMTP and Enhanced SMTP Code Translation</h2>
<p>Raw SMTP codes are not very helpful on their own.</p>
<p>This query maps:</p>
<ul>
<li>Standard SMTP status codes (e.g., <code class="language-plaintext highlighter-rouge">550</code>, <code class="language-plaintext highlighter-rouge">554</code>)</li>
<li>Enhanced SMTP status codes (e.g., <code class="language-plaintext highlighter-rouge">5.1.1</code>, <code class="language-plaintext highlighter-rouge">5.7.1</code>)</li>
</ul>
<p>Into <strong>clear, human-readable explanations</strong>, such as:</p>
<ul>
<li><em>“Bad destination mailbox address (recipient doesn’t exist)”</em></li>
<li><em>“Rejected by policy (SPF/DKIM/DMARC/reputation)”</em></li>
<li><em>“Temporary network issue; retry expected”</em></li>
</ul>
<p>Delivered messages automatically show:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge"><not applicable></code> for SMTP fields</li>
</ul>
<p>This removes ambiguity and speeds up root-cause analysis.</p>
<hr />
<h2 id="-recipient-and-server-intelligence">🌐 Recipient and Server Intelligence</h2>
<p>The query extracts and surfaces:</p>
<ul>
<li>Recipient domain</li>
<li>Recipient mail server hostname</li>
<li>InternetMessageId</li>
</ul>
<p>This allows you to:</p>
<ul>
<li>Group failures by destination domain</li>
<li>Identify problematic recipient mail systems</li>
<li>Correlate ACS activity with external mail logs or SIEM data</li>
</ul>
<hr />
<h2 id="-common-usage-patterns">🎯 Common Usage Patterns</h2>
<h3 id="filter-by-specific-sender">Filter by Specific Sender</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">SenderUsername</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"[email protected]"</span><span class="w">
</span></code></pre></div></div>
<h3 id="find-all-bounces-to-a-specific-domain">Find All Bounces to a Specific Domain</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">RecipientDomain</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"gmail.com"</span><span class="w"> </span><span class="k">and</span><span class="w"> </span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Bounced"</span><span class="w">
</span></code></pre></div></div>
<h3 id="identify-slow-deliveries-10-seconds">Identify Slow Deliveries (>10 seconds)</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">DurationSeconds</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mf">10</span><span class="w"> </span><span class="k">and</span><span class="w"> </span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Delivered"</span><span class="w">
</span></code></pre></div></div>
<h3 id="messages-with-large-size-or-attachments">Messages with Large Size or Attachments</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">MessageSize</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mf">5.0</span><span class="w"> </span><span class="k">or</span><span class="w"> </span><span class="n">AttachmentsCount</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mf">0</span><span class="w">
</span></code></pre></div></div>
<h3 id="all-hard-bounces-in-last-24-hours">All Hard Bounces in Last 24 Hours</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">BounceType</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Hard Bounce"</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">SendTime</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="nb">ago</span><span class="p">(</span><span class="n">24h</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<hr />
<h2 id="-aggregation-examples-for-dashboards">📊 Aggregation Examples for Dashboards</h2>
<h3 id="delivery-success-rate-by-recipient-domain">Delivery Success Rate by Recipient Domain</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add this to the end of the base query</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">summarize</span><span class="w">
</span><span class="n">Total</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">count</span><span class="p">(),</span><span class="w">
</span><span class="n">Delivered</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">countif</span><span class="p">(</span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Delivered"</span><span class="p">),</span><span class="w">
</span><span class="n">Bounced</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">countif</span><span class="p">(</span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Bounced"</span><span class="p">)</span><span class="w">
</span><span class="k">by</span><span class="w"> </span><span class="n">RecipientDomain</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">SuccessRate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">round</span><span class="p">(</span><span class="mf">100.0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Delivered</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">Total</span><span class="p">,</span><span class="w"> </span><span class="mf">2</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">order</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">Total</span><span class="w"> </span><span class="k">desc</span><span class="w">
</span></code></pre></div></div>
<h3 id="average-delivery-time-by-hour">Average Delivery Time by Hour</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add this to the end of the base query</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Delivered"</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">summarize</span><span class="w"> </span><span class="n">AvgDeliverySeconds</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">avg</span><span class="p">(</span><span class="n">DurationSeconds</span><span class="p">)</span><span class="w">
</span><span class="k">by</span><span class="w"> </span><span class="nb">bin</span><span class="p">(</span><span class="n">SendTime</span><span class="p">,</span><span class="w"> </span><span class="n">1h</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">render</span><span class="w"> </span><span class="n">timechart</span><span class="w">
</span></code></pre></div></div>
<h3 id="top-failure-reasons">Top Failure Reasons</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add this to the end of the base query</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">FinalDeliveryStatus</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s2">"Delivered"</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">summarize</span><span class="w"> </span><span class="k">Count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">count</span><span class="p">()</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">FailureReason</span><span class="p">,</span><span class="w"> </span><span class="n">EnhancedSmtpStatusCodeDetails</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">order</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="k">Count</span><span class="w"> </span><span class="k">desc</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">take</span><span class="w"> </span><span class="mf">10</span><span class="w">
</span></code></pre></div></div>
<h3 id="bounce-rate-by-sender">Bounce Rate by Sender</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add this to the end of the base query</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">summarize</span><span class="w">
</span><span class="n">TotalSent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">count</span><span class="p">(),</span><span class="w">
</span><span class="n">HardBounces</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">countif</span><span class="p">(</span><span class="n">BounceType</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Hard Bounce"</span><span class="p">),</span><span class="w">
</span><span class="n">SoftBounces</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">countif</span><span class="p">(</span><span class="n">BounceType</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"Soft Bounce"</span><span class="p">)</span><span class="w">
</span><span class="k">by</span><span class="w"> </span><span class="n">SenderUsername</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">HardBounceRate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">round</span><span class="p">(</span><span class="mf">100.0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">HardBounces</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">TotalSent</span><span class="p">,</span><span class="w"> </span><span class="mf">2</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">order</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">HardBounceRate</span><span class="w"> </span><span class="k">desc</span><span class="w">
</span></code></pre></div></div>
<h3 id="message-size-distribution">Message Size Distribution</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add this to the end of the base query</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">summarize</span><span class="w"> </span><span class="k">Count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">count</span><span class="p">()</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">MessageSizeCategory</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">render</span><span class="w"> </span><span class="n">piechart</span><span class="w">
</span></code></pre></div></div>
<hr />
<h2 id="️-limitations--known-issues">⚠️ Limitations & Known Issues</h2>
<h3 id="subject-lines-are-not-available">Subject Lines Are Not Available</h3>
<p>Azure Communication Services does not log email subject lines or body content in diagnostic logs for privacy and security reasons. Only metadata (sender, recipient, size, status codes) is captured.</p>
<p>If you need to track subjects, implement custom logging in your application before sending:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Example: Log subject before sending</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">LogInformation</span><span class="p">(</span><span class="s">"Sending email - MessageId: {messageId}, Subject: {subject}"</span><span class="p">,</span>
<span class="n">correlationId</span><span class="p">,</span> <span class="n">emailMessage</span><span class="p">.</span><span class="n">Subject</span><span class="p">);</span>
</code></pre></div></div>
<h3 id="ishardbounce-casing">IsHardBounce Casing</h3>
<p>The <code class="language-plaintext highlighter-rouge">IsHardBounce</code> field returns <strong>“True”/”False”</strong> (capital T/F), not “true”/”false”. The query handles this with case-insensitive comparison using <code class="language-plaintext highlighter-rouge">tolower()</code>.</p>
<h3 id="time-range-performance">Time Range Performance</h3>
<p>For optimal performance on large datasets, limit queries to specific time ranges (e.g., last 24-48 hours) rather than scanning all historical data. Add this at the start:</p>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">TimeGenerated</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="nb">ago</span><span class="p">(</span><span class="n">24h</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<h3 id="correlation-timing">Correlation Timing</h3>
<p>The query filters for <code class="language-plaintext highlighter-rouge">FinalStatusTime >= SendTime</code> to ensure logical ordering. In rare cases where clock skew exists, some records may be excluded.</p>
<hr />
<h2 id="-when-to-use-this-query">🧪 When to Use This Query</h2>
<p>This query is ideal for:</p>
<ul>
<li>Investigating bounced or delayed emails</li>
<li>Analyzing delivery performance trends</li>
<li>Supporting customer escalations</li>
<li>Validating ACS email configuration</li>
<li>Understanding policy-based rejections</li>
<li>Building workbooks or dashboards for email observability</li>
<li>Identifying problematic recipient domains or mail servers</li>
</ul>
<hr />
<h2 id="-next-steps">🚀 Next Steps</h2>
<p>Now that you have the query, here are some ways to extend it:</p>
<ol>
<li><strong>Create an Azure Workbook</strong> – Build interactive dashboards using this query as a data source</li>
<li><strong>Set Up Alerts</strong> – Create alerts for high bounce rates, delivery latency spikes, or specific failure patterns</li>
<li><strong>Join with Application Logs</strong> – Use <code class="language-plaintext highlighter-rouge">MessageId</code> or <code class="language-plaintext highlighter-rouge">InternetMessageId</code> to correlate with your application’s custom logging</li>
<li><strong>Export to Power BI</strong> – For long-term trend analysis and executive reporting</li>
<li><strong>Integrate with SIEM</strong> – Feed results into Azure Sentinel or third-party SIEM tools</li>
</ol>
<hr />
<h2 id="-related-resources">📚 Related Resources</h2>
<ul>
<li><a href="https://learn.microsoft.com/en-us/azure/communication-services/concepts/email/email-overview">Azure Communication Services Email Documentation</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/acsemailsendmailoperational">ACSEmailSendMailOperational Table Reference</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/acsemailstatusupdateoperational">ACSEmailStatusUpdateOperational Table Reference</a></li>
<li><a href="https://datatracker.ietf.org/doc/html/rfc5321#section-4.2">SMTP Status Codes (RFC 5321)</a></li>
<li><a href="https://datatracker.ietf.org/doc/html/rfc3463">Enhanced SMTP Status Codes (RFC 3463)</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/">Azure Monitor KQL Reference</a></li>
</ul>
<hr />
<h2 id="-final-thoughts">🧠 Final Thoughts</h2>
<p>Azure Communication Services provides excellent email diagnostics — but the real power comes from <strong>correlating and enriching that data</strong>.</p>
<p>This KQL query turns raw ACS logs into a structured, actionable dataset that answers the questions customers actually ask:</p>
<ul>
<li><em>What happened to my email?</em></li>
<li><em>Why did it fail?</em></li>
<li><em>How long did it take?</em></li>
<li><em>Is this temporary or permanent?</em></li>
</ul>
<p>If you work with ACS Email regularly, this query is a strong foundation for troubleshooting, reporting, and long-term monitoring.</p>
<p>Feel free to adapt, extend, and share this query with your team. Happy troubleshooting! 🎉</p>
<hr />
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/acs-email-delivery-analysis-kql/" alt="Page Views" /></p>
February 10, 2026
https://blakedrumm.com/blog/acs-email-delivery-analysis-kql/
https://blakedrumm.com/blog/acs-email-delivery-analysis-kql/Custom IAM Roles Are Not Supported - Azure Communication Services (ACS)/assets/img/posts/acs-custom-iam-roles-not-supported.png<h2 id="-introduction">💡 Introduction</h2>
<p>When deploying or securing Azure Communication Services (ACS), it’s natural to want to follow least-privilege access principles by creating custom IAM (RBAC) roles.</p>
<p>This is especially common when customers want to:</p>
<ul>
<li>Separate operational access from administrative access</li>
<li>Grant narrowly scoped permissions to applications or automation</li>
<li>Avoid over-assigning built-in roles</li>
</ul>
<p>However, Azure Communication Services behaves differently than many other Azure resource providers, and this often leads to confusion during role design.</p>
<hr />
<h2 id="-the-issue">🔐 The Issue</h2>
<p>A customer attempted to create and assign a custom IAM role for an Azure Communication Services resource.</p>
<p>The goal was to grant limited permissions for managing or interacting with ACS without assigning a broad built-in role.</p>
<p>Despite the role being created successfully in Azure, it did not function as expected when assigned to users or service principals.</p>
<hr />
<h2 id="-the-root-cause">🔍 The Root Cause</h2>
<p>Custom IAM roles are not supported for Azure Communication Services.</p>
<p>While Azure allows you to define custom roles at a subscription or resource scope, ACS does not honor custom role definitions, even if the permissions appear valid.</p>
<p>This means:</p>
<ul>
<li>Custom roles may assign successfully</li>
<li>Role assignments appear correct in the portal</li>
<li>Access attempts still fail at runtime</li>
</ul>
<p>This is not a configuration issue or a customer mistake. It is a platform limitation.</p>
<hr />
<h2 id="-the-resolution">✅ The Resolution</h2>
<p>To manage or interact with Azure Communication Services, you must use a predefined built-in role.</p>
<h3 id="-required-built-in-role">✔ Required Built-In Role</h3>
<p>Communication and Email Service Owner</p>
<p>This role provides the permissions required to:</p>
<ul>
<li>Manage ACS resources</li>
<li>Access keys and endpoints</li>
<li>Configure calling, SMS, email, and related features</li>
</ul>
<p>At this time, there is no supported alternative that allows partial or custom permission sets for ACS.</p>
<hr />
<h2 id="️-important-notes-about-acs-rbac">⚠️ Important Notes About ACS RBAC</h2>
<p>Here are a few important behaviors to be aware of when working with ACS permissions:</p>
<ul>
<li>ACS does not support custom RBAC roles</li>
<li>DataActions are not exposed or configurable for ACS</li>
<li>Least-privilege designs are limited to built-in roles only</li>
<li>Role assignments must be validated using real API calls, not just portal visibility</li>
</ul>
<p>This can be surprising if you’re used to other Azure services that fully support custom role definitions.</p>
<hr />
<h2 id="-design-guidance">🧭 Design Guidance</h2>
<p>If you need separation of duties or reduced blast radius, consider these alternatives:</p>
<ul>
<li>Use separate ACS resources per environment or workload</li>
<li>Assign the built-in role only to dedicated service principals</li>
<li>Scope access tightly at the resource level, not subscription-wide</li>
<li>Use Azure Monitor and diagnostics to audit usage instead of restricting permissions</li>
</ul>
<p>While not ideal, these approaches align with the current ACS security model.</p>
<hr />
<h2 id="-final-thoughts">🧠 Final Thoughts</h2>
<p>Azure Communication Services has a powerful feature set, but its RBAC model is intentionally constrained today. Attempting to use custom IAM roles will lead to confusing access failures that are difficult to troubleshoot unless this limitation is known upfront.</p>
<p>If you encounter authorization issues with ACS:</p>
<ul>
<li>Verify the role is <strong>Communication and Email Service Owner</strong></li>
<li>Do not rely on custom role definitions</li>
<li>Validate access using real SDK or REST calls</li>
</ul>
<p>If this behavior changes in the future, it will require a platform update from the ACS product group.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/acs-custom-iam-roles-not-supported/" alt="Page Views" /></p>
January 20, 2026
https://blakedrumm.com/blog/acs-custom-iam-roles-not-supported/
https://blakedrumm.com/blog/acs-custom-iam-roles-not-supported/Outbound Calling with a Lightweight Console Tool - Azure Communication Services (ACS)/assets/img/posts/acs-outbound-calling-tool.png<h2 id="bulb-introduction">:bulb: Introduction</h2>
<p>Azure Communication Services (ACS) provides powerful APIs for building telephony workflows — from simple outbound calls to fully automated IVR systems. But when you’re validating a new ACS deployment, troubleshooting access keys, or checking if a purchased phone number is correctly configured, you often need something much simpler:</p>
<p><strong>A tool that can place a real outbound PSTN call on demand.</strong></p>
<p>To streamline that process, I created a small <strong>C# console application</strong> that uses the ACS Call Automation API to place a call from an ACS-owned phone number to any valid target phone number. This post provides an overview of how the tool works, why it exists, and what to know when using ACS programmatically for calling.</p>
<hr />
<h2 id="telephone_receiver-why-build-a-tool-for-acs-outbound-calling">:telephone_receiver: Why Build a Tool for ACS Outbound Calling?</h2>
<p>When helping customers troubleshoot ACS calling issues, one of the most common challenges is isolating whether a problem is:</p>
<ul>
<li>a misconfigured ACS resource</li>
<li>an invalid or inactive phone number</li>
<li>a missing callback endpoint</li>
<li>incorrect API usage</li>
<li>version mismatch in the SDK</li>
<li>firewall or networking issues blocking callbacks</li>
</ul>
<p>A lightweight console caller removes all other moving parts so you can focus on validating:</p>
<ul>
<li>✔ The ACS resource is reachable</li>
<li>✔ The access key is correct</li>
<li>✔ The Call Automation API accepts your request</li>
<li>✔ The ACS phone number is capable of PSTN outbound traffic</li>
<li>✔ Call events are flowing to the configured callback URL (if applicable)</li>
</ul>
<p>It’s the ACS equivalent of <strong>“ping” for telephony</strong> — quick, simple, and reliable.</p>
<hr />
<h2 id="mag-understanding-acs-callautomation-behavior">:mag: Understanding ACS CallAutomation Behavior</h2>
<p>One important part of building this tool was understanding how ACS behaves across SDK versions. The <strong>CreateCall</strong> API:</p>
<ul>
<li><strong>Does not provide real-time call status</strong></li>
<li><strong>Does not block while waiting for the call to be answered</strong></li>
<li><strong>Does not include a call state object in the response</strong></li>
</ul>
<p>Instead, ACS gives you:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">CallConnectionId</code></li>
</ul>
<p>These identifiers uniquely represent the server-side call object and can be used:</p>
<ul>
<li>to correlate logs</li>
<li>to track call events</li>
<li>inside Call Automation actions (hang up, play audio, etc.)</li>
<li>for troubleshooting in Azure Monitor or diagnostics views</li>
</ul>
<p>Any real-time events — like CallConnected or CallDisconnected — are always delivered asynchronously to your configured <strong>callback URL</strong>, not through the tool itself.</p>
<p>This design is intentional and foundational to ACS at scale.</p>
<hr />
<h2 id="gear-what-the-tool-does">:gear: What the Tool Does</h2>
<p>The console tool performs the following steps:</p>
<ol>
<li><strong>Accepts two command-line parameters</strong>:
<ul>
<li>ACS source phone number</li>
<li>Target PSTN phone number</li>
</ul>
</li>
<li>
<p><strong>Creates a CallAutomationClient</strong> using your ACS connection string.</p>
</li>
<li>
<p><strong>Builds a CallInvite</strong> using the source and target numbers.</p>
</li>
<li>
<p><strong>Sends a CreateCall request</strong> to the ACS endpoint.</p>
</li>
<li>
<p><strong>Prints the CallConnectionId and ServerCallId</strong> returned by ACS.</p>
</li>
<li><strong>Exits immediately</strong> — because ACS handles all call progression asynchronously.</li>
</ol>
<h3 id="what-its-ideal-for">What It’s Ideal For</h3>
<ul>
<li>Verifying ACS outbound calling works</li>
<li>Testing newly purchased phone numbers</li>
<li>Troubleshooting 401/403/BadRequest failures</li>
<li>Ensuring your ACS access key is correct</li>
<li>Validating resource deployment issues</li>
<li>Proving connectivity before building more complex automation</li>
</ul>
<h3 id="what-its-not-designed-for">What It’s <em>Not</em> Designed For</h3>
<ul>
<li>Monitoring call state in real-time</li>
<li>Handling media, DTMF, or recording</li>
<li>Complete IVR or call-flow logic</li>
<li>Replacing full Call Automation workflows</li>
</ul>
<p>This tool is intentionally focused and minimal.</p>
<hr />
<h2 id="electric_plug-callback-url-requirements">:electric_plug: Callback URL Requirements</h2>
<p>ACS requires a <strong>public callback endpoint</strong> for call events. This is used to deliver:</p>
<ul>
<li>CallConnected</li>
<li>ParticipantsUpdated</li>
<li>CallDisconnected</li>
<li>Media events</li>
</ul>
<p>Even if you aren’t using callbacks yet, the <code class="language-plaintext highlighter-rouge">callbackUri</code> must be:</p>
<ul>
<li>a valid URI</li>
<li>publicly accessible</li>
<li>HTTPS recommended</li>
</ul>
<p>If you’re just validating call initiation, you can temporarily specify a placeholder endpoint.<br />
For full automation, you’ll want a real listener (Azure Functions, App Service, Ngrok, etc.).</p>
<hr />
<h2 id="warning-common-issues-when-testing-acs-calls">:warning: Common Issues When Testing ACS Calls</h2>
<p>Here are some real-world issues I’ve seen while helping customers:</p>
<h3 id="-401-unauthorized">❌ 401 Unauthorized</h3>
<p>Typically caused by:</p>
<ul>
<li>Incorrect access key</li>
<li>Expired regenerated key not updated in code</li>
<li>Wrong endpoint region</li>
</ul>
<h3 id="-403-forbidden">❌ 403 Forbidden</h3>
<p>Usually means:</p>
<ul>
<li>The ACS phone number is not enabled for PSTN</li>
<li>Phone number is missing from the resource</li>
<li>You’re calling a restricted destination</li>
</ul>
<h3 id="-call-never-arrives">❌ Call never arrives</h3>
<p>Often due to:</p>
<ul>
<li>Incorrect E.164 formatting (ACS is strict)</li>
<li>Callback endpoint unreachable</li>
<li>Resource not provisioned for PSTN</li>
</ul>
<p>The console tool makes diagnosing these issues much easier — if an outbound call fails, the response error tells you <em>why</em>.</p>
<hr />
<h2 id="floppy_disk-download-the-tool">:floppy_disk: Download the Tool</h2>
<p>You can download the tool or review the source code here:</p>
<blockquote>
<p>🔗 <strong>Download the ACS Outbound Calling Tool Executable</strong><br />
<a href="https://files.blakedrumm.com/ACS-CallExample-Console-Executable.zip">https://files.blakedrumm.com/ACS-CallExample-Console-Executable.zip</a></p>
</blockquote>
<blockquote>
<p>🔗 <strong>Source Code Repository</strong><br />
<a href="https://github.com/blakedrumm/ACS-CallExample-Console">https://github.com/blakedrumm/ACS-CallExample-Console</a></p>
</blockquote>
<p>Feel free to fork it, extend it, or incorporate it into your own automation workflows.</p>
<hr />
<h2 id="speech_balloon-final-thoughts">:speech_balloon: Final Thoughts</h2>
<p>Azure Communication Services is extremely powerful once you understand its event-driven architecture. Tools like this console caller make it easier to validate your environment, test scenarios quickly, and remove uncertainty during deployments.</p>
<p>If you’re working with ACS and need help diagnosing issues or extending call workflows, feel free to reach out — I’m always happy to help troubleshoot or share lessons learned.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/acs-outbound-calling-tool/" alt="Page Views" /></p>
December 5, 2025
https://blakedrumm.com/blog/acs-outbound-calling-tool/
https://blakedrumm.com/blog/acs-outbound-calling-tool/Cleaning Orphaned WindowsPatchExtension Status Files - Azure Update Manager/assets/img/posts/windows-patch-extension-status-cleanup.png<h2 id="bulb-introduction">:bulb: Introduction</h2>
<p>While helping customers troubleshoot patching issues with <strong>Azure Update Manager</strong>, I ran into a recurring problem—leftover <code class="language-plaintext highlighter-rouge">.status</code> files from the <strong>WindowsPatchExtension</strong>.</p>
<p>These orphaned files can confuse log analysis and clutter VMs over time. This blog post explains how they get there, why they matter, and how to clean them up using a simple PowerShell script.</p>
<hr />
<h2 id="mag-the-problem--orphaned-status-files">:mag: The Problem — Orphaned <code class="language-plaintext highlighter-rouge">.status</code> Files</h2>
<p>When the <code class="language-plaintext highlighter-rouge">WindowsPatchExtension</code> runs, it generates <code class="language-plaintext highlighter-rouge">.settings</code> and <code class="language-plaintext highlighter-rouge">.status</code> files in the following directories:</p>
<ul>
<li>
<p><strong>Settings Path</strong><br />
<code class="language-plaintext highlighter-rouge">C:\Packages\Plugins\Microsoft.CPlat.Core.WindowsPatchExtension\<version>\RuntimeSettings</code></p>
</li>
<li>
<p><strong>Status Path</strong><br />
<code class="language-plaintext highlighter-rouge">C:\Packages\Plugins\Microsoft.CPlat.Core.WindowsPatchExtension\<version>\status</code></p>
</li>
</ul>
<p>Under normal conditions, these files are created and removed together. But if patching is interrupted, retried, or a new version of the extension is installed, some <code class="language-plaintext highlighter-rouge">.status</code> files may remain—even if they no longer correspond to a <code class="language-plaintext highlighter-rouge">.settings</code> file.</p>
<h3 id="warning-real-world-scenario">:warning: Real-World Scenario</h3>
<p>In a recent case, the customer deployed VMs from a <strong>custom image</strong> that already had the <code class="language-plaintext highlighter-rouge">WindowsPatchExtension</code> installed. The image unknowingly <strong>included stale <code class="language-plaintext highlighter-rouge">.status</code> files</strong>, which then propagated to every new VM built from that image.</p>
<p>This mismatch between <code class="language-plaintext highlighter-rouge">.settings</code> and <code class="language-plaintext highlighter-rouge">.status</code> files caused confusion during patch runs, where the extension logs no longer lined up with the expected state.</p>
<hr />
<h2 id="thinking-why-this-matters">:thinking: Why This Matters</h2>
<p>These orphaned <code class="language-plaintext highlighter-rouge">.status</code> files:</p>
<ul>
<li>❌ Do <strong>not</strong> represent the current patch status</li>
<li>🤔 Can cause confusion when checking plugin behavior</li>
<li>🧹 Accumulate over time and clutter the file system</li>
</ul>
<p>While they don’t break the extension’s functionality, they make troubleshooting harder—especially when using automation or analyzing logs across many VMs.</p>
<hr />
<h2 id="wrench-the-fix--compare-and-clean-with-powershell">:wrench: The Fix — Compare and Clean with PowerShell</h2>
<p>To resolve this, I wrote a <a href="https://gist.github.com/blakedrumm/62a572ddc786963136641b2c52894211" target="_blank">PowerShell script</a> that compares <code class="language-plaintext highlighter-rouge">.status</code> and <code class="language-plaintext highlighter-rouge">.settings</code> file indexes and deletes any <code class="language-plaintext highlighter-rouge">.status</code> files that don’t match.</p>
<h3 id="what-it-does">What It Does</h3>
<ol>
<li>Finds the highest-index <code class="language-plaintext highlighter-rouge">.settings</code> file in the RuntimeSettings folder</li>
<li>Deletes any <code class="language-plaintext highlighter-rouge">.status</code> files with a <strong>higher index</strong></li>
</ol>
<p>This keeps only the relevant <code class="language-plaintext highlighter-rouge">.status</code> files and ensures consistency.</p>
<hr />
<h2 id="floppy_disk-how-to-use-the-script">:floppy_disk: How to Use the Script</h2>
<blockquote>
<p>🔗 <strong>Script Link</strong>: <a href="https://gist.github.com/blakedrumm/62a572ddc786963136641b2c52894211" target="_blank">PowerShell Gist - Cleanup Status Files</a></p>
</blockquote>
<blockquote>
<p><strong>Disclaimer</strong>: Always test in a development environment before applying to production.</p>
</blockquote>
<h3 id="1-save-the-script-locally">1. Save the Script Locally</h3>
<p>Save the content of the Gist above as a <code class="language-plaintext highlighter-rouge">.ps1</code> file on your VM:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Remove-UpdateManagerOldStatusFiles.ps1</span><span class="w">
</span></code></pre></div></div>
<h3 id="2-run-powershell-as-administrator">2. Run PowerShell as Administrator</h3>
<p>Because the script accesses protected directories, you must run it with admin rights.</p>
<ul>
<li>Right-click <strong>PowerShell</strong> → <strong>Run as Administrator</strong></li>
</ul>
<h3 id="3-execute-the-script">3. Execute the Script</h3>
<p>Navigate to the script location and run:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Remove-UpdateManagerOldStatusFiles.ps1</span><span class="w">
</span></code></pre></div></div>
<p>The script will:</p>
<ul>
<li>Detect the latest version of the <code class="language-plaintext highlighter-rouge">WindowsPatchExtension</code></li>
<li>Find the highest <code class="language-plaintext highlighter-rouge">.settings</code> file</li>
<li>Remove <code class="language-plaintext highlighter-rouge">.status</code> files with a <strong>higher index</strong></li>
</ul>
<p>You’ll get output confirming what (if anything) was removed.</p>
<hr />
<h2 id="speech_balloon-share-your-experience">:speech_balloon: Share Your Experience</h2>
<p>Have you encountered similar cleanup scenarios with the WindowsPatchExtension or Update Manager?<br />
Did you solve it a different way?</p>
<p>Let me know! I’m always interested in how others handle extension state management at scale.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/azure-update-manager-status-cleanup/" alt="Page Views" /></p>
June 18, 2025
https://blakedrumm.com/blog/azure-update-manager-status-cleanup/
https://blakedrumm.com/blog/azure-update-manager-status-cleanup/Setup OpenWeb UI AI Webpage - Azure Container Apps/assets/img/posts/openweb-ui-logged-in.png<h2 id="bulb-introduction">:bulb: Introduction</h2>
<p>Deploying OpenWeb UI on Azure allows you to host an interactive AI webpage. However, due to OpenWeb UI’s architecture—where both the frontend and backend are housed in a single container—scalability is limited. This guide will walk you through setting up OpenWeb UI using Azure Container Apps, discuss its limitations regarding scaling, and compare this solution to using Kubernetes.</p>
<h2 id="hammer-prerequisites">:hammer: Prerequisites</h2>
<p>Before starting, make sure you have the following:</p>
<ul>
<li><strong>Azure Account</strong>: An active Azure subscription with permissions to create new resources.</li>
<li><strong>OpenWeb UI Container Image</strong>: The container image from GitHub Container Registry (<code class="language-plaintext highlighter-rouge">ghcr.io/open-webui/open-webui:main</code>).</li>
<li><strong>OpenAI API Key</strong>: [Optional] In order to utilize OpenAI in OpenWeb UI, you will need an OpenAI API Key. <a href="https://platform.openai.com/api-keys">https://platform.openai.com/api-keys</a></li>
</ul>
<h2 id="rocket-setting-up-openweb-ui-with-azure-container-apps">:rocket: Setting Up OpenWeb UI with Azure Container Apps</h2>
<h3 id="step-by-step-guide-portal">Step-by-Step Guide (Portal)</h3>
<h4 id="1-access-the-azure-portal">1. <strong>Access the Azure Portal</strong></h4>
<p>Log in to <a href="https://portal.azure.com/" target="_blank">Azure Portal</a>.</p>
<h4 id="2-create-a-resource-group">2. <strong>Create a Resource Group</strong></h4>
<ul>
<li>Search for <strong>Resource groups</strong> and create a new one named <code class="language-plaintext highlighter-rouge">OpenWebUI-ContainerApp-RG</code>.</li>
<li>Select a region like <strong>East US</strong> be sure you are consistent with the region through this guide.</li>
</ul>
<h4 id="3-create-a-storage-account">3. <strong>Create a Storage Account</strong></h4>
<ul>
<li>Search for <strong>Storage accounts</strong>, create a new one (For example: <code class="language-plaintext highlighter-rouge">openwebuistorageaccount</code> (lowercase required)) in the <code class="language-plaintext highlighter-rouge">OpenWebUI-ContainerApp-RG</code> resource group.
<ul>
<li>
<p>During creation of the Storage account there are configuration changes required:</p>
<ul>
<li><strong><u>Basics tab</u></strong>
<ol>
<li><strong>Primary service</strong> select <code class="language-plaintext highlighter-rouge">Azure Files</code>.</li>
<li><strong>Performance</strong> you can set <code class="language-plaintext highlighter-rouge">Standard</code> unless you have a specific need for <code class="language-plaintext highlighter-rouge">Premium</code>.</li>
<li><strong>Redundancy</strong> you can set <code class="language-plaintext highlighter-rouge">Locally-redundant storage (LRS)</code> unless you have a specific need for the other options.</li>
</ol>
</li>
<li><strong><u>Networking tab</u></strong>
<ol>
<li><strong>Network access</strong> select <code class="language-plaintext highlighter-rouge">Enable public access from all networks</code> (default option) unless you have a specific need for the other options (the other options require additional configuration which will not be covered in this guide).</li>
</ol>
</li>
<li><strong><u>Other tabs</u></strong>
<ol>
<li>Leave the defaults and create the storage account.</li>
</ol>
</li>
</ul>
</li>
<li>
<p><em>After</em> the storage account is created there are additional steps required:</p>
<ol>
<li>Search for <strong>Storage accounts</strong>. Locate the storage account (<strong><em>openwebuistorageaccount</em></strong>) and select it.</li>
<li>Expand <strong>Data storage</strong> and go to the <strong>File shares</strong> blade. Add a new file share.
<ol>
<li><strong>Name</strong> set to <code class="language-plaintext highlighter-rouge">ai-storage-file-share</code>.</li>
<li>For <strong>Access tier</strong> select <code class="language-plaintext highlighter-rouge">Transaction optimized</code>.</li>
<li>On the <strong>Backup</strong> tab I disable backup, as I do not want to incur any additional charges. But if you can afford it, keep it enabled to keep your files safe in the event of data loss.</li>
<li>Create the file share.</li>
</ol>
</li>
</ol>
</li>
</ul>
</li>
</ul>
<h4 id="4-create-a-container-app">4. <strong>Create a Container App</strong></h4>
<p>Search for <strong>Container Apps</strong>, create a new container app.</p>
<ul>
<li><strong><u>Basics tab</u></strong>
<ol>
<li><strong>Container app name</strong> set the name to <code class="language-plaintext highlighter-rouge">ai-openwebcontainer</code>.</li>
<li><strong>Deployment source</strong> set to <code class="language-plaintext highlighter-rouge">Container image</code>.</li>
<li><strong>Region</strong> set <code class="language-plaintext highlighter-rouge">East US</code>.</li>
<li><strong>Container Apps Environment</strong> create a new container apps environment. There is additional configuration needed for the container app environment:
<ol>
<li>Set the <strong>Environment Name</strong> to <code class="language-plaintext highlighter-rouge">OpenWebContainerEnvironment</code>.</li>
<li>Leave the rest of the options as the defaults.</li>
<li>
<p>Create the Container Apps Environment.</p>
<p><img src="/assets/img/posts/create-container-app-basics-tab-filled-out.png" alt="Example of how to setup container app basics tab" /></p>
</li>
</ol>
</li>
</ol>
</li>
<li>
<p>Proceed to <strong>Next: Container</strong>.</p>
</li>
<li><strong><u>Container tab</u></strong>
<ol>
<li><strong>Image source</strong> set to <code class="language-plaintext highlighter-rouge">Docker Hub or other registries</code></li>
<li><strong>Image type</strong> set to <code class="language-plaintext highlighter-rouge">Public</code></li>
<li><strong>Registry login server</strong> set to <code class="language-plaintext highlighter-rouge">ghcr.io</code></li>
<li><strong>Image and tag</strong> set to <code class="language-plaintext highlighter-rouge">open-webui/open-webui:main</code></li>
<li><strong>CPU and Memory</strong> set to what you are comfortable with, I set to <code class="language-plaintext highlighter-rouge">2 CPU cores, 4 Gi memory</code> but this can be lower if needed.</li>
<li>
<p>Leave the rest of the options as the defaults (we will configure the environmental variables in a few steps).</p>
<p><img src="/assets/img/posts/create-container-app-container-tab-filled-out.png" alt="Example of how to setup container app container tab - picture 1" /></p>
</li>
</ol>
</li>
<li>
<p>Proceed to <strong>Next: Bindings</strong>.</p>
</li>
<li><strong><u>Bindings tab</u></strong>
<ol>
<li>Nothing needs to be modified on this tab.</li>
</ol>
</li>
<li>
<p>Proceed to <strong>Next: Ingress</strong>.</p>
</li>
<li><strong><u>Ingress tab</u></strong>
<ol>
<li>Toggle <strong>Ingress</strong> to <code class="language-plaintext highlighter-rouge">Enabled</code></li>
<li><strong>Ingress traffic</strong> set to <code class="language-plaintext highlighter-rouge">Accept traffic from anywhere: Applies if 'internal' setting is set to false on the Container Apps environment</code></li>
<li><strong>Ingress Type</strong> set to <code class="language-plaintext highlighter-rouge">HTTP</code></li>
<li><strong>Target port</strong> set to <code class="language-plaintext highlighter-rouge">8080</code></li>
<li>Leave the rest of the options as the defaults.</li>
</ol>
</li>
<li>Select <strong>Review + create</strong> to create the Container App.</li>
</ul>
<h4 id="5-gather-data-from-storage-accounts">5. <strong>Gather data from Storage Accounts</strong></h4>
<ol>
<li>Search for <strong>Storage accounts</strong>, select the storage account we created <strong>openwebuistorageaccount</strong>.</li>
<li>Expand <strong>Security + networking</strong> and select <strong>Access keys</strong>.</li>
<li>Click show on one of the 2 keys listed, <strong>copy one</strong> for us to use in the next step.</li>
</ol>
<h4 id="6-link-azure-files-to-container-apps-environment">6. <strong>Link Azure Files to Container Apps Environment</strong></h4>
<ol>
<li>Search for <strong>Container Apps Environments</strong>.</li>
<li>Expand <strong>Settings</strong>, then select <strong>Azure Files</strong>, we are going to Add a new file share to the container apps environment.
<ol>
<li><strong>Name</strong> set a name (<code class="language-plaintext highlighter-rouge">openwebcontainerfileshare</code>) for the file share in the container apps environment.
<ol>
<li><strong>Storage account name</strong> set to <code class="language-plaintext highlighter-rouge">openwebuistorageaccount</code></li>
<li><strong>Storage account key</strong> set to the access key we copied in the previous step.</li>
<li><strong>File Share</strong> set to <code class="language-plaintext highlighter-rouge">ai-storage-file-share</code></li>
<li><strong>Access mode</strong> set to <code class="language-plaintext highlighter-rouge">Read/Write</code></li>
</ol>
</li>
</ol>
</li>
</ol>
<h4 id="7-mount-azure-file-share-to-container-app">7. <strong>Mount Azure File Share to Container App</strong></h4>
<ol>
<li>Search for <strong>Container Apps</strong>, select the container app we created <strong>ai-openwebcontainer</strong></li>
<li>Expand <strong>Application</strong>, select <strong>Containers</strong>. Select <strong>Edit and deploy</strong>.
<ul>
<li>First, you will need to select the Volumes tab.</li>
<li><strong><u>Volumes tab</u></strong>
<ol>
<li>Select <strong>+ Add</strong></li>
<li><strong>Volume type</strong> set to <code class="language-plaintext highlighter-rouge">Azure file volume</code></li>
<li><strong>Name</strong> set to whatever name you would like (I used <code class="language-plaintext highlighter-rouge">ai-openweb-volume</code>).</li>
<li><strong>File share</strong> select the file share we created <code class="language-plaintext highlighter-rouge">openwebcontainerfileshare</code></li>
<li><strong>Mount options</strong> set to <code class="language-plaintext highlighter-rouge">nobrl</code> <a href="https://learn.microsoft.com/troubleshoot/azure/azure-kubernetes/storage/mountoptions-settings-azure-files#other-useful-settings" target="_blank">more information</a></li>
</ol>
</li>
<li>Now select the <strong>Container</strong> tab.</li>
<li><strong><u>Container tab</u></strong>
<ol>
<li><strong>Name / suffix</strong> set the name of the revision to something you will recognize. (I used <code class="language-plaintext highlighter-rouge">live</code>)</li>
<li>Click on the container image <code class="language-plaintext highlighter-rouge">ai-openwebcontainer</code> shown in the Container Image table
<img src="/assets/img/posts/edit-container-app-revision-container-image-select.png" alt="Where to click, to configure the container image" /></li>
<li>The <strong>Edit a container</strong> menu will open.
<ol>
<li>In the <strong>Basics</strong> tab you can add your Environment variables at the bottom of the tab. Here are all the environmental variables that OpenWeb UI Supports: <a href="https://docs.openwebui.com/getting-started/env-configuration/" target="_blank">https://docs.openwebui.com/getting-started/env-configuration/</a>
<ul>
<li>Add a new environmental variable <strong><em>(keep in mind this method will expose your API key in plain text. If you want security you need to save it as a secret)</em></strong>:
<ul>
<li><strong>Name:</strong> <code class="language-plaintext highlighter-rouge">OPENAI_API_KEY</code></li>
<li><strong>Source:</strong> <code class="language-plaintext highlighter-rouge">Manual entry</code></li>
<li><strong>Value:</strong> <code class="language-plaintext highlighter-rouge"><OpenAI-API-Key></code> <a href="https://platform.openai.com/api-keys" target="_blank">https://platform.openai.com/api-keys</a></li>
</ul>
</li>
</ul>
</li>
<li>Select the <strong>Volume mounts</strong> tab.</li>
<li>Select the dropdown under volume name and select the Azure file volume that we created in the Volumes tab.
<ul>
<li><strong>Volume name:</strong> <code class="language-plaintext highlighter-rouge">ai-openweb-volume</code></li>
<li><strong>Mount path:</strong> <code class="language-plaintext highlighter-rouge">/app/backend/data</code></li>
<li><strong>Sub path (optional):</strong> Leave this empty</li>
</ul>
</li>
<li>Click save</li>
</ol>
</li>
</ol>
</li>
<li>
<p>Lastly, you will need to select the Scale tab.</p>
</li>
<li><strong><u>Scale tab</u></strong>
<ol>
<li><strong>Min replicas</strong> set to <code class="language-plaintext highlighter-rouge">1</code> (If you want the instance to spin up on demand and deallocate when not in use, set this to <code class="language-plaintext highlighter-rouge">0</code> instead. Personally, I prefer the application to remain running, so I don’t have to wait for Azure Container Apps to activate the container.)</li>
<li><strong>Max replicas</strong> set to <code class="language-plaintext highlighter-rouge">1</code> (the max cannot be more than 1 due to design of Docker container for OpenWeb UI)</li>
</ol>
</li>
<li>Select <strong>Create</strong> to create the revision.</li>
</ul>
</li>
</ol>
<h4 id="8-access-the-application">8. <strong>Access the Application</strong>:</h4>
<ol>
<li>In the <strong>Container App</strong> view, expand <strong>Application</strong> and select <strong>Revisions and replicas</strong>.</li>
<li>Click the Active revision that ends with <code class="language-plaintext highlighter-rouge">live</code> (or whatever you configured your revision name to)</li>
<li>In the <strong>Revision details</strong> menu select the <strong>Revision URL</strong> this is the published URL for your container app revision. (the main URL is in the <strong>Overview</strong> blade of your container app. Its called the <strong>Application Url</strong>.)</li>
</ol>
<hr />
<h2 id="gear-scaling-limitations-of-openweb-ui">:gear: Scaling Limitations of OpenWeb UI</h2>
<p>Due to OpenWeb UI’s architecture, where both frontend and backend are housed in the same container, scaling the application horizontally (adding more replicas) is problematic. Here’s why:</p>
<ol>
<li><strong>Single Container Design</strong>: The combined frontend and backend make it difficult to scale individual components like you would in a decoupled architecture.</li>
<li><strong>Session Handling</strong>: Without advanced session management, multiple instances of the backend can cause inconsistent behavior, as there’s no mechanism to manage session persistence across replicas.</li>
<li><strong>Best Fit</strong>: For now, deploying OpenWeb UI with <strong>1 replica</strong> in <strong>Azure Container Apps</strong> is the most efficient way to ensure stability.</li>
</ol>
<h3 id="possible-solutions">Possible Solutions</h3>
<ul>
<li><strong>Decoupling Services</strong>: If you want to scale, consider splitting the frontend and backend into separate containers and using Kubernetes for scaling them independently.</li>
<li><strong>Kubernetes Deployment</strong>: Kubernetes can help manage scaling by separating components, introducing load balancing, and handling session persistence. However, this adds complexity and cost.</li>
</ul>
<h2 id="moneybag-cost-effective-hosting-container-apps-vs-kubernetes">:moneybag: Cost-Effective Hosting: Container Apps vs. Kubernetes</h2>
<p>When comparing <strong>Azure Container Apps</strong> and <strong>Azure Kubernetes Service (AKS)</strong>, here’s what you need to know about cost-effectiveness:</p>
<h3 id="azure-container-apps">Azure Container Apps</h3>
<ul>
<li><strong>Serverless Pricing</strong>: You only pay for the CPU and memory your app uses. It’s cost-efficient for small to medium workloads and apps with unpredictable traffic.</li>
<li><strong>Low Management Overhead</strong>: Azure manages the underlying infrastructure, so there’s no need to worry about managing virtual machines (VMs), which reduces operational costs.</li>
<li><strong>Best Use</strong>: Ideal for apps like OpenWeb UI that don’t require complex scaling and benefit from Azure’s autoscaling features.</li>
</ul>
<h3 id="azure-kubernetes-service-aks">Azure Kubernetes Service (AKS)</h3>
<ul>
<li><strong>VM-Based Pricing</strong>: You pay for VMs even when your app is idle. Scaling adds complexity since you need to manage pods, nodes, and networking.</li>
<li><strong>Scalability</strong>: While AKS offers more flexibility in scaling, the cost is higher, especially for apps that don’t need continuous scalability.</li>
<li><strong>Best Use</strong>: Suitable for large-scale applications that need fine-grained control over scaling and architecture.</li>
</ul>
<p><strong>Conclusion</strong>: <strong>Azure Container Apps</strong> is the more cost-effective solution for hosting OpenWeb UI due to its serverless pricing and minimal management requirements. AKS is better suited for complex, highly scalable applications, but it comes with a higher cost and management overhead.</p>
<h2 id="mag-conclusion">:mag: Conclusion</h2>
<p>In this guide, we deployed OpenWeb UI using Azure Container Apps and explored its scalability limitations. For most users, sticking with a single-instance deployment in Container Apps is the most cost-effective and stable approach. If scaling is essential, consider moving to the <a href="https://docs.openwebui.com/getting-started/installation" target="_blank">Kubernetes-based solution</a> where the frontend and backend can be decoupled.</p>
<h2 id="thought_balloon-feedback">:thought_balloon: Feedback</h2>
<p>Have you tried deploying OpenWeb UI on Azure? What’s your experience with its scaling capabilities? Share your insights in the comments below.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/azure-container-apps-openweb-ui/" alt="Page Views" /></p>
September 7, 2024
https://blakedrumm.com/blog/azure-container-apps-openweb-ui/
https://blakedrumm.com/blog/azure-container-apps-openweb-ui/PowerShell: SCOM's Best Friend - Insights from Scomathon 2024/assets/img/posts/scomathon-2024.png<h2 id="book-introduction">:book: Introduction</h2>
<p>At Scomathon 2024, I had the privilege of presenting on a topic that is near and dear to my heart: “PowerShell: SCOM’s Best Friend.” In this blog post, I’ll be sharing the key takeaways from my presentation, along with some practical PowerShell scripts that can significantly enhance your SCOM environment. Whether you’re just starting with SCOM or are a seasoned professional, there’s something here for everyone.</p>
<p>For those who couldn’t attend, you can watch my presentation here: <a href="https://www.youtube.com/watch?v=ewcJpC0iFqY">https://www.youtube.com/watch?v=ewcJpC0iFqY</a></p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/ewcJpC0iFqY?si=FtH07844yFjErQEe" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>
<h2 id="classical_building-why-powershell-for-scom">:classical_building: Why PowerShell for SCOM?</h2>
<p>PowerShell is a powerful scripting language that can automate and simplify many tasks within System Center Operations Manager (SCOM). From managing alerts and notifications to performing regular maintenance and configuration tasks, PowerShell can be your go-to tool for enhancing the efficiency and functionality of your SCOM environment.</p>
<h3 id="page_with_curl-key-benefits">:page_with_curl: Key Benefits</h3>
<ul>
<li><strong>Automation:</strong> Schedule and automate repetitive tasks to save time and reduce errors.</li>
<li><strong>Flexibility:</strong> Modify and extend scripts to meet your specific needs.</li>
<li><strong>Integration:</strong> Seamlessly integrate with other Windows services and applications.</li>
</ul>
<h2 id="hammer_and_wrench-tools-and-techniques">:hammer_and_wrench: Tools and Techniques</h2>
<p>During the presentation, I covered a variety of tools and techniques that are particularly useful for SCOM administrators. Below are the links to the tools discussed. <strong>Please note that these scripts require compliance with the MIT license</strong>.</p>
<blockquote>
<h3 id="system-center-operations-manager-data-warehouse-grooming-tool">System Center Operations Manager Data Warehouse Grooming Tool</h3>
<p><a href="/blog/scom-dw-grooming-tool">Read more</a></p>
<p>This tool analyzes your Data Warehouse Grooming to see what is being stored and how much of your Data Warehouse is filled with the related data. It is available in multiple formats: MSI, EXE, or source PS1.</p>
</blockquote>
<blockquote>
<h3 id="scom-data-collector">SCOM Data Collector</h3>
<p><a href="/blog/scom-data-collector">Read more</a></p>
<p>With the SCOM Data Collector, you can collect useful data to analyze and troubleshoot your SCOM Environment. It’s an essential tool for any SCOM Admin who wants a holistic view of their configuration and setup.</p>
</blockquote>
<blockquote>
<h3 id="reconfigure-system-center-operations-manager-for-database-move-tool">Reconfigure System Center Operations Manager for Database Move Tool</h3>
<p><a href="/blog/scom-db-move-tool">Read more</a></p>
<p>This application aids in updating the configuration when migrating SCOM SQL Instances.</p>
</blockquote>
<blockquote>
<h3 id="remove-data-from-the-scom-database-instantly---the-powershell-way">Remove Data from the SCOM Database Instantly - The PowerShell Way!</h3>
<p><a href="/blog/remove-data-from-scom-database/">Read more</a></p>
<p>This guide allows for quick removal of specific data from the SCOM Database without needing SQL Server Management Studio.</p>
</blockquote>
<blockquote>
<h3 id="scom-certificate-checker-script">SCOM Certificate Checker Script</h3>
<p><a href="/blog/scom-certificate-checker-script/">Read more</a></p>
<p>Check the validity of SCOM Certificates on an Agent, Gateway, or Management Server.</p>
</blockquote>
<blockquote>
<h3 id="enforce-tls-12--tls-13-in-scom---the-powershell-way">Enforce TLS 1.2 & TLS 1.3 in SCOM - The PowerShell Way!</h3>
<p><a href="/blog/enforce-tls-1-2-scom/">Read more</a></p>
<p>Configure your SCOM Environment for a more secure configuration with TLS 1.2 and TLS 1.3.</p>
</blockquote>
<h2 id="star-best-practices">:star: Best Practices</h2>
<p>Here are some best practices to keep in mind when using PowerShell with SCOM:</p>
<ul>
<li><strong>Test Scripts:</strong> Always test scripts in a non-production environment before deploying them live.</li>
<li><strong>Error Handling:</strong> Implement robust error handling to manage exceptions and failures gracefully.</li>
<li><strong>Documentation:</strong> Keep your scripts well-documented to ensure they are understandable and maintainable.</li>
</ul>
<h2 id="rocket-conclusion">:rocket: Conclusion</h2>
<p>PowerShell truly is SCOM’s best friend, offering unparalleled flexibility and control. By leveraging the tools and techniques discussed in my Scomathon 2024 presentation, you can enhance your SCOM environment, automate tedious tasks, and focus on what truly matters—optimizing your IT operations.</p>
<h2 id="link-additional-resources">:link: Additional Resources</h2>
<ul>
<li><a href="https://docs.microsoft.com/powershell/">Official PowerShell Documentation</a></li>
<li><a href="https://docs.microsoft.com/system-center/scom/">System Center Operations Manager Documentation</a></li>
</ul>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scomathon-2024-presentation/" alt="Page Views" /></p>
June 18, 2024
https://blakedrumm.com/blog/scomathon-2024-presentation/
https://blakedrumm.com/blog/scomathon-2024-presentation/Resolving Azure Maintenance Configuration Authorization Errors - Azure Update Manager/assets/img/posts/azure-authorization-error.png<h2 id="book-introduction">:book: Introduction</h2>
<p>While working with Azure, I encountered an authorization error while attempting to create a maintenance configuration. This post discusses the error, its implications, and how to resolve it using a custom role.</p>
<h2 id="x-error-text">:x: Error text</h2>
<p>While creating a maintenance configuration, I encountered the following error:</p>
<blockquote>
<p><span style="color:yellow">The client ‘[email protected]’</span> with object id ‘8b4fd821-05b6-4938-9949-18782893c5ed’ <span style="color:yellow">does not have authorization to perform action ‘Microsoft.Resources/deployments/validate/action’</span> over scope ‘/subscriptions/a1b2c3d4-5e6f-7g8h-9i0j-1k2l3m4n5o6p/resourceGroups/DeleteThisResourceGroup/providers/Microsoft.Resources/deployments/TestConfiguration_1715820611290’ or the scope is invalid. If access was recently granted, please refresh your credentials. (Code: AuthorizationFailed)</p>
</blockquote>
<p>This error message indicates a lack of permissions necessary to perform specific actions within the Azure portal.</p>
<h2 id="gear-solution">:gear: Solution</h2>
<p>To address this error we will need to create a custom role that specifically includes the necessary permissions for managing maintenance configurations and validating deployments.</p>
<h2 id="arrow_down-how-to-get-it">:arrow_down: How to get it</h2>
<p><strong>GitHub Gist:</strong> <a href="https://gist.github.com/blakedrumm/d94fe65970bbf5d4c56d471e5f4024a2">Create-MaintenanceConfigManagerRole.ps1</a></p>
<p>I developed a PowerShell script that creates a custom role to grant a user the necessary permissions for managing Maintenance Configurations within a specific Resource Group.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create-MaintenanceConfigManagerRole.ps1</span><span class="w">
</span><span class="c"># Script to create a custom role for managing Azure Maintenance Configurations</span><span class="w">
</span><span class="c"># Author: Blake Drumm ([email protected])</span><span class="w">
</span><span class="c"># Website: https://blakedrumm.com/blog/resolve-azure-maintenance-configuration-error/</span><span class="w">
</span><span class="c"># Date created: May 15th, 2024</span><span class="w">
</span><span class="c"># Define custom variables</span><span class="w">
</span><span class="nv">$subscriptionId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"a1b2c3d4-5e6f-7g8h-9i0j-1k2l3m4n5o6p"</span><span class="w">
</span><span class="nv">$resourceGroupName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"ResourceGroupName"</span><span class="w">
</span><span class="nv">$customRoleName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Maintenance Configuration Manager - Resource Group: </span><span class="nv">$resourceGroupName</span><span class="s2">"</span><span class="w">
</span><span class="nv">$userPrincipalName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"[email protected]"</span><span class="w">
</span><span class="c"># Define the custom role as a JSON string with the subscription ID and resource group name directly replaced</span><span class="w">
</span><span class="nv">$customRoleJson</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sh">@"
{
"Name": "</span><span class="nv">$customRoleName</span><span class="sh">",
"IsCustom": true,
"Description": "Allows management of maintenance configurations, validate and write deployments, read and write virtual machines, and write configuration assignments.",
"Actions": [
"Microsoft.Maintenance/maintenanceConfigurations/read",
"Microsoft.Maintenance/maintenanceConfigurations/write",
"Microsoft.Maintenance/maintenanceConfigurations/delete",
"Microsoft.Resources/deployments/validate/action",
"Microsoft.Resources/deployments/write",
"Microsoft.Maintenance/configurationAssignments/write",
"Microsoft.Compute/virtualMachines/read",
"Microsoft.Compute/virtualMachines/write"
],
"NotActions": [],
"AssignableScopes": [
"/subscriptions/</span><span class="nv">$subscriptionId</span><span class="sh">/resourceGroups/</span><span class="nv">$resourceGroupName</span><span class="sh">"
]
}
"@</span><span class="w">
</span><span class="c"># Convert the JSON string to a PowerShell object</span><span class="w">
</span><span class="nv">$customRole</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$customRoleJson</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ConvertFrom-Json</span><span class="w">
</span><span class="c"># Create the custom role</span><span class="w">
</span><span class="n">New-AzRoleDefinition</span><span class="w"> </span><span class="nt">-Role</span><span class="w"> </span><span class="nv">$customRole</span><span class="w">
</span><span class="c"># Define the scope</span><span class="w">
</span><span class="nv">$scope</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"/subscriptions/</span><span class="nv">$subscriptionId</span><span class="s2">/resourceGroups/</span><span class="nv">$resourceGroupName</span><span class="s2">"</span><span class="w">
</span><span class="c"># Assign the custom role to the user</span><span class="w">
</span><span class="n">New-AzRoleAssignment</span><span class="w"> </span><span class="nt">-RoleDefinitionName</span><span class="w"> </span><span class="nv">$customRoleName</span><span class="w"> </span><span class="nt">-UserPrincipalName</span><span class="w"> </span><span class="nv">$userPrincipalName</span><span class="w"> </span><span class="nt">-Scope</span><span class="w"> </span><span class="nv">$scope</span><span class="w">
</span><span class="cm"><#
Copyright (c) Microsoft Corporation. MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#></span><span class="w">
</span></code></pre></div></div>
<h2 id="bulb-how-to-use-it">:bulb: How to use it</h2>
<p>To implement this solution:</p>
<ol>
<li><strong>Modify the script</strong> with your specific details, including subscription ID, resource group name, and user principal name.</li>
<li><strong>Execute the script</strong> in your PowerShell environment to create the custom role and assign it.</li>
<li><strong>Verify the permissions</strong> are correctly applied by attempting to create a Maintenance Configuration again.</li>
</ol>
<h2 id="speech_balloon-conclusion">:speech_balloon: Conclusion</h2>
<p>By understanding and addressing Azure permission errors through custom role creation, administrators can ensure smoother operation, enhance security, and reduce manual workload. Feel free to modify the script to fit your specific needs and share your feedback on how it worked for you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/resolve-azure-maintenance-configuration-error/" alt="Page Views" /></p>
May 15, 2024
https://blakedrumm.com/blog/resolve-azure-maintenance-configuration-error/
https://blakedrumm.com/blog/resolve-azure-maintenance-configuration-error/Automated Azure Role Assignment Reports via Email - Azure Automation/assets/img/posts/azure-role-assignments-email.png<h2 id="book-introduction">:book: Introduction</h2>
<p>Azure cloud services management often requires monitoring and auditing user roles and group memberships. This script automates the generation and email distribution of detailed Azure subscription role assignments. It utilizes managed identity for Azure login, fetches role assignments, and compiles them into a comprehensive report sent via email.</p>
<h2 id="arrow_down-how-to-get-it">:arrow_down: How to get it</h2>
<p>You can download the script from the following links:</p>
<ul>
<li><a href="https://gist.github.com/blakedrumm/8f73e82f78b675bea2968117b70fd83e">Get-AzRoleAssignmentReport.ps1</a> :arrow_left: <strong>Direct Download Link</strong></li>
<li><a href="https://files.blakedrumm.com/Get-AzRoleAssignmentReport.ps1">Personal File Server - Get-AzRoleAssignmentReport.ps1</a> :arrow_left: <strong>Alternative Download Link</strong></li>
<li><a href="https://files.blakedrumm.com/Get-AzRoleAssignmentReport.txt">Personal File Server - Get-AzRoleAssignmentReport.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></li>
</ul>
<h2 id="classical_building-argument-list">:classical_building: Argument List</h2>
<table class="table table-hover table-text d-block overflow-auto">
<thead>
<tr>
<th>Parameter</th>
<th>Alias</th>
<th>ValueFromPipeline</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>EmailUsername</td>
<td> </td>
<td> </td>
<td>String</td>
<td>The username used to authenticate with the SMTP server.</td>
</tr>
<tr>
<td>EmailPassword</td>
<td> </td>
<td> </td>
<td>SecureString</td>
<td>The secure password used for SMTP authentication.</td>
</tr>
<tr>
<td>From</td>
<td> </td>
<td> </td>
<td>String</td>
<td>The email address from which the report will be sent.</td>
</tr>
<tr>
<td>To</td>
<td> </td>
<td> </td>
<td>Array</td>
<td>Array of recipient email addresses to whom the report will be sent.</td>
</tr>
<tr>
<td>Cc</td>
<td> </td>
<td> </td>
<td>Array</td>
<td>Array of CC recipient email addresses.</td>
</tr>
<tr>
<td>Subject</td>
<td> </td>
<td> </td>
<td>String</td>
<td>The subject line of the email.</td>
</tr>
<tr>
<td>Body</td>
<td> </td>
<td> </td>
<td>String</td>
<td>The body text of the email, describing the contents of the report. Can be HTML or plain text.</td>
</tr>
<tr>
<td>SMTPServer</td>
<td> </td>
<td> </td>
<td>String</td>
<td>The SMTP server used for sending the email.</td>
</tr>
<tr>
<td>SubscriptionIds</td>
<td> </td>
<td> </td>
<td>Array</td>
<td>Array of Azure subscription IDs to be included in the report.</td>
</tr>
<tr>
<td>WhatIf</td>
<td> </td>
<td> </td>
<td>Switch</td>
<td>A switch to simulate the script execution for testing purposes without performing any actual operations.</td>
</tr>
</tbody>
</table>
<h2 id="key-configuring-permissions-for-managed-identity">:key: Configuring Permissions for Managed Identity</h2>
<p>To enable the PowerShell script to retrieve detailed user information, such as ObjectType and DisplayName from Azure Active Directory, the UserManagedIdentity needs the “Directory Readers” permission. This role-based access control (RBAC) is assigned at the Microsoft Entra ID level (formerly known as Azure Active Directory), not at the subscription level. Follow these steps to assign the correct permissions:</p>
<ol>
<li><strong>Identify the Object ID:</strong>
<ul>
<li><strong>System Assigned Identity</strong>
<ul>
<li>Navigate to your Azure Automation Account -> Identity, select the System assigned tab. Copy the Object ID of the System Assigned identity. <br />
<img src="/assets/img/posts/system-assigned-identity.png" alt="Copy the System assigned Identity Object ID" /></li>
</ul>
</li>
<li><strong>User Assigned Identity</strong>
<ul>
<li>Navigate to your Azure Automation Account -> Identity, select the User assigned tab. Click on the name of the user assigned identity you want to gather the id from. Copy the Object ID of the User Assigned identity. <br />
<img src="/assets/img/posts/user-assigned-identity.png" alt="Copy the System assigned Identity Object ID" /> <br />
<img src="/assets/img/posts/user-assigned-identity-object-id.png" alt="Gather the Object ID from the User Managed Identity" /></li>
</ul>
</li>
</ul>
</li>
<li><strong>Set Azure role assignments</strong>
<ul>
<li>Select <strong>Azure role assignments</strong></li>
<li>Select <strong>Add role assignment</strong></li>
<li>Set the scope to: <strong>Subscription</strong></li>
<li>Select the subscription.</li>
<li>Set the role to (use what your company allows here, this is just what I used in my testing): <strong>Reader</strong> <br />
<img src="/assets/img/posts/add-role-assignments-subscription-reader.png" alt="Subscription reader RBAC permission" /></li>
</ul>
</li>
<li><strong>Assign the Role:</strong>
<ul>
<li>Open Microsoft Entra Id -> Roles and Administrators. <br />
<a href="https://portal.azure.com/#view/Microsoft_AAD_IAM/RolesManagementMenuBlade/~/AllRoles/adminUnitObjectId//resourceScope/">Azure Portal - Roles and Administrators</a></li>
<li>In the roles list, find and click on <strong>Directory Readers</strong>. <br />
<img src="/assets/img/posts/add-directory-reader-assignment.png" alt="Where to click for Add assignments" /></li>
<li>Click <strong>+ Add Assignments</strong> to start the role assignment process.</li>
</ul>
</li>
<li><strong>Add Managed Identity to Role:</strong>
<ul>
<li>In the assignment interface, you might not see app registrations or managed identities by default.</li>
<li>Paste the Object ID (from step 1) into the search field. This should display the name and ID of your Azure Automation Account.</li>
<li>Select your account and confirm the assignment. <br />
<img src="/assets/img/posts/add-directory-reader-assignment-object-id.png" alt="How to add a object id for assignment" /></li>
</ul>
</li>
<li><strong>Verify Permissions:</strong>
<ul>
<li>Once the “Directory Readers” permission is assigned, the script will be able to pull the Object Type and DisplayName along with other outputs from <code class="language-plaintext highlighter-rouge">Get-AzRoleAssignment</code>.</li>
</ul>
</li>
</ol>
<p><strong>This configuration is essential for the script to function correctly and securely access the necessary Azure AD data!</strong></p>
<h2 id="page_with_curl-how-to-use-it">:page_with_curl: How to use it</h2>
<p>In order to utilize this script in your Automation Runbook, you will need to set an encrypted variable inside of the Automation Account. This will be so we can pass the EmailPassword variable securely to the script. The script has the ability to gather this password automatically if you perform the following steps.</p>
<ol>
<li>Go to <strong>Automation Accounts</strong> -> Select the Automation Account -> <strong>Variables</strong>.</li>
<li>Click <strong>+ Add a variable</strong></li>
<li><strong>New Variable</strong>
<ul>
<li><strong>Name:</strong> <code class="language-plaintext highlighter-rouge">EmailPassword</code></li>
<li><strong>Description:</strong> <code class="language-plaintext highlighter-rouge">This is the password for the Email Account used in SMTP for an Azure Automation Runbook</code>.</li>
<li><strong>Type:</strong> <code class="language-plaintext highlighter-rouge">String</code></li>
<li><strong>Value:</strong> <code class="language-plaintext highlighter-rouge"><YourPassword></code></li>
<li><strong>Encrypted:</strong> <code class="language-plaintext highlighter-rouge">Yes</code> <br />
<img src="/assets/img/posts/encrypted-variables-automation-account.png" alt="Encrypted Variables Azure Automation Account" /></li>
</ul>
</li>
</ol>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/azure-automation-automated-azure-role-assignment-reports/" alt="Page Views" /></p>
April 23, 2024
https://blakedrumm.com/blog/azure-automation-automated-azure-role-assignment-reports/
https://blakedrumm.com/blog/azure-automation-automated-azure-role-assignment-reports/Toggle VM Power by Tag - Azure Automation/assets/img/start-stop-vms-by-tag-test-panel.png<h2 id="bulb-introduction">:bulb: Introduction</h2>
<p>Managing the power state of Azure VMs can be a cumbersome task, especially when dealing with a large number of instances. In scenarios where VMs need to be started or stopped based on certain criteria—like environment tags—it’s crucial to have an automated solution. This guide introduces a PowerShell script designed to toggle the power state of Azure Virtual Machines (VMs) based on their tags, offering a streamlined approach for bulk operations.</p>
<h2 id="wrench-the-script">:wrench: The Script</h2>
<p>The PowerShell script enables you to start or stop Azure VMs in bulk by specifying their subscription IDs, a tag name, and a tag value. It also supports a <code class="language-plaintext highlighter-rouge">-WhatIf</code> parameter for dry runs, allowing you to preview the changes without applying them.</p>
<h2 id="label-preparing-your-vms">:label: Preparing Your VMs</h2>
<p>To ensure your Azure VMs respond correctly to the script, you must tag them with specific key-value pairs. The script identifies VMs to start or stop based on these tags. Here’s how to set up your VM tags:</p>
<h3 id="tagging-vms">Tagging VMs</h3>
<p><img src="/assets/img/start-stop-vms-by-tag-vm-example.png" alt="Example showing a tag configured for a Virtual Machine in the Azure Portal" /></p>
<ol>
<li>
<p><strong>Access the Azure Portal:</strong> Navigate to the Azure Portal and find the Virtual Machines section.</p>
</li>
<li>
<p><strong>Select a VM:</strong> Choose the VM you want to manage with the script.</p>
</li>
<li>
<p><strong>Add Tags:</strong></p>
<ul>
<li>Click on the <strong>Tags</strong> section in the VM’s menu.</li>
<li>Add a new tag with the <strong>TagName</strong> you plan to use in the script. For example, if your script uses <code class="language-plaintext highlighter-rouge">Environment</code> as the tag name, you might set the tag value to <code class="language-plaintext highlighter-rouge">Development</code> for all development VMs.</li>
</ul>
</li>
</ol>
<h3 id="example-tag-configuration">Example Tag Configuration</h3>
<ul>
<li><strong>Tag Name:</strong> Environment</li>
<li><strong>Tag Value:</strong> Development</li>
</ul>
<p>With this configuration, if you run the script with <code class="language-plaintext highlighter-rouge">Environment</code> as the <code class="language-plaintext highlighter-rouge">$TagName</code> and <code class="language-plaintext highlighter-rouge">Development</code> as the <code class="language-plaintext highlighter-rouge">$TagValue</code>, it will target all VMs tagged as part of your development environment.</p>
<p>This setup allows for precise control over which VMs are affected by the script, enabling you to manage VM power states efficiently across different environments or projects.</p>
<h2 id="arrow_down-how-to-get-it">:arrow_down: How to get it</h2>
<p><strong>GitHub Gist:</strong> <a href="https://gist.github.com/blakedrumm/23163b76af766e38bcc507743472c603">Toggle-VMPowerByTag.ps1</a></p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">param</span><span class="w">
</span><span class="p">(</span><span class="w">
</span><span class="p">[</span><span class="n">Parameter</span><span class="p">(</span><span class="n">Mandatory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$true</span><span class="p">)]</span><span class="w">
</span><span class="p">[</span><span class="n">String</span><span class="p">[]]</span><span class="nv">$SubscriptionIds</span><span class="p">,</span><span class="w">
</span><span class="p">[</span><span class="n">Parameter</span><span class="p">(</span><span class="n">Mandatory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$true</span><span class="p">)]</span><span class="w">
</span><span class="p">[</span><span class="n">String</span><span class="p">]</span><span class="nv">$TagName</span><span class="p">,</span><span class="w">
</span><span class="p">[</span><span class="n">Parameter</span><span class="p">(</span><span class="n">Mandatory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$true</span><span class="p">)]</span><span class="w">
</span><span class="p">[</span><span class="n">String</span><span class="p">]</span><span class="nv">$TagValue</span><span class="p">,</span><span class="w">
</span><span class="p">[</span><span class="n">Parameter</span><span class="p">(</span><span class="n">Mandatory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$true</span><span class="p">)]</span><span class="w">
</span><span class="p">[</span><span class="n">Boolean</span><span class="p">]</span><span class="nv">$PowerState</span><span class="p">,</span><span class="w"> </span><span class="c"># true for start, false for stop</span><span class="w">
</span><span class="p">[</span><span class="n">Boolean</span><span class="p">]</span><span class="nv">$WhatIf</span><span class="w"> </span><span class="c"># test how the script will work, without making any changes to your environment</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="c"># Script to toggle Azure VM power states based on tags</span><span class="w">
</span><span class="c"># Requires PowerShell 7.2 or higher</span><span class="w">
</span><span class="c"># Author: Blake Drumm ([email protected])</span><span class="w">
</span><span class="c"># Website: https://blakedrumm.com/</span><span class="w">
</span><span class="c"># Date created: March 31st, 2024</span><span class="w">
</span><span class="c"># Date modified: April 16th, 2024</span><span class="w">
</span><span class="c"># Ensures you do not inherit an AzContext in your runbook</span><span class="w">
</span><span class="nv">$disableAzContextAutosave</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Disable-AzContextAutosave</span><span class="w"> </span><span class="nt">-Scope</span><span class="w"> </span><span class="nx">Process</span><span class="w">
</span><span class="c"># Connect using a Managed Service Identity</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Connect to Azure</span><span class="w">
</span><span class="nv">$AzConnection</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Connect-AzAccount</span><span class="w"> </span><span class="nt">-Identity</span><span class="w"> </span><span class="nt">-AccountId</span><span class="w"> </span><span class="nx">cb02e61e-d392-48d7-936a-9b44bbf5f312</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - Connected to Azure (Account Id: </span><span class="si">$(</span><span class="nv">$AzConnection</span><span class="o">.</span><span class="nf">Context</span><span class="o">.</span><span class="nf">Account</span><span class="o">.</span><span class="nf">Id</span><span class="si">)</span><span class="s2">)"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Log the error and exit</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - Connection failed: </span><span class="bp">$_</span><span class="s2">"</span><span class="w">
</span><span class="kr">exit</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$SubscriptionIds</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="c"># Initialize variables</span><span class="w">
</span><span class="nv">$PS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$PowerState</span><span class="w">
</span><span class="nv">$SubId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$_</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Set the subscription context</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - Subscription Id: </span><span class="nv">$SubId</span><span class="s2">"</span><span class="w">
</span><span class="nv">$setAzContext</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Set-AzContext</span><span class="w"> </span><span class="nt">-SubscriptionId</span><span class="w"> </span><span class="nv">$SubId</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Log the error and exit</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - Encountered error: </span><span class="bp">$_</span><span class="s2">"</span><span class="w">
</span><span class="kr">exit</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Fetch VMs with the specified tag</span><span class="w">
</span><span class="nv">$vms</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-AzResource</span><span class="w"> </span><span class="nt">-ResourceType</span><span class="w"> </span><span class="nx">Microsoft.Compute/virtualMachines</span><span class="w"> </span><span class="nt">-TagName</span><span class="w"> </span><span class="nv">$TagName</span><span class="w"> </span><span class="nt">-TagValue</span><span class="w"> </span><span class="nv">$TagValue</span><span class="w">
</span><span class="c"># Start or stop the VMs based on the desired state</span><span class="w">
</span><span class="nv">$vms</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="nt">-Parallel</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">$vm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$_</span><span class="w">
</span><span class="nv">$WhatIf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$</span><span class="nn">using</span><span class="p">:</span><span class="nv">WhatIf</span><span class="w">
</span><span class="nv">$Power</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$</span><span class="nn">using</span><span class="p">:</span><span class="nv">PS</span><span class="w">
</span><span class="c"># Fetch VM status</span><span class="w">
</span><span class="nv">$x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w">
</span><span class="kr">do</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$x</span><span class="o">++</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$vmStatus</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-AzVM</span><span class="w"> </span><span class="nt">-ResourceGroupName</span><span class="w"> </span><span class="nv">$vm</span><span class="o">.</span><span class="nf">ResourceGroupName</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="nt">-Status</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="c"># This will only be set to 2 if the command above is able to successfully fetch the VM status</span><span class="w">
</span><span class="nv">$x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - Encountered error: (VM Name: </span><span class="si">$(</span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="si">)</span><span class="s2">) </span><span class="bp">$_</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">until</span><span class="w"> </span><span class="p">(</span><span class="nv">$x</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w">
</span><span class="c"># Extract the power state of the VM</span><span class="w">
</span><span class="nv">$vmPowerState</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$vmStatus</span><span class="o">.</span><span class="nf">Statuses</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">Code</span><span class="w"> </span><span class="o">-like</span><span class="w"> </span><span class="s1">'PowerState/*'</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-ExpandProperty</span><span class="w"> </span><span class="nx">Code</span><span class="w">
</span><span class="c"># Start or stop VM based on the desired state </span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">((</span><span class="nv">$Power</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="bp">$true</span><span class="p">)</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="p">(</span><span class="nv">$vmPowerState</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="s1">'PowerState/running'</span><span class="p">))</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$WhatIf</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - What if: Starting </span><span class="si">$(</span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="si">)</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">else</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Start the VM</span><span class="w">
</span><span class="n">Start-AzVM</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="nt">-ResourceGroupName</span><span class="w"> </span><span class="nv">$vm</span><span class="o">.</span><span class="nf">ResourceGroupName</span><span class="w"> </span><span class="nt">-Verbose</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - Starting </span><span class="si">$(</span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="si">)</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">elseif</span><span class="w"> </span><span class="p">(</span><span class="nv">$Power</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="bp">$false</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="nv">$vmPowerState</span><span class="w"> </span><span class="o">-notmatch</span><span class="w"> </span><span class="s1">'PowerState/(deallocated|stopped)'</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$WhatIf</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - What if: Stopping </span><span class="si">$(</span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="si">)</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">else</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Stop the VM</span><span class="w">
</span><span class="n">Stop-AzVM</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="nt">-ResourceGroupName</span><span class="w"> </span><span class="nv">$vm</span><span class="o">.</span><span class="nf">ResourceGroupName</span><span class="w"> </span><span class="nt">-Force</span><span class="w"> </span><span class="nt">-Verbose</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - Stopping </span><span class="si">$(</span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="si">)</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">else</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Log the VM is already in the desired state</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - VM </span><span class="si">$(</span><span class="nv">$vm</span><span class="o">.</span><span class="nf">Name</span><span class="si">)</span><span class="s2"> is already in the desired state (PowerState: </span><span class="nv">$Power</span><span class="s2">). (Current VM PowerState: </span><span class="nv">$vmPowerState</span><span class="s2">)"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="nt">-ThrottleLimit</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="c"># Example throttle limit</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="s2">.ToLocalTime()) - Script completed!"</span><span class="w">
</span><span class="cm"><#
Copyright (c) Microsoft Corporation. MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#></span><span class="w">
</span></code></pre></div></div>
<h2 id="gear-how-it-works">:gear: How It Works</h2>
<p>The script first disables AzContext autosave to ensure a clean environment. Then, it attempts to connect to Azure using a Managed Service Identity. For each subscription ID provided, it sets the Azure context and fetches VMs that match the specified tag name and value. Depending on the desired power state (<code class="language-plaintext highlighter-rouge">$PowerState</code>), it starts or stops the fetched VMs, respecting the <code class="language-plaintext highlighter-rouge">-WhatIf</code> parameter to only simulate actions if specified.</p>
<h3 id="key-key-features">:key: Key Features</h3>
<ul>
<li><strong>Tag-Based Filtering:</strong> Selectively start or stop VMs based on tags, allowing for flexible management of different environments or deployment stages.</li>
<li><strong>Bulk Operations:</strong> Perform actions on multiple VMs across different subscriptions, saving time and effort.</li>
<li><strong>Safe Testing with <code class="language-plaintext highlighter-rouge">-WhatIf</code>:</strong> Preview the impact of the script without making actual changes to your VMs, enhancing control and safety.</li>
</ul>
<h2 id="mag-use-cases">:mag: Use Cases</h2>
<p>This script is particularly useful for scenarios like:</p>
<ul>
<li><strong>Cost Optimization:</strong> Automatically stop non-essential VMs outside of business hours.</li>
<li><strong>Environment Management:</strong> Quickly start or stop all VMs within a specific environment (e.g., development, testing) based on tagging.</li>
</ul>
<h2 id="thought_balloon-feedback">:thought_balloon: Feedback</h2>
<p>Have you tried using the script in your Azure environment? Any suggestions for improvement or additional features you’d find useful? Share your thoughts and experiences to help enhance this script for everyone.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/azure-automation-toggle-vm-power-by-tag/" alt="Page Views" /></p>
March 31, 2024
https://blakedrumm.com/blog/azure-automation-toggle-vm-power-by-tag/
https://blakedrumm.com/blog/azure-automation-toggle-vm-power-by-tag/Assessment Failures - Azure Update Manager/assets/img/posts/example-error-azure-update-manager-assessment.png<h2 id="bulb-introduction">:bulb: Introduction</h2>
<p>I had a case today where Azure Update Manager was showing errors regarding checks for assessments, upon checking the Windows Updates installed on the machine we noticed the updates were successfully installed.</p>
<h3 id="x-error-text">:x: Error text</h3>
<pre style="white-space: pre-wrap;">
1 errors reported. The latest 100 errors are shared in details. To view all errors, review this log file on the machine: [C:\ProgramData\GuestConfig\extension_logs\Microsoft.Software Update Management.WindowsOsUpdateExtension\1.telemetryLogs]. Failed to apply patch installation. Reason: [Failed to assess the machine for available updates: Activityld = [4242741a-0959-4b6c-886b-d7385dfc62f1], Operation=[Patching], Reason:[Windows update API threw an exception while assessing the machine for available updates. <span style="color:yellow">HResult: 0x80244022</span>.. For information on diagnosing this error, see: https://aka.ms/TroubleshootVMGuestPatching.].].
</pre>
<h2 id="mag-cause">:mag: Cause</h2>
<p>Details on the above exception:</p>
<div class="w-100 overflow-auto">
<hr />
<table>
<thead>
<tr>
<th>Hexadecimal Error Code</th>
<th>Decimal Error Code</th>
<th>Symbolic Name</th>
<th>Error Description</th>
<th>Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x80244022 </td>
<td>-2145107934 </td>
<td>WU_E_PT_HTTP_STATUS_SERVICE_UNAVAIL </td>
<td>Same as HTTP status 503 - the service is temporarily overloaded. </td>
<td>wuerror.h </td>
</tr>
</tbody>
</table>
<hr />
</div>
<p> </p>
<p>The issue above in my customers circumstance was due to the following registry key being present: <br />
<strong>HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU</strong></p>
<p>Specifically this key was changed to <code class="language-plaintext highlighter-rouge">1</code> which needed to be <code class="language-plaintext highlighter-rouge">0</code> in order to utilize Microsoft Updates:</p>
<table>
<thead>
<tr>
<th>Entry name</th>
<th>Data type</th>
<th>Values</th>
</tr>
</thead>
<tbody>
<tr>
<td>UseWUServer </td>
<td>Reg_DWORD </td>
<td><strong>1</strong> = The computer gets its updates from a WSUS server.</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td><strong>0</strong> = The computer gets its updates from Microsoft Update.</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td>The WUServer value is not respected unless this key is set.</td>
</tr>
</tbody>
</table>
<p> </p>
<p>More information on the registry keys for Automatic Updates and WSUS: <br />
<a href="https://learn.microsoft.com/windows/deployment/update/waas-wu-settings#configuring-automatic-updates-by-editing-the-registry">https://learn.microsoft.com/windows/deployment/update/waas-wu-settings#configuring-automatic-updates-by-editing-the-registry</a> <br />
<a href="https://github.com/vFense/vFenseAgent-win/wiki/Registry-keys-for-configuring-Automatic-Updates-&-WSUS">https://github.com/vFense/vFenseAgent-win/wiki/Registry-keys-for-configuring-Automatic-Updates-&-WSUS</a></p>
<h2 id="wrench-resolution">:wrench: Resolution</h2>
<p>Modifying the registry key above (<strong>UseWUServer</strong>) registry key to <strong>0</strong> instead of <strong>1</strong> allowed us to successfully utilize Azure Update Manager.</p>
<h3 id="computer-powershell-script">:computer: PowerShell Script</h3>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># The following code will allow you to set the UseWUServer registry key to 0</span><span class="w">
</span><span class="c"># Which allows you to utilize Microsoft Updates instead of Software Update Services (WSUS)</span><span class="w">
</span><span class="n">Set-ItemProperty</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">UseWUServer</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="nx">0</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s2">"HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"</span><span class="w">
</span></code></pre></div></div>
<p><img src="/assets/img/posts/wsus-registry-key.png" alt="Example showing how the registry should look" /></p>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/azure-update-manager-assessment-failures/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
February 27, 2024
https://blakedrumm.com/blog/azure-update-manager-assessment-failures/
https://blakedrumm.com/blog/azure-update-manager-assessment-failures/Configure periodic checking for missing system updates on azure virtual machines - Azure Update Manager Policy/assets/img/posts/azure-update-manager-policy-configure-periodic-checking.png<h2 id="bulb-introduction">:bulb: Introduction</h2>
<p>I had a case today were my customer was experiencing an error with the built-in Azure Update Manager Policy named: <strong>Configure periodic checking for missing system updates on azure virtual machines</strong>. I decided it would be a good idea to script out how to fix this so it can be automatically fixed for anyone who needs this fix in the future.</p>
<h3 id="x-error-text">:x: Error text</h3>
<pre style="white-space: pre-wrap;">
Failed to remediate resource: '/subscriptions/a84b857e-2f4b-4b79-8b92-c6f1093b6d4f/resourceGroups/rg-app-production/providers/Microsoft.Compute/virtualMachines/vmProdServer01'. The 'PUT' request failed with status code: 'Forbidden'. Inner Error: 'The client 'f4e3d2c1-b6a5-4f09-b8ed-9c2a3b1c9e4d' with object id 'f4e3d2c1-b6a5-4f09-b8ed-9c2a3b1c9e4d' has permission to perform action 'Microsoft.Compute/virtualMachines/write' on scope '/subscriptions/a84b857e-2f4b-4b79-8b92-c6f1093b6d4f/resourceGroups/rg-app-production/providers/Microsoft.Compute/virtualMachines/vmProdServer01'; however, <span style="color:yellow">it does not have permission to perform action(s) 'Microsoft.Compute/diskEncryptionSets/read' on the linked scope(s) '/subscriptions/a84b857e-2f4b-4b79-8b92-c6f1093b6d4f/resourceGroups/rg-encryption-keys/providers/Microsoft.Compute/diskEncryptionSets/desProdKeySet'</span> (respectively) or the linked scope(s) are invalid.', Correlation Id: '9e2d4b3c-a1b2-c3d4-e5f6-7g8h9i0j1k2l'.
</pre>
<h2 id="mag-cause">:mag: Cause</h2>
<p>Built-in policy for <strong>Configure periodic checking for missing system updates on azure virtual machines</strong> does not utilize a role that includes the permissions needed for Disk Encryption Set read.</p>
<h2 id="wrench-resolution">:wrench: Resolution</h2>
<p>The below PowerShell script is designed to duplicate the Virtual Machine Contributor role and will add Disk Encryption Set read access to the new custom role. Then the script duplicates the Azure Policy:
Configure periodic checking for missing system updates on azure virtual machines</p>
<p>Lastly the script edits the policy and replaces the assigned Role to the newly created custom role created with the script. You will need to edit line 22 to set the subscription name. On line 23 you can see the name of the new Policy that will be created with the script. You can verify the Role Definition is created correctly by searching the display name in your roles: <strong>Virtual Machine Contributor (with Disk Encryption Set read)</strong></p>
<h3 id="computer-powershell-script">:computer: PowerShell Script</h3>
<p><a href="https://gist.github.com/blakedrumm/1ed524f72e9bd2456bed96ff409ae17d">https://gist.github.com/blakedrumm/1ed524f72e9bd2456bed96ff409ae17d</a></p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ============================================================================</span><span class="w">
</span><span class="c"># Name: VM Management Role and Update Compliance Policy Setup Script</span><span class="w">
</span><span class="c"># ------------------------------------------------------------------</span><span class="w">
</span><span class="c"># Description: This PowerShell script automates the creation or updating of a custom Azure role and policy definition </span><span class="w">
</span><span class="c"># for managing virtual machine (VM) security and compliance. It ensures VMs within specified subscriptions are managed </span><span class="w">
</span><span class="c"># with enhanced permissions, including disk encryption set reading, and comply with system update policies. If the </span><span class="w">
</span><span class="c"># targeted custom role does not exist, it creates one by extending the "Virtual Machine Contributor" role. It then </span><span class="w">
</span><span class="c"># duplicates a built-in Azure policy for system update assessments, integrating the custom role to enforce update </span><span class="w">
</span><span class="c"># compliance. Designed for Azure administrators, this script streamlines VM management, security, and compliance </span><span class="w">
</span><span class="c"># within Azure environments.</span><span class="w">
</span><span class="c"># ============================================================================</span><span class="w">
</span><span class="c"># Author: Blake Drumm ([email protected])</span><span class="w">
</span><span class="c"># Date Created: February 2nd, 2024</span><span class="w">
</span><span class="c"># Date Modified: February 6th, 2024</span><span class="w">
</span><span class="c"># ============================================================================</span><span class="w">
</span><span class="c"># Edit Variables Below</span><span class="w">
</span><span class="c"># Type in the Subscription Scope you want to target for the new Role</span><span class="w">
</span><span class="c"># (You can comma separate Subscriptions you want to apply this role to)</span><span class="w">
</span><span class="c"># (Leave this empty if you want to select all subscriptions)</span><span class="w">
</span><span class="nv">$SubscriptionsScope</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'Visual Studio Enterprise Subscription'</span><span class="w">
</span><span class="nv">$PolicyDefinitionName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'Configure periodic checking for missing system updates on azure virtual machines (with Disk Encryption Set read)'</span><span class="w">
</span><span class="c"># ============================================================================</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$SubscriptionScopeDetails</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-AzSubscription</span><span class="w"> </span><span class="nt">-SubscriptionName</span><span class="w"> </span><span class="nv">$SubscriptionsScope</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"Experienced an error while gathering the subscription(s): </span><span class="nv">$error</span><span class="se">`n`n</span><span class="si">$(</span><span class="n">Get-AzContext</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-String</span><span class="p">)</span><span class="s2">"</span><span class="w">
</span><span class="kr">break</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$SubscriptionScopeId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="nv">$SubscriptionScopeDetails</span><span class="p">)</span><span class="o">.</span><span class="nf">Id</span><span class="w">
</span><span class="kr">do</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$Question</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Read-Host</span><span class="w"> </span><span class="s2">"Current subscriptions selected (</span><span class="si">$(</span><span class="nv">$SubscriptionScopeId</span><span class="o">.</span><span class="nf">Count</span><span class="si">)</span><span class="s2">): </span><span class="se">`n</span><span class="s2"> • </span><span class="si">$(</span><span class="nv">$SubscriptionScopeDetails</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">-join</span><span class="w"> </span><span class="s2">"</span><span class="se">`n</span><span class="s2"> • "</span><span class="si">)</span><span class="se">`n`n</span><span class="s2"> Are you sure you want to perform actions against the above subscriptions? (Y/N)"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">until</span><span class="w"> </span><span class="p">(</span><span class="nv">$Question</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="s2">"^Y|^N"</span><span class="p">)</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$Question</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="s2">"^N"</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"Exiting the script."</span><span class="w">
</span><span class="kr">return</span><span class="w"> </span><span class="c"># Use `return` instead of `break` outside of loops to exit the script</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$RoleDefinitionName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Virtual Machine Contributor (with Disk Encryption Set read)"</span><span class="w">
</span><span class="nv">$CheckIfRolePresent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-AzRoleDefinition</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s1">'Virtual Machine Contributor (with Disk Encryption Set read)'</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">SilentlyContinue</span><span class="w"> </span><span class="nt">-WarningAction</span><span class="w"> </span><span class="nx">SilentlyContinue</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`n</span><span class="s2">-----------------------------------------------------------------------------"</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="o">-NOT</span><span class="w"> </span><span class="nv">$CheckIfRolePresent</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Get the built-in "Virtual Machine Contributor" role definition</span><span class="w">
</span><span class="nv">$role</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-AzRoleDefinition</span><span class="w"> </span><span class="s2">"Virtual Machine Contributor"</span><span class="w">
</span><span class="c"># Clone the role to create a new custom role</span><span class="w">
</span><span class="nv">$customRole</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$role</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ConvertTo-Json</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ConvertFrom-Json</span><span class="w">
</span><span class="c"># Set properties for the new custom role</span><span class="w">
</span><span class="nv">$customRole</span><span class="o">.</span><span class="nf">Id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$null</span><span class="w">
</span><span class="nv">$customRole</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$RoleDefinitionName</span><span class="w">
</span><span class="nv">$customRole</span><span class="o">.</span><span class="nf">Description</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Lets you manage virtual machines, but not access to them, and not the virtual network or storage account they're connected to. Also lets you read disk encryption sets."</span><span class="w">
</span><span class="nv">$customRole</span><span class="o">.</span><span class="nf">IsCustom</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$true</span><span class="w">
</span><span class="c"># Replace Actions with a new collection including Disk Encryption Sets read permission</span><span class="w">
</span><span class="nv">$customRole</span><span class="o">.</span><span class="nf">Actions</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@(</span><span class="w">
</span><span class="s2">"Microsoft.Authorization/*/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/availabilitySets/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/locations/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/virtualMachines/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/virtualMachineScaleSets/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/cloudServices/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/disks/write"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/disks/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/disks/delete"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.DevTestLab/schedules/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Insights/alertRules/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/applicationGateways/backendAddressPools/join/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/loadBalancers/backendAddressPools/join/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/loadBalancers/inboundNatPools/join/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/loadBalancers/inboundNatRules/join/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/loadBalancers/probes/join/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/loadBalancers/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/locations/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/networkInterfaces/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/networkSecurityGroups/join/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/networkSecurityGroups/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/publicIPAddresses/join/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/publicIPAddresses/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/virtualNetworks/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Network/virtualNetworks/subnets/join/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/locations/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/backupFabrics/backupProtectionIntent/write"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/backupFabrics/protectionContainers/protectedItems/*/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/backupFabrics/protectionContainers/protectedItems/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/backupFabrics/protectionContainers/protectedItems/write"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/backupPolicies/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/backupPolicies/write"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/usages/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.RecoveryServices/Vaults/write"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.ResourceHealth/availabilityStatuses/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Resources/deployments/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Resources/subscriptions/resourceGroups/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.SerialConsole/serialPorts/connect/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.SqlVirtualMachine/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Storage/storageAccounts/listKeys/action"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Storage/storageAccounts/read"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Support/*"</span><span class="p">,</span><span class="w">
</span><span class="s2">"Microsoft.Compute/diskEncryptionSets/read"</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="c"># Replace NotActions with an empty array if needed, or customize as necessary</span><span class="w">
</span><span class="nv">$customRole</span><span class="o">.</span><span class="nf">NotActions</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@()</span><span class="w">
</span><span class="c"># Replace assignable scopes with a new collection</span><span class="w">
</span><span class="nv">$customRole</span><span class="o">.</span><span class="nf">AssignableScopes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@()</span><span class="w">
</span><span class="kr">foreach</span><span class="w"> </span><span class="p">(</span><span class="nv">$id</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="nv">$SubscriptionScopeId</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$customRole</span><span class="o">.</span><span class="nf">AssignableScopes</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="s2">"/subscriptions/</span><span class="nv">$id</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`n`t</span><span class="s2">• Getting ready to create Azure Role Definition: </span><span class="nv">$RoleDefinitionName</span><span class="s2">"</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Verbose</span><span class="w"> </span><span class="nt">-Verbose</span><span class="w"> </span><span class="s2">"Custom Role Variable:</span><span class="se">`n</span><span class="si">$(</span><span class="nv">$customRole</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-String</span><span class="p">)</span><span class="s2">"</span><span class="w">
</span><span class="c"># Create the new role definition</span><span class="w">
</span><span class="nv">$newAzRole</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-AzRoleDefinition</span><span class="w"> </span><span class="nt">-Role</span><span class="w"> </span><span class="nv">$customRole</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`n`t</span><span class="s2">• Successfully created Azure Role Definition!"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$ScriptError</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$_</span><span class="w">
</span><span class="s2">"-- Custom Role:"</span><span class="w">
</span><span class="nv">$customRole</span><span class="w">
</span><span class="nv">$ScriptError</span><span class="w">
</span><span class="n">Write-Verbose</span><span class="w"> </span><span class="nt">-Verbose</span><span class="w"> </span><span class="s2">" == Aborting script / See above for error == "</span><span class="w">
</span><span class="kr">return</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">else</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$newAzRole</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$CheckIfRolePresent</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`n`t</span><span class="s2">Role Definition is already created.</span><span class="se">`n</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="nv">$newAzRole</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`n</span><span class="s2">-----------------------------------------------------------------------------</span><span class="se">`n</span><span class="s2">"</span><span class="w">
</span><span class="c"># Step 1: Capture the New Role Definition ID</span><span class="w">
</span><span class="nv">$newRoleDefinitionId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$newAzRole</span><span class="o">.</span><span class="nf">Id</span><span class="w">
</span><span class="c"># Step 2: Identify the Built-in Azure Policy to Duplicate</span><span class="w">
</span><span class="c"># For example, let's assume you've identified a policy by its definition ID</span><span class="w">
</span><span class="nv">$existingPolicyDefinitionId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'59efceea-0c96-497e-a4a1-4eb2290dac15'</span><span class="w">
</span><span class="c"># Get the existing policy definition</span><span class="w">
</span><span class="nv">$existingPolicyDefinition</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-AzPolicyDefinition</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nv">$existingPolicyDefinitionId</span><span class="w">
</span><span class="c"># Step 3: Duplicate and Update the Policy with the New Role Definition ID</span><span class="w">
</span><span class="c"># Convert the existing policy rule to an object to make it editable</span><span class="w">
</span><span class="nv">$policyRuleObject</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$existingPolicyDefinition</span><span class="o">.</span><span class="nf">Properties</span><span class="o">.</span><span class="nf">PolicyRule</span><span class="w">
</span><span class="c"># Assuming the policy involves role assignments, update the rule to include your new role definition ID</span><span class="w">
</span><span class="c"># Note: The specific changes depend on the policy's structure. This is a generic example.</span><span class="w">
</span><span class="c"># If the policy assigns roles, you might find a section in the policy rule to insert the role ID.</span><span class="w">
</span><span class="c"># Correctly format the roleDefinitionIds as an array</span><span class="w">
</span><span class="nv">$policyRuleObject</span><span class="o">.</span><span class="nf">then</span><span class="o">.</span><span class="nf">details</span><span class="o">.</span><span class="nf">roleDefinitionIds</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@(</span><span class="s2">"/providers/Microsoft.Authorization/roleDefinitions/</span><span class="nv">$newRoleDefinitionId</span><span class="s2">"</span><span class="p">)</span><span class="w">
</span><span class="c"># Convert the modified policy rule back to JSON</span><span class="w">
</span><span class="nv">$modifiedPolicyRuleJson</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$policyRuleObject</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ConvertTo-Json</span><span class="w"> </span><span class="nt">-Depth</span><span class="w"> </span><span class="nx">20</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`t</span><span class="s2">• Creating/Updating new Policy Definition.</span><span class="se">`n`t</span><span class="s2"> • Name: </span><span class="nv">$PolicyDefinitionName</span><span class="s2">"</span><span class="w">
</span><span class="c"># Step 4: Create the New Policy Definition</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$newPolicyDefinition</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-AzPolicyDefinition</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"PeroidicCheckMissingAzureVMs"</span><span class="w"> </span><span class="se">`
</span><span class="w"> </span><span class="nt">-DisplayName</span><span class="w"> </span><span class="nv">$PolicyDefinitionName</span><span class="w"> </span><span class="se">`
</span><span class="w"> </span><span class="nt">-Description</span><span class="w"> </span><span class="s2">"Configure auto-assessment (every 24 hours) for OS updates on native Azure virtual machines. You can control the scope of assignment according to machine subscription, resource group, location or tag. Learn more about this for Windows: https://aka.ms/computevm-windowspatchassessmentmode, for Linux: https://aka.ms/computevm-linuxpatchassessmentmode."</span><span class="w"> </span><span class="se">`
</span><span class="w"> </span><span class="nt">-Policy</span><span class="w"> </span><span class="nv">$modifiedPolicyRuleJson</span><span class="w"> </span><span class="se">`
</span><span class="w"> </span><span class="nt">-Mode</span><span class="w"> </span><span class="nv">$existingPolicyDefinition</span><span class="o">.</span><span class="nf">Properties</span><span class="o">.</span><span class="nf">Mode</span><span class="w"> </span><span class="se">`
</span><span class="w"> </span><span class="nt">-Parameter</span><span class="w"> </span><span class="p">(</span><span class="nv">$existingPolicyDefinition</span><span class="o">.</span><span class="nf">Properties</span><span class="o">.</span><span class="nf">Parameters</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ConvertTo-Json</span><span class="p">)</span><span class="w"> </span><span class="se">`
</span><span class="w"> </span><span class="nt">-Metadata</span><span class="w"> </span><span class="p">(</span><span class="nv">$existingPolicyDefinition</span><span class="o">.</span><span class="nf">Properties</span><span class="o">.</span><span class="nf">Metadata</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ConvertTo-Json</span><span class="p">)</span><span class="w"> </span><span class="se">`
</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="c"># Output the new policy definition for verification</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`n`t</span><span class="s2">• New policy definition created/updated.</span><span class="se">`n`t</span><span class="s2"> • Resource Id: </span><span class="si">$(</span><span class="nv">$newPolicyDefinition</span><span class="o">.</span><span class="nf">ResourceId</span><span class="si">)</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"Experienced an error while creating the Policy Definition:</span><span class="se">`n`n</span><span class="nv">$error</span><span class="s2">"</span><span class="w">
</span><span class="kr">return</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="cm"><#
Copyright (c) Microsoft Corporation. MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#></span><span class="w">
</span></code></pre></div></div>
<p><img src="/assets/img/posts/azure-update-manager-policy-powershell-script.png" alt="VM Management Role and Update Compliance Policy Setup Script Output" class="img-fluid" /></p>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/azure-update-manager-policy-failure-remediation/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
February 14, 2024
https://blakedrumm.com/blog/azure-update-manager-policy-failure-remediation/
https://blakedrumm.com/blog/azure-update-manager-policy-failure-remediation/How to check core usage of ESU licenses - Azure Arc/assets/img/posts/azure-arc.png<h2 id="bulb-introduction">:bulb: Introduction</h2>
<p>This is my first blog post regarding the Azure space! On my blog today, I want to shed light on a common issue customers face: tracking the usage of Cores across their licenses. This is vital for understanding how many Cores are being utilized versus what’s available. Currently, Azure Portal lacks a direct report view for this, forcing customers to manually check each license and linked server to sum up the Core count, which is a hassle.</p>
<p>Good news, though. When a customer asks for such a report, there’s a simpler method: querying the Azure Resource Graph (ARG). The query I’ve got does the heavy lifting. It counts the Cores from each linked Arc machine, adjusts the count to meet the minimum requirements (8 vCores per VM and 16 pCores per physical server), and then presents this data alongside the license info.</p>
<p>This approach is a game-changer. It not only saves time but also gives a more accurate picture of Core usage.</p>
<h2 id="chart_with_upwards_trend-steps-to-gather-data">:chart_with_upwards_trend: Steps to Gather Data</h2>
<h3 id="mag-open-resource-graph-explorer">:mag: Open Resource Graph Explorer</h3>
<p>Within the Azure Portal open <a href="https://portal.azure.com/#view/HubsExtension/ArgQueryBlade" target="_blank">Resource Graph Explorer</a>.</p>
<p><img src="/assets/img/posts/resource-graph-explorer.png" alt="Resource Graph Explorer" class="img-fluid" /></p>
<h3 id="memo-kusto-query-kql">:memo: Kusto Query (KQL)</h3>
<div class="language-kql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resources</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">=~</span><span class="w"> </span><span class="s2">"microsoft.hybridcompute/licenses"</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">sku</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tostring</span><span class="p">(</span><span class="n">properties</span><span class="p">.</span><span class="n">licenseDetails</span><span class="p">.</span><span class="n">edition</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">totalCores</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tostring</span><span class="p">(</span><span class="n">properties</span><span class="p">.</span><span class="n">licenseDetails</span><span class="p">.</span><span class="n">processors</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">coreType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">case</span><span class="p">(</span><span class="w">
</span><span class="n">properties</span><span class="p">.</span><span class="n">licenseDetails</span><span class="p">.</span><span class="n">type</span><span class="w"> </span><span class="o">=~</span><span class="w"> </span><span class="s1">'vCore'</span><span class="p">,</span><span class="s1">'Virtual core'</span><span class="p">,</span><span class="w">
</span><span class="n">properties</span><span class="p">.</span><span class="n">licenseDetails</span><span class="p">.</span><span class="n">type</span><span class="w"> </span><span class="o">=~</span><span class="w"> </span><span class="s1">'pCore'</span><span class="p">,</span><span class="s1">'Physical core'</span><span class="p">,</span><span class="w">
</span><span class="s1">'Unknown'</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tostring</span><span class="p">(</span><span class="n">properties</span><span class="p">.</span><span class="n">licenseDetails</span><span class="p">.</span><span class="n">state</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">licenseId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tolower</span><span class="p">(</span><span class="nb">tostring</span><span class="p">(</span><span class="n">id</span><span class="p">))</span><span class="w"> </span><span class="c1">// Depending on what is stored in license profile, might have to get the immutableId instead</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">join</span><span class="w"> </span><span class="k">kind</span><span class="o">=</span><span class="n">inner</span><span class="p">(</span><span class="w">
</span><span class="n">resources</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">=~</span><span class="w"> </span><span class="s2">"microsoft.hybridcompute/machines/licenseProfiles"</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">machineId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tolower</span><span class="p">(</span><span class="nb">tostring</span><span class="p">(</span><span class="n">trim_end</span><span class="p">(</span><span class="s2">@"\/\w+\/(\w|\.)+"</span><span class="p">,</span><span class="w"> </span><span class="n">id</span><span class="p">)))</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">licenseId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tolower</span><span class="p">(</span><span class="nb">tostring</span><span class="p">(</span><span class="n">properties</span><span class="p">.</span><span class="n">esuProfile</span><span class="p">.</span><span class="n">assignedLicense</span><span class="p">))</span><span class="w">
</span><span class="p">)</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">licenseId</span><span class="w"> </span><span class="c1">// Get count of license profile per license, a license profile is created for each machine that is assigned a license</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">join</span><span class="w"> </span><span class="k">kind</span><span class="o">=</span><span class="n">inner</span><span class="p">(</span><span class="w">
</span><span class="n">resources</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">=~</span><span class="w"> </span><span class="s2">"microsoft.hybridcompute/machines"</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">machineId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tolower</span><span class="p">(</span><span class="n">id</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">coreCount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">toint</span><span class="p">(</span><span class="n">properties</span><span class="p">.</span><span class="n">detectedProperties</span><span class="p">.</span><span class="n">coreCount</span><span class="p">)</span><span class="w">
</span><span class="p">)</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">machineId</span><span class="w"> </span><span class="c1">// Get core count by machine</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">adjustedCoreCount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">iff</span><span class="p">(</span><span class="n">sku</span><span class="w"> </span><span class="o">=~</span><span class="w"> </span><span class="s2">"Standard"</span><span class="w">
</span><span class="p">,</span><span class="w"> </span><span class="k">case</span><span class="p">(</span><span class="n">coreCount</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mf">8</span><span class="p">,</span><span class="w"> </span><span class="mf">8</span><span class="p">,</span><span class="w"> </span><span class="n">coreCount</span><span class="p">)</span><span class="w"> </span><span class="p">,</span><span class="w">
</span><span class="nb">iff</span><span class="p">(</span><span class="n">sku</span><span class="w"> </span><span class="o">=~</span><span class="w"> </span><span class="s2">"DataCenter"</span><span class="w">
</span><span class="p">,</span><span class="w"> </span><span class="k">case</span><span class="p">(</span><span class="n">coreCount</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mf">16</span><span class="p">,</span><span class="w"> </span><span class="mf">16</span><span class="p">,</span><span class="w"> </span><span class="n">coreCount</span><span class="p">)</span><span class="w">
</span><span class="p">,</span><span class="n">coreCount</span><span class="p">))</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">extend</span><span class="w"> </span><span class="n">machineName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">tostring</span><span class="p">(</span><span class="nb">split</span><span class="p">(</span><span class="n">machineId</span><span class="p">,</span><span class="w"> </span><span class="s2">"/"</span><span class="p">)</span><span class="nv">[-1]</span><span class="p">)</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">project</span><span class="w"> </span><span class="n">machineName</span><span class="p">,</span><span class="w"> </span><span class="n">machineId</span><span class="p">,</span><span class="w"> </span><span class="n">licenseId</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="p">,</span><span class="w"> </span><span class="n">location</span><span class="p">,</span><span class="w"> </span><span class="n">subscriptionId</span><span class="p">,</span><span class="w"> </span><span class="n">resourceGroup</span><span class="p">,</span><span class="w"> </span><span class="n">sku</span><span class="p">,</span><span class="w"> </span><span class="n">totalCores</span><span class="p">,</span><span class="w"> </span><span class="n">coreType</span><span class="p">,</span><span class="w"> </span><span class="n">status</span><span class="p">,</span><span class="w"> </span><span class="n">adjustedCoreCount</span><span class="w">
</span><span class="o">|</span><span class="w"> </span><span class="k">summarize</span><span class="w"> </span><span class="n">UsedCoreCount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">sum</span><span class="p">(</span><span class="n">adjustedCoreCount</span><span class="p">)</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">licenseId</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="p">,</span><span class="w"> </span><span class="n">location</span><span class="p">,</span><span class="w"> </span><span class="n">subscriptionId</span><span class="p">,</span><span class="w"> </span><span class="n">resourceGroup</span><span class="p">,</span><span class="w"> </span><span class="n">sku</span><span class="p">,</span><span class="w"> </span><span class="n">totalCores</span><span class="p">,</span><span class="w"> </span><span class="n">coreType</span><span class="p">,</span><span class="w"> </span><span class="n">status</span><span class="w">
</span></code></pre></div></div>
<p><img src="/assets/img/posts/esu-core-output-azure-arc.png" alt="Azure Arc ESU licenses used" class="img-fluid" /></p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/how-to-check-esu-licenses-azure-arc/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 24, 2024
https://blakedrumm.com/blog/how-to-check-esu-licenses-azure-arc/
https://blakedrumm.com/blog/how-to-check-esu-licenses-azure-arc/SCOM Certificate Error - ASN1 Bad Tag Value Met/assets/img/posts/scom-asn1-bad-tag-value-met.png<h2 id="book-introduction">:book: Introduction</h2>
<p>Today I encountered an issue where SCOM fails to generate a certificate for Unix/Linux agents with an error message stating “ASN1 bad tag value met”.</p>
<h3 id="error-description">Error Description</h3>
<blockquote>
<p>Task invocation failed with error code -2130771918. Error message was: The SCXCertWriteAction module encountered a DoProcess exception. The workflow “Microsoft.Unix.Agent.GetCert.Task” has been unloaded. <br />
<br />
<br />
Module: SCXCertWriteAction <br />
Location: DoProcess <br />
Exception type: ScxCertLibException <br />
Exception message: <span style="color:yellow">Unable to create certificate context <br />
; {ASN1 bad tag value met. <br />
}
</span> <br />
Additional data: Sudo path: /etc/opt/microsoft/scx/conf/sudodir/</p>
<p>Management group: SCOM2019 <br />
Workflow name: Microsoft.Unix.Agent.GetCert.Task <br />
Object name: UNIX/Linux Resource Pool <br />
Object ID: {7B5B80D1-5C4A-6643-762D-60F46FB70CB8}</p>
</blockquote>
<hr />
<h2 id="mag-possible-causes-and-resolution">:mag: Possible Causes and Resolution</h2>
<h3 id="possible-causes">Possible Causes</h3>
<ul>
<li>Sudoers permissions are missing.</li>
<li>Errors in SSHCommandProbe.log (look for <code class="language-plaintext highlighter-rouge">errdata</code>)
<blockquote>
<p>3: 08/08/22 12:01:59 : Entering RunSSHCommand <br />
3: 08/08/22 12:01:59 : Using su command: su - root -c <br />
3: 08/08/22 12:01:59 : Using sudo command: ${SUDO_PATH}sudo sh -c <br />
3: 08/08/22 12:01:59 : sending: if [ -x /etc/opt/microsoft/scx/conf/sudodir/sudo ]; then <br />
SUDO_PATH=/etc/opt/microsoft/scx/conf/sudodir/; export SUDO_PATH <br />
else <br />
if [ -x /opt/sfw/bin/sudo ]; then <br />
SUDO_PATH=/opt/sfw/bin/; export SUDO_PATH <br />
else <br />
SUDO_PATH=/usr/bin/; export SUDO_PATH <br />
fi <br />
fi <br />
echo “Sudo path: ${SUDO_PATH}” <br />
${SUDO_PATH}sudo sh -c ‘cat /etc/opt/microsoft/scx/ssl/scx.pem’ <br />
<br />
3: 08/08/22 12:01:59 : Enter SSHFacade::RunCommand <br />
3: 08/08/22 12:02:02 : Leave SSHFacade::RunCommand <br />
3: 08/08/22 12:02:02 : returned: Sudo path: /etc/opt/microsoft/scx/conf/sudodir/ <br />
<br />
<span style="color:yellow">errdata: sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper</span></p>
</blockquote>
</li>
<li>In the secure log file on the Linux Server, you should see messages like:
<blockquote>
<p>Aug 8 12:32:00 rhel8-5 sshd[2749309]: pam_unix(sshd:session): session opened for user scxmaint by (uid=0) <br />
Aug 8 12:32:00 rhel8-5 sudo[2749343]: pam_unix(sudo:auth): conversation failed <br />
Aug 8 12:32:00 rhel8-5 sudo[2749343]: pam_unix(sudo:auth): auth could not identify password for [scxmaint] <br />
Aug 8 12:32:02 rhel8-5 sudo[2749343]: <span style="color:yellow">scxmaint : command not allowed</span> ; TTY=unknown ; PWD=/home/scxmaint ; USER=root ; COMMAND=/bin/sh -c cat /etc/opt/microsoft/scx/ssl/scx.pem <br />
Aug 8 12:32:02 rhel8-5 sshd[2749309]: pam_unix(sshd:session): session closed for user scxmaint</p>
</blockquote>
</li>
</ul>
<h3 id="how-to-fix-it">How to fix it</h3>
<ol>
<li>Check and verify the sudoers are setup correctly: <br />
<a href="https://learn.microsoft.com/system-center/scom/manage-security-unix-linux-sudoers-templates">https://learn.microsoft.com/system-center/scom/manage-security-unix-linux-sudoers-templates</a></li>
</ol>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-cert-asn1-bad-tag-value-met/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
... [Remaining GitHub Pages content] ...
-->
November 14, 2023
https://blakedrumm.com/blog/scom-cert-asn1-bad-tag-value-met/
https://blakedrumm.com/blog/scom-cert-asn1-bad-tag-value-met/SCOM Scheduled Reports Fail with AlertConnectionString, PerfConnectionString, or StateConnectionString Error/assets/img/posts/scom-reports-perfconnection-error.png<h2 id="warning-symptoms">:warning: Symptoms</h2>
<p>In SCOM 2016, 2019, or 2022, scheduled reports fail to run. If you check report status by opening the Scheduled Reports view in the Operations Console, the status message shows one of the following:</p>
<ul>
<li>“Default value or value provided for the report parameter ‘AlertConnectionString’ is not a valid value.”</li>
<li>“Default value or value provided for the report parameter ‘PerfConnectionString’ is not a valid value.”</li>
<li>“Default value or value provided for the report parameter ‘StateConnectionString’ is not a valid value.”</li>
</ul>
<h2 id="bulb-cause">:bulb: Cause</h2>
<p>This can occur if the <code class="language-plaintext highlighter-rouge"><appSettings></code> element is missing from the SQL Server Reporting Services (SSRS) configuration file.</p>
<p>By default, this configuration file is in the following folder on the SCOM Reporting server:</p>
<p><code class="language-plaintext highlighter-rouge">C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\ReportServer\bin\ReportingServicesService.exe.config</code></p>
<p>The issue described in the Symptoms section occurs when the below element is missing from the configuration file:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><appSettings></span>
<span class="nt"><add</span> <span class="na">key=</span><span class="s">"ManagementGroupId"</span> <span class="na">value=</span><span class="s">"management_group_GUID"</span><span class="nt">/></span>
<span class="nt"></appSettings></span>
</code></pre></div></div>
<h2 id="wrench-resolution">:wrench: Resolution</h2>
<h3 id="powershell-automatic-method">PowerShell Automatic Method</h3>
<hr />
<h4 id="what-does-this-powershell-script-do">What Does This PowerShell Script Do?</h4>
<p>This script automates the process of configuring SQL Server Reporting Services (SSRS) in a System Center Operations Manager (SCOM) environment. Below are the key steps:</p>
<h5 id="step-1-gather-system-information">Step 1: Gather System Information</h5>
<ul>
<li><strong>Fetch SSRS Info</strong>: Gathers essential details about the SSRS installation using Windows Management Instrumentation (WMI).</li>
<li><strong>Fetch SCOM Info</strong>: Retrieves System Center Operations Manager Data Warehouse database settings from the Windows registry.</li>
</ul>
<h5 id="step-2-fetch-management-group-id">Step 2: Fetch Management Group ID</h5>
<ul>
<li><strong>SQL Connection</strong>: Establishes a connection to the System Center Operations Manager Data Warehouse database.</li>
<li><strong>Fetch ID</strong>: Executes a SQL query to obtain the Management Group ID.</li>
</ul>
<h5 id="step-3-locate-and-check-the-configuration-file">Step 3: Locate and Check the Configuration File</h5>
<ul>
<li><strong>Locate Config</strong>: Determines the path of the SSRS configuration file (<code class="language-plaintext highlighter-rouge">ReportingServicesService.exe.config</code>).</li>
<li><strong>Check Config</strong>: Checks if the configuration file already contains the correct Management Group ID.</li>
</ul>
<h5 id="step-4-update-configuration">Step 4: Update Configuration</h5>
<ul>
<li><strong>Backup Config</strong>: Creates a backup of the original configuration file.</li>
<li><strong>Update Config</strong>: If necessary, updates the SSRS configuration file with the new Management Group ID.</li>
</ul>
<h5 id="step-5-finalize-changes">Step 5: Finalize Changes</h5>
<ul>
<li><strong>Save Changes</strong>: Saves the updated configuration.</li>
<li><strong>Restart Service</strong>: Restarts the SSRS service to apply the changes.</li>
</ul>
<hr />
<ol>
<li>Run the following script on your System Center Operations Manager Reporting Server. Be sure the PowerShell window is opened as Administrator and you have rights to query the Operations Manager Data Warehouse Database:
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="c">#Author: Blake Drumm ([email protected])</span><span class="w">
</span><span class="c">#Date Created: 10/31/2023</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$RS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"root\Microsoft\SqlServer\ReportServer\"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nx">root\Microsoft\SqlServer\ReportServer</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">__Namespace</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-First</span><span class="w"> </span><span class="nx">1</span><span class="p">)</span><span class="o">.</span><span class="nf">Name</span><span class="w">
</span><span class="nv">$RSV</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">__Namespace</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-First</span><span class="w"> </span><span class="nx">1</span><span class="p">)</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\Admin"</span><span class="w">
</span><span class="nv">$RSInfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nv">$RSV</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">MSReportServer_ConfigurationSetting</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="c"># Output or use $RSInfo as needed</span><span class="w">
</span><span class="nv">$SSRSConfigPath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$RSInfo</span><span class="o">.</span><span class="nf">PathName</span><span class="w">
</span><span class="nv">$DWDBInfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-ItemProperty</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s1">'HKLM:\SOFTWARE\Microsoft\System Center Operations Manager\12\Reporting'</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nx">DWDBInstance</span><span class="p">,</span><span class="w"> </span><span class="nx">DWDBName</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"An error occurred: </span><span class="nv">$error</span><span class="s2">"</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Red</span><span class="w">
</span><span class="kr">return</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># User-defined SQL Server Instance for the Operations Manager database</span><span class="w">
</span><span class="nv">$SQLInstance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$DWDBInfo</span><span class="o">.</span><span class="nf">DWDBInstance</span><span class="w">
</span><span class="nv">$DatabaseName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$DWDBInfo</span><span class="o">.</span><span class="nf">DWDBName</span><span class="w">
</span><span class="c"># Get the Management Group ID using SQL query</span><span class="w">
</span><span class="nv">$connectionString</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Server=</span><span class="nv">$SQLInstance</span><span class="s2">;Database=</span><span class="nv">$DatabaseName</span><span class="s2">;Integrated Security=True;"</span><span class="w">
</span><span class="nv">$connection</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Data.SqlClient.SqlConnection</span><span class="w">
</span><span class="nv">$connection</span><span class="o">.</span><span class="nf">ConnectionString</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$connectionString</span><span class="w">
</span><span class="nv">$connection</span><span class="o">.</span><span class="nf">Open</span><span class="p">()</span><span class="w">
</span><span class="nv">$command</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$connection</span><span class="o">.</span><span class="nf">CreateCommand</span><span class="p">()</span><span class="w">
</span><span class="nv">$command</span><span class="o">.</span><span class="nf">CommandText</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"SELECT ManagementGroupGuid from vManagementGroup"</span><span class="w">
</span><span class="nv">$reader</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$command</span><span class="o">.</span><span class="nf">ExecuteReader</span><span class="p">()</span><span class="w">
</span><span class="nv">$managementGroupId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$null</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$reader</span><span class="o">.</span><span class="nf">Read</span><span class="p">())</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$managementGroupId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$reader</span><span class="p">[</span><span class="s2">"ManagementGroupGuid"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$reader</span><span class="o">.</span><span class="nf">Close</span><span class="p">()</span><span class="w">
</span><span class="nv">$connection</span><span class="o">.</span><span class="nf">Close</span><span class="p">()</span><span class="w">
</span><span class="c"># Check if we got the Management Group ID</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="bp">$null</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="nv">$managementGroupId</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"Failed to get Management Group ID."</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Red</span><span class="w">
</span><span class="kr">return</span><span class="w">
</span><span class="c">#exit 1</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$SSRSParentDirectory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Split-Path</span><span class="w"> </span><span class="nv">$SSRSConfigPath</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Path to ReportingServicesService.exe.config</span><span class="w">
</span><span class="nv">$configPath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">Resolve-Path</span><span class="w"> </span><span class="s2">"</span><span class="nv">$SSRSParentDirectory</span><span class="s2">\bin\ReportingServicesService.exe.config"</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="p">)</span><span class="o">.</span><span class="nf">Path</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"Unable to access '</span><span class="nv">$SSRSParentDirectory</span><span class="s2">\bin\ReportingServicesService.exe.config' : </span><span class="nv">$error</span><span class="s2">"</span><span class="w">
</span><span class="kr">return</span><span class="w">
</span><span class="c">#exit 1</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Load the XML content of the config file</span><span class="w">
</span><span class="p">[</span><span class="n">xml</span><span class="p">]</span><span class="nv">$configXml</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-Content</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nv">$configPath</span><span class="w">
</span><span class="c"># Check if the appSettings element already exists and has the correct ManagementGroupId</span><span class="w">
</span><span class="nv">$appSettings</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$configXml</span><span class="o">.</span><span class="nf">SelectSingleNode</span><span class="p">(</span><span class="s2">"/configuration/appSettings/add[@key='ManagementGroupId']"</span><span class="p">)</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="bp">$null</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="nv">$appSettings</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="nv">$appSettings</span><span class="o">.</span><span class="nf">GetAttribute</span><span class="p">(</span><span class="s2">"value"</span><span class="p">)</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="nv">$managementGroupId</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"Configuration is already up to date."</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Green</span><span class="w">
</span><span class="kr">return</span><span class="w">
</span><span class="c">#exit 0</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Create a backup of the existing config file</span><span class="w">
</span><span class="n">Copy-Item</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nv">$configPath</span><span class="w"> </span><span class="nt">-Destination</span><span class="w"> </span><span class="s2">"</span><span class="nv">$configPath</span><span class="s2">.bak"</span><span class="w">
</span><span class="c"># Update or create the appSettings element</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="bp">$null</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="nv">$appSettings</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$appSettings</span><span class="o">.</span><span class="nf">SetAttribute</span><span class="p">(</span><span class="s2">"value"</span><span class="p">,</span><span class="w"> </span><span class="nv">$managementGroupId</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">else</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$appSettings</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$configXml</span><span class="o">.</span><span class="nf">CreateElement</span><span class="p">(</span><span class="s2">"appSettings"</span><span class="p">)</span><span class="w">
</span><span class="nv">$addKey</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$configXml</span><span class="o">.</span><span class="nf">CreateElement</span><span class="p">(</span><span class="s2">"add"</span><span class="p">)</span><span class="w">
</span><span class="nv">$addKey</span><span class="o">.</span><span class="nf">SetAttribute</span><span class="p">(</span><span class="s2">"key"</span><span class="p">,</span><span class="w"> </span><span class="s2">"ManagementGroupId"</span><span class="p">)</span><span class="w">
</span><span class="nv">$addKey</span><span class="o">.</span><span class="nf">SetAttribute</span><span class="p">(</span><span class="s2">"value"</span><span class="p">,</span><span class="w"> </span><span class="nv">$managementGroupId</span><span class="p">)</span><span class="w">
</span><span class="nv">$appSettings</span><span class="o">.</span><span class="nf">AppendChild</span><span class="p">(</span><span class="nv">$addKey</span><span class="p">)</span><span class="w">
</span><span class="nv">$configXml</span><span class="o">.</span><span class="nf">SelectSingleNode</span><span class="p">(</span><span class="s2">"/configuration"</span><span class="p">)</span><span class="o">.</span><span class="nf">AppendChild</span><span class="p">(</span><span class="nv">$appSettings</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Save the modified XML back to the config file</span><span class="w">
</span><span class="nv">$configXml</span><span class="o">.</span><span class="nf">Save</span><span class="p">(</span><span class="nv">$configPath</span><span class="p">)</span><span class="w">
</span><span class="c"># Restart the SQL Server Reporting Services service</span><span class="w">
</span><span class="n">Restart-Service</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nv">$RSInfo</span><span class="o">.</span><span class="nf">ServiceName</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"Configuration updated successfully."</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Green</span><span class="w">
</span></code></pre></div> </div>
</li>
</ol>
<h3 id="manual-method">Manual Method</h3>
<p>To resolve the issue, edit the SSRS configuration file to add a valid <code class="language-plaintext highlighter-rouge"><appSettings></code> element.</p>
<p>The following are the steps:</p>
<ol>
<li>
<p>On any computer that has the SCOM Operations Console installed, run the following PowerShell commands to get the management group ID:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Import-Module</span><span class="w"> </span><span class="nx">OperationsManager</span><span class="w">
</span><span class="p">(</span><span class="n">Get-SCOMManagementGroup</span><span class="p">)</span><span class="o">.</span><span class="nf">id</span><span class="o">.</span><span class="nf">guid</span><span class="w">
</span></code></pre></div> </div>
</li>
<li>
<p>Create a copy of the existing <code class="language-plaintext highlighter-rouge">ReportingServicesService.exe.config</code> file. By default, this file is in the following folder on the SCOM Reporting server:</p>
<p><code class="language-plaintext highlighter-rouge">C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\ReportServer\bin\ReportingServicesService.exe.config</code></p>
</li>
<li>Open the <code class="language-plaintext highlighter-rouge">ReportingServicesService.exe.config</code> file in a text editor.</li>
<li>
<p>Add the following element to the file immediately before the closing <code class="language-plaintext highlighter-rouge"></configuration></code> tag:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><appSettings></span>
<span class="nt"><add</span> <span class="na">key=</span><span class="s">"ManagementGroupId"</span> <span class="na">value=</span><span class="s">"management_group_GUID"</span><span class="nt">/></span>
<span class="nt"></appSettings></span>
</code></pre></div> </div>
<p>In the above XML, replace <code class="language-plaintext highlighter-rouge">management_group_GUID</code> with the management group ID you obtained in Step 1.</p>
<p>For example, the element will look like the following:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><startup</span> <span class="na">useLegacyV2RuntimeActivationPolicy=</span><span class="s">"true"</span><span class="nt">></span>
<span class="nt"><supportedRuntime</span> <span class="na">version=</span><span class="s">"v4.0"</span><span class="nt">/></span>
<span class="nt"></startup></span>
<span class="nt"><appSettings></span>
<span class="nt"><add</span> <span class="na">key=</span><span class="s">"ManagementGroupId"</span> <span class="na">value=</span><span class="s">"7f263180-e7d2-9c12-a1cd-0c6c54a7341c"</span><span class="nt">/></span>
<span class="nt"></appSettings></span>
<span class="nt"></configuration></span>
</code></pre></div> </div>
</li>
<li>Save the configuration file.</li>
<li>Restart the SQL Server Reporting Services service.</li>
</ol>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scheduled-reports-perfconnection-error/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
October 31, 2023
https://blakedrumm.com/blog/scheduled-reports-perfconnection-error/
https://blakedrumm.com/blog/scheduled-reports-perfconnection-error/SCOM SDK not staying on - AzMan Issue/assets/img/posts/sdk-service-stopped.png<h2 id="book-introduction">:book: Introduction</h2>
<p>Today I came across a problem with a customer that had an issue with the System Center Data Access Service (SDK) on all Management Servers crashing immediately after being started. The below errors can be found in the Operations Manager event log:</p>
<h3 id="1st-event">1st Event</h3>
<pre>
Log Name: Operations Manager
Source: OpsMgr SDK Service
Date: 10/12/2023 3:10:10 PM
Event ID: 26380
Level: Error
Computer: MS01-2019.contoso.com
Description:
<span style="color:yellow">The System Center Data Access service failed due to an unhandled exception.</span>
The service will attempt to restart.
Exception:
Microsoft.EnterpriseManagement.ConfigurationReaderException: Feature of type 'Microsoft.EnterpriseManagement.ServiceDataLayer.IAuthorizationFeature, Microsoft.EnterpriseManagement.DataAccessService.Core, Version=7.0.5000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' cannot be added to the container. ---> System.ServiceModel.FaultException\`1\[Microsoft.EnterpriseManagement.Common.UnknownAuthorizationStoreException]: The creator of this fault did not specify a Reason.
at Microsoft.EnterpriseManagement.<span style="color:yellow">Mom.Sdk.Authorization.AzManHelper.Initialize</span>(String pathToStore, String appName, AzManHelperModes helperMode, String storeDesc, String appDesc)
at Microsoft.EnterpriseManagement.Mom.Sdk.Authorization.AuthManager.Initialize(AuthManagerModes authMode)
at Microsoft.EnterpriseManagement.ServiceDataLayer.AuthorizationFeatureImplementation.InitializeAzmanAccessCheckObject()
at Microsoft.EnterpriseManagement.ServiceDataLayer.AuthorizationFeatureImplementation.Initialize(IContainer container)
at Microsoft.EnterpriseManagement.SingletonLifetimeManager\`1.GetComponent\[K]()
at Microsoft.EnterpriseManagement.FeatureContainer.GetFeatureInternal\[T](Type type, String featureName)
at Microsoft.EnterpriseManagement.FeatureContainer.AddFeatureInternal\[T,V](ActivationContext`1 context, String featureName)
--- End of inner exception stack trace ---
at Microsoft.EnterpriseManagement.ConfigurationReaderHelper.ReadFeatures(XPathNavigator navi, IContainer container)
at Microsoft.EnterpriseManagement.ConfigurationReaderHelper.Process()
at Microsoft.EnterpriseManagement.ServiceDataLayer.DispatcherService.Initialize(InProcEnterpriseManagementConnectionSettings configuration)
at Microsoft.EnterpriseManagement.ServiceDataLayer.DispatcherService.InitializeRunner(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart(Object obj)
</pre>
<h3 id="2nd-event">2nd Event</h3>
<pre>
Log Name: Operations Manager
Source: OpsMgr SDK Service
Date: 10/12/2023 3:10:10 PM
Event ID: 26339
Level: Error
Computer: MS01-2019.contoso.com
Description:
An exception was thrown while initializing the service container.
Exception message: Initialize
Full exception: Feature of type 'Microsoft.EnterpriseManagement.ServiceDataLayer.<span style="color:yellow">IAuthorizationFeature</span>, Microsoft.EnterpriseManagement.DataAccessService.Core, Version=7.0.5000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' cannot be added to the container
</pre>
<h3 id="3rd-event">3rd Event</h3>
<pre>
Log Name: Operations Manager
Source: OpsMgr SDK Service
Date: 10/12/2023 3:10:10 PM
Event ID: 26325
Level: Error
Computer: MS01-2019.contoso.com
Description: An authorization store exception was thrown in the System Center Data Access service. Exception message: <span style="color:yellow">Unable to perform the operation because of authorization store errors.</span>
</pre>
<hr />
<h2 id="page_with_curl-how-to-fix-it">:page_with_curl: How to fix it</h2>
<p>First you want to verify this problem is definitely related to Authorization Manager (AzMan).</p>
<hr />
<blockquote>
<h3 id="what-is-authorization-manager">What is Authorization Manager</h3>
<p>Authorization Manager, often referred to as <code class="language-plaintext highlighter-rouge">AzMan</code> or <code class="language-plaintext highlighter-rouge">AzMan.msc</code>, is a Microsoft Management Console (MMC) snap-in that provides a flexible framework for integrating role-based access control (RBAC) into applications. It’s a part of Windows and can be used to manage authorization policies using roles and tasks for applications.</p>
<p>Here’s a basic overview of its functionalities:</p>
<ol>
<li>
<p><strong>Role-Based Access Control (RBAC)</strong>: Authorization Manager allows for the definition of roles, operations, tasks, and scopes to achieve RBAC. This makes it easier for administrators to manage user permissions based on their roles within an organization.</p>
</li>
<li>
<p><strong>Store Policies in AD, AD LDS, and XML</strong>: Authorization policies can be stored in Active Directory (AD), Active Directory Lightweight Directory Services (AD LDS), or in an XML file. This flexibility allows for the storage and retrieval of policies in a manner best suited to the application’s needs.</p>
</li>
<li>
<p><strong>Application Integration</strong>: Applications can be developed to use Authorization Manager for enforcing access control. By doing this, the application offloads the management of roles and permissions to AzMan, making it easier to manage and update permissions without changing application code.</p>
</li>
<li>
<p><strong>Scriptable Interface</strong>: Authorization Manager provides a scriptable interface, which means you can automate many administrative tasks using scripts.</p>
</li>
<li>
<p><strong>Auditing</strong>: Authorization Manager can be configured to log access requests, which can then be used for audit purposes.</p>
</li>
<li>
<p><strong>Delegation of Administrative Duties</strong>: Administrators can delegate certain administrative duties to others, allowing for distributed management of roles and permissions without giving full administrative access.</p>
</li>
</ol>
</blockquote>
<hr />
<p>You can either run a PowerShell Script to check the AzMan connectivity or you can use the GUI.</p>
<h3 id="powershell-method">PowerShell Method</h3>
<p>Open a PowerShell window as Administrator on the SCOM Management Server, copy and paste the below script:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$SQLServerAddress</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">Get-ItemPropertyValue</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s2">"HKLM:\SOFTWARE\Microsoft\System Center\2010\Common\Database"</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"DatabaseServerName"</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="p">)</span><span class="w">
</span><span class="nv">$SQLServerOpsDatabase</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">Get-ItemPropertyValue</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s2">"HKLM:\SOFTWARE\Microsoft\System Center\2010\Common\Database"</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"DatabaseName"</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"Error automatically gathering the SCOM SQL instance name: </span><span class="si">$(</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Exception</span><span class="o">.</span><span class="nf">Message</span><span class="si">)</span><span class="s2">"</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Red</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Uncomment the below lines to set the SQL Server manually instead of trying to automatically grab the information from the registry</span><span class="w">
</span><span class="c"># $SQLServerAddress = "SQL01-2019"</span><span class="w">
</span><span class="c"># $SQLServerOpsDatabase = "OperationsManager"</span><span class="w">
</span><span class="c"># Load the AzMan assembly</span><span class="w">
</span><span class="p">[</span><span class="n">Reflection.Assembly</span><span class="p">]::</span><span class="n">LoadWithPartialName</span><span class="p">(</span><span class="s2">"AzRoles"</span><span class="p">)</span><span class="w">
</span><span class="c"># Create a new AzAuthorizationStore object</span><span class="w">
</span><span class="nv">$azStore</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nt">-ComObject</span><span class="w"> </span><span class="nx">AzRoles.AzAuthorizationStore</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Initialize the authorization store; replace with your SQL AzMan store connection string</span><span class="w">
</span><span class="nv">$azStore</span><span class="o">.</span><span class="nf">Initialize</span><span class="p">(</span><span class="nx">0</span><span class="p">,</span><span class="w"> </span><span class="s2">"mssql://Driver={SQL Server};Server={</span><span class="nv">$SQLServerAddress</span><span class="s2">};/</span><span class="nv">$SQLServerOpsDatabase</span><span class="s2">/AzmanStore"</span><span class="p">)</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"Connection to AzMan store successful."</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Green</span><span class="w">
</span><span class="c"># Optionally, list applications in the AzMan store to further verify connectivity</span><span class="w">
</span><span class="c">#$azStore.GetApplications() | ForEach-Object { Write-Host $_.Name }</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c"># Catch any exceptions and display the error message</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"Connection failed: </span><span class="si">$(</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Exception</span><span class="o">.</span><span class="nf">Message</span><span class="si">)</span><span class="s2">"</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Red</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>If you are affected you will see an output of:</p>
<pre>
<span style="color:red">Connection failed: The security ID structure is invalid. (Exception from HRESULT: 0x80070539)</span>
</pre>
<p>OR</p>
<h3 id="gui-method">GUI Method</h3>
<ol>
<li>Open Authorization Manager. Open a run box and type in:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AzMan.msc
</code></pre></div> </div>
<p>Press <strong>Enter</strong> and you will see the Authorization Manager Window. <br />
<img src="/assets/img/posts/azman-window.PNG" alt="Authorization Manager Main Window" class="img-fluid" /></p>
</li>
<li>Right Click the text Authorization Manager in the left box, select <strong>Open Authorization Store…</strong> <br />
<img src="/assets/img/posts/azman-window-open-store.PNG" alt="Open Authorization Store" class="img-fluid" /></li>
<li>Select <strong><u>M</u>icrosoft SQL</strong> and enter into the <strong>Store name</strong> text box:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mssql://Driver={SQL Server};Server={<SQLServer\Instance,OptionalPort>};/<OpsDatabaseName>/AzmanStore
</code></pre></div> </div>
<p>Press <strong>Enter</strong>. <br />
You will see the following pop-up: <br />
<code class="language-plaintext highlighter-rouge">Cannot open the authorization store. The following problem occurred: The security ID structure is invalid.</code> <br />
<img src="/assets/img/posts/azman-set-store.png" alt="AzMan Set Store Error Example" class="img-fluid" /></p>
</li>
</ol>
<h2 id="mag-find-and-fix-the-issue-in-sql">:mag: Find and fix the issue in SQL</h2>
<ol>
<li>Run the following query to determine the DB Owner for the databases:
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">name</span> <span class="k">AS</span> <span class="n">DatabaseName</span><span class="p">,</span> <span class="n">SUSER_SNAME</span><span class="p">(</span><span class="n">owner_sid</span><span class="p">)</span> <span class="k">AS</span> <span class="n">DatabaseOwner</span>
<span class="k">FROM</span> <span class="n">sys</span><span class="p">.</span><span class="n">databases</span><span class="p">;</span>
</code></pre></div> </div>
<p>OR <br />
You can also see the DB Owner via SQL Server Management Studio.</p>
<ol>
<li>Locate the Operations Manager or Operations Manager Data Warehouse Database in the Object Explorer view.</li>
<li>Right Click the Database and select <strong>Properties</strong>.</li>
<li>Click on <strong>Files</strong> and on the top is the DB Owner.
<img src="/assets/img/posts/sql-db-owner.png" alt="SQL DB Owner Example" class="img-fluid" /> <br />
Verify the account is not a local SQL account. I usually just set this to <code class="language-plaintext highlighter-rouge">sa</code>, as it is a built-in account that will not expire. But be aware as it can be disabled.</li>
<li>Run the following query to determine if a local sql account has db_owner permission on the Operations Manager Database <em>(the query is read only)</em>:
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">DECLARE</span> <span class="o">@</span><span class="n">DB_Users</span> <span class="k">TABLE</span>
<span class="p">(</span><span class="n">DBName</span> <span class="n">sysname</span><span class="p">,</span> <span class="n">UserName</span> <span class="n">sysname</span><span class="p">,</span> <span class="n">LoginType</span> <span class="n">sysname</span><span class="p">,</span> <span class="n">AssociatedRole</span> <span class="nb">varchar</span><span class="p">(</span><span class="k">max</span><span class="p">),</span><span class="n">create_date</span> <span class="nb">datetime</span><span class="p">,</span><span class="n">modify_date</span> <span class="nb">datetime</span><span class="p">)</span>
<span class="k">INSERT</span> <span class="o">@</span><span class="n">DB_Users</span>
<span class="k">EXEC</span> <span class="n">sp_MSforeachdb</span>
<span class="s1">'
use [?]
SELECT </span><span class="se">''</span><span class="s1">?</span><span class="se">''</span><span class="s1"> AS DB_Name,
case prin.name when </span><span class="se">''</span><span class="s1">dbo</span><span class="se">''</span><span class="s1"> then prin.name + </span><span class="se">''</span><span class="s1"> (</span><span class="se">''</span><span class="s1">+ (select SUSER_SNAME(owner_sid) from master.sys.databases where name =</span><span class="se">''</span><span class="s1">?</span><span class="se">''</span><span class="s1">) + </span><span class="se">''</span><span class="s1">)</span><span class="se">''</span><span class="s1"> else prin.name end AS UserName,
prin.type_desc AS LoginType,
isnull(USER_NAME(mem.role_principal_id),</span><span class="se">''''</span><span class="s1">) AS AssociatedRole ,create_date,modify_date
FROM sys.database_principals prin
LEFT OUTER JOIN sys.database_role_members mem ON prin.principal_id=mem.member_principal_id
WHERE prin.sid IS NOT NULL and prin.sid NOT IN (0x00) and
prin.is_fixed_role <> 1 AND prin.name NOT LIKE </span><span class="se">''</span><span class="s1">##%</span><span class="se">''</span><span class="s1">'</span>
<span class="k">SELECT</span>
<span class="n">dbname</span><span class="p">,</span><span class="n">username</span> <span class="p">,</span><span class="n">logintype</span> <span class="p">,</span><span class="n">create_date</span> <span class="p">,</span><span class="n">modify_date</span> <span class="p">,</span>
<span class="n">STUFF</span><span class="p">(</span>
<span class="p">(</span>
<span class="k">SELECT</span> <span class="s1">','</span> <span class="o">+</span> <span class="k">CONVERT</span><span class="p">(</span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">500</span><span class="p">),</span><span class="n">associatedrole</span><span class="p">)</span>
<span class="k">FROM</span> <span class="o">@</span><span class="n">DB_Users</span> <span class="n">user2</span>
<span class="k">WHERE</span>
<span class="n">user1</span><span class="p">.</span><span class="n">DBName</span><span class="o">=</span><span class="n">user2</span><span class="p">.</span><span class="n">DBName</span> <span class="k">AND</span> <span class="n">user1</span><span class="p">.</span><span class="n">UserName</span><span class="o">=</span><span class="n">user2</span><span class="p">.</span><span class="n">UserName</span>
<span class="k">FOR</span> <span class="n">XML</span> <span class="n">PATH</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="s1">''</span><span class="p">)</span> <span class="k">AS</span> <span class="n">Permissions_user</span>
<span class="k">FROM</span> <span class="o">@</span><span class="n">DB_Users</span> <span class="n">user1</span>
<span class="k">WHERE</span> <span class="n">LoginType</span> <span class="o">=</span> <span class="s1">'SQL_USER'</span> <span class="k">and</span>
<span class="n">UserName</span> <span class="o">!=</span> <span class="s1">'dbo (sa)'</span> <span class="k">and</span>
<span class="n">UserName</span> <span class="o">!=</span> <span class="s1">'MS_DataCollectorInternalUser'</span>
<span class="k">GROUP</span> <span class="k">BY</span>
<span class="n">dbname</span><span class="p">,</span><span class="n">username</span> <span class="p">,</span><span class="n">logintype</span> <span class="p">,</span><span class="n">create_date</span> <span class="p">,</span><span class="n">modify_date</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">DBName</span><span class="p">,</span> <span class="n">username</span>
</code></pre></div> </div>
</li>
</ol>
</li>
<li>You can use the following query to edit the User Mapping for the local SQL account and remove the <code class="language-plaintext highlighter-rouge">db_owner</code> role: <br />
(<em>Example Local Account Name:</em> <strong><em>LocalSQLAccount</em></strong> <– Replace with your SQL account)
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">USE</span> <span class="p">[</span><span class="n">OperationsManager</span><span class="p">];</span>
<span class="k">GO</span>
<span class="k">EXEC</span> <span class="n">sp_droprolemember</span> <span class="n">N</span><span class="s1">'db_owner'</span><span class="p">,</span> <span class="n">N</span><span class="s1">'LocalSQLAccount'</span><span class="p">;</span>
<span class="k">GO</span>
</code></pre></div> </div>
<p>OR <br />
You can edit via SQL Server Management Studio.</p>
<ol>
<li>Go to <strong>Security</strong> -> <strong>Logins</strong>, locate the local SQL account, Right Click and go to <strong>Properties</strong>.</li>
<li>Go to <strong>User Mapping</strong> and select the Operations Manager or Operations Manager Data Warehouse database.</li>
<li>Scroll in the <strong>Database role membership</strong> panel until you see <code class="language-plaintext highlighter-rouge">db_owner</code>, uncheck it and press <strong>OK</strong>. <br />
<img src="/assets/img/posts/sql-db-owner-usermapping.png" alt="SQL Server Management Studio - User Mapping for Local SQL User" class="img-fluid" /></li>
</ol>
</li>
<li>Restart the <strong>System Center Operations Manager Data Access Service</strong> (omsdk) on the Management Servers:
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Restart-Service</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">OMSDK</span><span class="w">
</span></code></pre></div> </div>
</li>
</ol>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-azman-issue/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
October 12, 2023
https://blakedrumm.com/blog/scom-azman-issue/
https://blakedrumm.com/blog/scom-azman-issue/SCOM License Expired/assets/img/posts/scom-activation.png<h2 id="book-introduction">:book: Introduction</h2>
<p>We attempted to activate the expired license for SCOM but we were unable due to the expiration of the product. The following errors would show when attempting to activate via PowerShell. These errors would show every time we try to activate:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Set-SCOMLicense : Unable to proceed with the command. Ensure you are connecting to correct Management Server and have sufficient privileges to execute the command.
At line:1 char:1
+ Set-SCOMLicense -ManagementServer localhost -ProductId BZX70-NQZUT-SS ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (BZX70-NQZUT-SSFEQ-7PWWZ-9ZOQC:String) [Set-SCOMLicense], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.SystemCenter.OperationsManagerV10.Commands.Commands.AdministrationCmdlets.SetSCOMLicense
</code></pre></div></div>
<p>At the same time two consecutive events are logged in the Application Log:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Log Name: Application
Source: .NET Runtime
Event ID: 1026
Task Category: None
Level: Error
Keywords: Classic
User: N/A
Description:
Application: MonitoringHost.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.UnauthorizedAccessException
at Microsoft.EnterpriseManagement.Common.Internal.ExceptionHandlers.HandleChannelExceptions(System.Exception)
at Microsoft.EnterpriseManagement.Common.Internal.SdkDataLayerProxyCore.CreateEndpoint[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](Microsoft.EnterpriseManagement.EnterpriseManagementConnectionSettings, Microsoft.EnterpriseManagement.Common.Internal.SdkChannelObject`1<Microsoft.EnterpriseManagement.Common.Internal.IDispatcherService>)
at Microsoft.EnterpriseManagement.Common.Internal.SdkDataLayerProxyCore.ConstructEnterpriseManagementGroupInternal[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](Microsoft.EnterpriseManagement.EnterpriseManagementConnectionSettings, Microsoft.EnterpriseManagement.DataAbstractionLayer.ClientDataAccessCore)
at Microsoft.EnterpriseManagement.Common.Internal.SdkDataLayerProxyCore.RetrieveEnterpriseManagementGroupInternal[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](Microsoft.EnterpriseManagement.EnterpriseManagementConnectionSettings, Microsoft.EnterpriseManagement.DataAbstractionLayer.ClientDataAccessCore)
at Microsoft.EnterpriseManagement.Common.Internal.SdkDataLayerProxyCore.Connect[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](Microsoft.EnterpriseManagement.EnterpriseManagementConnectionSettings, Microsoft.EnterpriseManagement.DataAbstractionLayer.ClientDataAccessCore)
at Microsoft.EnterpriseManagement.ManagementGroup.InternalInitialize(Microsoft.EnterpriseManagement.EnterpriseManagementConnectionSettings, Microsoft.EnterpriseManagement.ManagementGroupInternal)
at Microsoft.EnterpriseManagement.ManagementGroup.Connect(System.String)
at Microsoft.EnterpriseManagement.Mom.ValidateAlertSubscriptionModule.ValidateAlertSubscriptionDataSource.ValidateAlertSubscriptions(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.TimerQueueTimer.CallCallback()
at System.Threading.TimerQueueTimer.Fire()
at System.Threading.TimerQueue.FireNextTimers()
</code></pre></div></div>
<p>and</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Log Name: Application
Source: Application Error
Event ID: 1000
Task Category: (100)
Level: Error
Keywords: Classic
User: N/A
Description:
Faulting application name: MonitoringHost.exe, version: 10.19.10014.0, time stamp: 0x5c45e51b
Faulting module name: KERNELBASE.dll, version: 10.0.14393.5582, time stamp: 0x63882301
Exception code: 0xe0434352
Fault offset: 0x0000000000026ea8
Faulting process id: 0xaf4
Faulting application start time: 0x01d937237975b89c
Faulting application path: C:\Program Files\Microsoft System Center\Operations Manager\Server\MonitoringHost.exe
Faulting module path: C:\Windows\System32\KERNELBASE.dll
Report Id: 21ffc48d-66ca-4aab-9967-47b2201d498f
Faulting package full name:
Faulting package-relative application ID:
</code></pre></div></div>
<hr />
<h2 id="page_with_curl-how-to-fix-it">:page_with_curl: How to fix it</h2>
<p>Follow the below steps to allow you to fix the Activation issue:</p>
<ol>
<li>Run the following PowerShell script on your Management Server to unregister the Time Service, set the date 48 hours ahead of the date SCOM was installed on the Management Server, and finally restarting the SCOM services.
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="c"># Unregister the Time Service</span><span class="w">
</span><span class="n">W32tm</span><span class="w"> </span><span class="nx">/unregister</span><span class="w">
</span><span class="c"># Stop the Time Service</span><span class="w">
</span><span class="n">Stop-Service</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">w32time</span><span class="w">
</span><span class="c"># Set the Operating System date 48 hours ahead of the InstalledOn date that is in the registry</span><span class="w">
</span><span class="n">Set-Date</span><span class="w"> </span><span class="p">([</span><span class="n">DateTime</span><span class="p">]::</span><span class="n">ParseExact</span><span class="p">(</span><span class="err">$</span><span class="p">((</span><span class="n">Get-ItemProperty</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s1">'HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup'</span><span class="p">)</span><span class="o">.</span><span class="nf">InstalledOn</span><span class="p">),</span><span class="w"> </span><span class="s1">'M/d/yyyy-HH:mm:ss'</span><span class="p">,</span><span class="w"> </span><span class="bp">$null</span><span class="p">)</span><span class="o">.</span><span class="nf">AddHours</span><span class="p">(</span><span class="nx">48</span><span class="p">))</span><span class="w">
</span><span class="c"># Restart the SCOM Services (System Center Data Access Service, System Center Management Configuration, Microsoft Monitoring Agent)</span><span class="w">
</span><span class="n">Restart-Service</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">omsdk</span><span class="p">,</span><span class="w"> </span><span class="nx">cshost</span><span class="p">,</span><span class="w"> </span><span class="nx">healthservice</span><span class="w">
</span></code></pre></div> </div>
</li>
<li>Verify the time has been changed.</li>
<li>Open the SCOM Console and navigate to the top of the Console window, click on <strong>Help</strong> -> <strong>About</strong> <br />
<img src="/assets/img/posts/scom-console-help.png" alt="SCOM Console Help -> About" class="img-fluid" /></li>
<li>Click on Activate and type in your License key: <br />
<img src="/assets/img/posts/scom-activation.png" alt="SCOM Console Activation - Help -> About" class="img-fluid" /> <br />
<img src="/assets/img/posts/scom-activation-button.png" alt="SCOM Console Activation - Activation Window" class="img-fluid" /></li>
<li>Accept the license agreement: <br />
<img src="/assets/img/posts/scom-activation-license-agreement.png" alt="SCOM Console Activation Agreement" class="img-fluid" /></li>
<li>
<p>Successfully activated! <br />
<img src="/assets/img/posts/scom-activation-licensed-successfully.png" alt="SCOM Console Activation Successful" class="img-fluid" /></p>
</li>
<li>Register the Time Service to revert the changes made above, close the SCOM Console, and finally restart the SCOM SDK Service (System Center Data Access Service):
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Register the Time Service</span><span class="w">
</span><span class="n">W32tm</span><span class="w"> </span><span class="nx">/register</span><span class="w">
</span><span class="c"># Close the SCOM Console</span><span class="w">
</span><span class="n">Stop-Process</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">Microsoft.EnterpriseManagement.Monitoring.Console</span><span class="w"> </span><span class="nt">-Force</span><span class="w">
</span><span class="c"># Restart the SCOM SDK Service</span><span class="w">
</span><span class="n">Restart-Service</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">omsdk</span><span class="w">
</span></code></pre></div> </div>
</li>
<li>Open the SCOM Console and verify if you go to <strong>Help</strong> -> <strong>About</strong>. Do you see <strong>(Eval)</strong> in the Console version? <br />
If you see <strong>(Retail)</strong> (as shown below), you are activated! :sun_behind_small_cloud: <br />
<img src="/assets/img/posts/scom-activation-activated.png" alt="SCOM Console Activation Successful" class="img-fluid" /></li>
</ol>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-license-expired/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
September 25, 2023
https://blakedrumm.com/blog/scom-license-expired/
https://blakedrumm.com/blog/scom-license-expired/SCOM UNIX/Linux - Failed to find a matching agent kit to install/assets/img/posts/RHEL8_unable_to_upgrade.png<h2 id="what-is-the-problem">What is the problem?</h2>
<p>The latest version of the UNIX/Linux Management Pack includes a hotfix for compiler mitigated OMI support. The KB (5028684) needs to be applied, which needs to be applied on the SCOM Management Server and SCOM Console components installed in your environment.</p>
<h3 id="unixlinux-versions">UNIX/Linux versions</h3>
<p><strong>Linux Agent version:</strong> <code class="language-plaintext highlighter-rouge">1.7.1-0</code> <br />
<strong>SCOM 2022 (<em>10.22.1052.0</em>):</strong> <a href="https://www.microsoft.com/download/details.aspx?id=104213">https://www.microsoft.com/download/details.aspx?id=104213</a> <br />
<strong>SCOM 2019 (<em>10.19.1226.0</em>):</strong> <a href="https://www.microsoft.com/download/details.aspx?id=58208">https://www.microsoft.com/download/details.aspx?id=58208</a> <br />
<strong>SCOM 2016 (<em>7.6.1185.0</em>):</strong> <a href="https://www.microsoft.com/download/details.aspx?id=29696">https://www.microsoft.com/download/details.aspx?id=29696</a></p>
<p><img src="/assets/img/posts/linux-mp-1.7.1-0.png" alt="Linux Agent versions" class="img-fluid" /></p>
<h2 id="how-to-fix">How to fix</h2>
<p>Download the hotfix listed here: <br />
<a href="https://support.microsoft.com/kb/5028684">https://support.microsoft.com/kb/5028684</a></p>
<p>You must apply the hotfix on the SCOM Management Server and SCOM Console components installed in your environment.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/failed-to-find-a-matching-agent-kit-to-install//" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
August 14, 2023
https://blakedrumm.com/blog/failed-to-find-a-matching-agent-kit-to-install/
https://blakedrumm.com/blog/failed-to-find-a-matching-agent-kit-to-install/SCOM ETL Trace Gathering Script/assets/img/posts/etl_trace.png<h2 id="book-introduction">:book: Introduction</h2>
<p>This Tool will assist you in gathering ETL Traces. You have the options of selecting specific Tracing to gather with this script.</p>
<p>The script will perform the following, in this order:</p>
<ol>
<li>Stops any existing ETL Traces
<ul>
<li><em>Optional:</em> Stops the SCOM Services</li>
</ul>
</li>
<li>Starts the ETL Trace
<ul>
<li><em>Optional:</em> Starts the SCOM Services back up</li>
</ul>
</li>
<li>Script will wait for issue to occur
<ul>
<li><em>Default:</em> Pauses Script, waits until you press Enter</li>
<li><em>Optional:</em> Sleeps for x Seconds (<code class="language-plaintext highlighter-rouge">-SleepSeconds 10</code>)</li>
<li><em>Optional:</em> Script will loop until an Event ID is detected (<code class="language-plaintext highlighter-rouge">-DetectOpsMgrEventID</code>)</li>
<li><em>Optional:</em> Script can sleep for any amount of seconds after an Event is detected. (<code class="language-plaintext highlighter-rouge">-SleepAfterEventDetection</code>)</li>
</ul>
</li>
<li>Stops ETL Trace</li>
<li><em>Optional:</em> Script can attempt to Format the ETL Trace (<code class="language-plaintext highlighter-rouge">-FormatTrace</code>)</li>
<li>Zips Up Output and Opens Explorer Window for Viewing File</li>
</ol>
<h2 id="arrow_down-how-to-get-it">:arrow_down: How to get it</h2>
<p>You can get a copy of the script here: <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/SCOM%20ETL%20Trace/Start-ScomETLTrace.ps1">Start-ScomETLTrace.ps1</a> :arrow_left: <strong>Direct Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Start-ScomETLTrace.ps1">Personal File Server - Start-ScomETLTrace.ps1</a> :arrow_left: <strong>Alternative Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Start-ScomETLTrace.txt">Personal File Server - Start-ScomETLTrace.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></p>
<h2 id="page_with_curl-how-to-use-it">:page_with_curl: How to use it</h2>
<p>Open Powershell Prompt as Administrator:</p>
<blockquote>
<h4 id="examples">Examples</h4>
<h5 id="all-available-commands">All Available Commands</h5>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-GetAdvisor</span><span class="w"> </span><span class="nt">-GetApmConnector</span><span class="w"> </span><span class="nt">-GetBID</span><span class="w"> </span><span class="nt">-GetConfigService</span><span class="w"> </span><span class="nt">-GetDAS</span><span class="w"> </span><span class="nt">-GetFailover</span><span class="w"> </span><span class="nt">-GetManaged</span><span class="w"> </span><span class="nt">-GetNASM</span><span class="w"> </span><span class="nt">-GetNative</span><span class="w"> </span><span class="nt">-GetScript</span><span class="w"> </span><span class="nt">-GetUI</span><span class="w"> </span><span class="nt">-VerboseTrace</span><span class="w"> </span><span class="nt">-DebugTrace</span><span class="w"> </span><span class="nt">-NetworkTrace</span><span class="w"> </span><span class="nt">-SleepSeconds</span><span class="w"> </span><span class="nt">-RestartSCOMServices</span><span class="w"> </span><span class="nt">-DetectOpsMgrEventID</span><span class="w">
</span></code></pre></div> </div>
<h6 id="get-verbose-native-etl-trace">Get Verbose Native ETL Trace</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-GetNative</span><span class="w"> </span><span class="nt">-VerboseTrace</span><span class="w">
</span></code></pre></div> </div>
<blockquote>
<h6 id="get-verbose-native-etl-trace-and-format-the-trace">Get Verbose Native ETL Trace and Format the trace</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-GetNative</span><span class="w"> </span><span class="nt">-VerboseTrace</span><span class="w"> </span><span class="nt">-FormatTrace</span><span class="w">
</span></code></pre></div> </div>
</blockquote>
<h6 id="gather-verbose-etl-trace-and-detect-for-1210-event-id-sleep-for-30-seconds-between-checks">Gather Verbose ETL Trace and detect for 1210 Event ID (Sleep for 30 Seconds between checks)</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-VerboseTrace</span><span class="w"> </span><span class="nt">-DetectOpsMgrEventID</span><span class="w"> </span><span class="nx">1210</span><span class="w"> </span><span class="nt">-SleepSeconds</span><span class="w"> </span><span class="nx">30</span><span class="w">
</span></code></pre></div> </div>
<blockquote>
<h6 id="gather-verbose-etl-trace-and-detect-for-1210-event-id-sleep-for-30-seconds-between-checks-and-sleep-for-10-seconds-after-finding-the-event-id">Gather Verbose ETL Trace and detect for 1210 Event ID (Sleep for 30 Seconds between checks) and sleep for 10 seconds after finding the Event ID</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-VerboseTrace</span><span class="w"> </span><span class="nt">-DetectOpsMgrEventID</span><span class="w"> </span><span class="nx">1210</span><span class="w"> </span><span class="nt">-SleepSeconds</span><span class="w"> </span><span class="nx">30</span><span class="w"> </span><span class="nt">-SleepAfterEventDetection</span><span class="w"> </span><span class="nx">10</span><span class="w">
</span></code></pre></div> </div>
</blockquote>
<h6 id="restart-scom-services-after-starting-an-etl-trace-sleep-for-2-minutes-and-stop-the-trace-automatically">Restart SCOM Services after starting an ETL Trace. Sleep for 2 Minutes and stop the Trace Automatically</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-Sleep</span><span class="w"> </span><span class="nx">120</span><span class="w"> </span><span class="nt">-RestartSCOMServices</span><span class="w">
</span></code></pre></div> </div>
<h4 id="get-all-etl-traces">Get All ETL Traces</h4>
<h6 id="get-verbose-tracing-for-all-the-default-tracing-available-just-like-running-this--getadvisor--getapmconnector--getbid--getconfigservice--getdas--getfailover--getmanaged--getnasm--getnative--getscript--getui">Get Verbose Tracing for all the Default Tracing Available (just like running this: -GetAdvisor -GetApmConnector -GetBID -GetConfigService -GetDAS -GetFailover -GetManaged -GetNASM -GetNative -GetScript -GetUI)</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-VerboseTrace</span><span class="w">
</span></code></pre></div> </div>
<h6 id="get-debug-tracing-for-all-the-default-tracing-available-just-like-running-this--getadvisor--getapmconnector--getbid--getconfigservice--getdas--getfailover--getmanaged--getnasm--getnative--getscript--getui">Get Debug Tracing for all the Default Tracing Available (just like running this: -GetAdvisor -GetApmConnector -GetBID -GetConfigService -GetDAS -GetFailover -GetManaged -GetNASM -GetNative -GetScript -GetUI)</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-DebugTrace</span><span class="w">
</span></code></pre></div> </div>
<h6 id="get-verbose-tracing-for-all-the-default-tracing-available-and-network-tracing-just-like-running-this--getadvisor--getapmconnector--getbid--getconfigservice--getdas--getfailover--getmanaged--getnasm--getnative--getscript--getui">Get Verbose Tracing for all the Default Tracing Available and Network Tracing (just like running this: -GetAdvisor -GetApmConnector -GetBID -GetConfigService -GetDAS -GetFailover -GetManaged -GetNASM -GetNative -GetScript -GetUI)</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-VerboseTrace</span><span class="w"> </span><span class="nt">-NetworkTrace</span><span class="w">
</span></code></pre></div> </div>
<h6 id="get-verbose-tracing-for-all-the-default-tracing-available-and-opsmgrmodulelogging-for-linux-related-issues">Get Verbose Tracing for all the Default Tracing Available and OpsMgrModuleLogging for Linux Related Issues</h6>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Start-ScomETLTrace.ps1</span><span class="w"> </span><span class="nt">-VerboseTrace</span><span class="w"> </span><span class="nt">-OpsMgrModuleLogging</span><span class="w">
</span></code></pre></div> </div>
</blockquote>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-etl-trace/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
June 30, 2023
https://blakedrumm.com/blog/scom-etl-trace/
https://blakedrumm.com/blog/scom-etl-trace/Enforce TLS 1.2 & TLS 1.3 in SCOM - The PowerShell Way!/assets/img/posts/enforce-tls-1-2-scom.png<h2 id="book-introduction">:book: Introduction</h2>
<p>This PowerShell script will allow you to enforce TLS 1.2 & TLS 1.3 in your SCOM Environment to help you to secure your environment. (A big thank you to Kevin Holman for the original creation of his <a href="https://kevinholman.com/2018/05/06/implementing-tls-1-2-enforcement-with-scom/">TLS 1.2 enforcement script</a>, which this script originated from.) It will attempt to auto download the prerequisites if they are not present in the local directory (or if you set the parameter <strong>DirectoryForPrerequisites</strong> to another path it will check there). The script from a high level will do the following:</p>
<ol>
<li>Creates a log file to Program Data (<code class="language-plaintext highlighter-rouge">C:\ProgramData\SCOM_TLS_1.2_-_<Month>-<Day>-<Year>.log</code>).</li>
<li>Locate or Download the prerequisites for TLS 1.2 Enforcement.</li>
<li>Checks the SCOM Role (<em>Management Server, Web Console, ACS Collector</em>).</li>
<li>Checks the version of System Center Operations Manager to confirm supportability of TLS enforcement.</li>
<li>Checks the .NET version to confirm you are on a valid version.</li>
<li>Checks the SQL version (on both the Operations Manager and Data Warehouse Database Instances) to confirm your version of SQL supports TLS enforcement.</li>
<li>Checks and/or installs the <em>(prerequisite software)</em> MSOLEDB driver (or SQL Client).</li>
<li>Checks and/or installs the <em>(prerequisite software)</em> ODBC driver.</li>
<li>Checks and/or modifies the registry to enforce TLS 1.2 (If your using Window Server 2022 (or newer) or Windows 11 (or newer) it will attempt to enforce TLS 1.2 <strong>and</strong> TLS 1.3).</li>
<li>Ask to reboot the machine to finalize the configuration.</li>
</ol>
<h2 id="classical_building-argument-list">:classical_building: Argument List</h2>
<table class="table table-hover table-text d-block overflow-auto">
<thead>
<tr>
<th>Parameter</th>
<th>Alias</th>
<th>ValueFromPipeline</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>AssumeYes</td>
<td>yes</td>
<td> </td>
<td>Switch</td>
<td>The script will not ask any questions. Good for unattended runs.</td>
</tr>
<tr>
<td>DirectoryForPrerequisites</td>
<td>dfp</td>
<td> </td>
<td>String</td>
<td>The directory to save / load the prerequisites from. Default is the current directory.</td>
</tr>
<tr>
<td>ForceDownloadPrerequisites</td>
<td>fdp</td>
<td> </td>
<td>Switch</td>
<td>Force download the prerequisites to the directory specified in DirectoryForPrerequisites.</td>
</tr>
<tr>
<td>SkipDotNetCheck</td>
<td>sdnc</td>
<td> </td>
<td>Switch</td>
<td>Skip the .NET Check step.</td>
</tr>
<tr>
<td>SkipDownloadPrerequisites</td>
<td>sdp</td>
<td> </td>
<td>Switch</td>
<td>Skip downloading the prerequisite files to current directory.</td>
</tr>
<tr>
<td>SkipModifyRegistry</td>
<td>smr</td>
<td> </td>
<td>String</td>
<td>Skip any registry modifications.</td>
</tr>
<tr>
<td>SkipRoleCheck</td>
<td>src</td>
<td> </td>
<td>Switch</td>
<td>Skip the SCOM Role Check step.</td>
</tr>
<tr>
<td>SkipSQLQueries</td>
<td>ssq</td>
<td> </td>
<td>Switch</td>
<td>Skip any check for SQL version compatibility.</td>
</tr>
<tr>
<td>SkipSQLSoftwarePrerequisites</td>
<td>sssp</td>
<td> </td>
<td>Switch</td>
<td>Skip the ODBC, MSOLEDBSQL, and/or Microsoft SQL Server 2012 Native Client.</td>
</tr>
<tr>
<td>SkipVersionCheck</td>
<td>svc</td>
<td> </td>
<td>Switch</td>
<td>Skip SCOM Version Check step.</td>
</tr>
</tbody>
</table>
<blockquote>
<h2 id="notebook-note">:notebook: Note</h2>
<p>You may edit line <a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/TLS%201.2%20Enforcement/Invoke-EnforceSCOMTLS1.2.ps1#L1904">1904</a> in the script to change what happens when the script is run without any arguments or parameters, this also allows you to change what happens when the script is run from the Powershell ISE.</p>
</blockquote>
<h2 id="arrow_down-how-to-get-it">:arrow_down: How to get it</h2>
<p>You can get a copy of the script here: <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/TLS%201.2%20Enforcement/Invoke-EnforceSCOMTLS1.2.ps1">Invoke-EnforceSCOMTLS1.2.ps1</a> :arrow_left: <strong>Direct Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Invoke-EnforceSCOMTLS1.2.ps1">Personal File Server - Invoke-EnforceSCOMTLS1.2.ps1</a> :arrow_left: <strong>Alternative Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Invoke-EnforceSCOMTLS1.2.txt">Personal File Server - Invoke-EnforceSCOMTLS1.2.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></p>
<h2 id="page_with_curl-how-to-use-it">:page_with_curl: How to use it</h2>
<blockquote>
<h4 id="example-1">Example 1</h4>
<p>Normal run:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Invoke-EnforceSCOMTLS1.2.ps1</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-2">Example 2</h4>
<p>Set the prerequisites folder:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Invoke-EnforceSCOMTLS1.2.ps1</span><span class="w"> </span><span class="nt">-DirectoryForPrerequisites</span><span class="w"> </span><span class="s2">"C:\Temp"</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-3">Example 3</h4>
<p>Assume yes to all questions asked by script:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Invoke-EnforceSCOMTLS1.2.ps1</span><span class="w"> </span><span class="nt">-AssumeYes</span><span class="w">
</span></code></pre></div> </div>
</blockquote>
<h2 id="check-tls-configuration">Check TLS Configuration</h2>
<p>You can run the following PowerShell script to gather your current TLS configuration:</p>
<h3 id="arrow_down-how-to-get-it-1">:arrow_down: How to get it</h3>
<p><a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Get-TLSRegistryKeys.ps1">Get-TLSRegistryKeys.ps1</a> :arrow_left: <strong>Direct Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Get-TLSRegistryKeys.ps1">Personal File Server - Get-TLSRegistryKeys.ps1</a> :arrow_left: <strong>Alternative Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Get-TLSRegistryKeys.txt">Personal File Server - Get-TLSRegistryKeys.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></p>
<p><img src="/assets/img/posts/check-tlssettings.png" alt="Script example showing how TLS is configured" class="img-fluid" /></p>
<hr />
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/enforce-tls-1-2-scom/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
May 25, 2023
https://blakedrumm.com/blog/enforce-tls-1-2-scom/
https://blakedrumm.com/blog/enforce-tls-1-2-scom/How to Decommission SCOM Gateway/assets/img/posts/scom-gateway-decommission.png<h2 id="the-steps-required">The Steps Required</h2>
<ol>
<li>
<p>Move any agents (Agents or Agentless) assigned to the Gateway to another server.</p>
</li>
<li>
<p>Uninstall the SCOM Gateway through programs and features.</p>
</li>
<li>
<p>Delete the Gateway with the Gateway Approval Tool.</p>
<blockquote>
<p>The Microsoft.EnterpriseManagement.GatewayApprovalTool.exe tool is needed only on the management server, and it only has to be run once.</p>
<p>To copy Microsoft.EnterpriseManagement.GatewayApprovalTool.exe to management servers
From a target management server, open the Operations Manager installation media <code class="language-plaintext highlighter-rouge">\SupportTools\</code> (amd64 or x86) directory.</p>
<p>Copy the <strong><em>Microsoft.EnterpriseManagement.GatewayApprovalTool.exe</em></strong> from the installation media to the Operations Manager installation directory.</p>
</blockquote>
<p>The command to delete a SCOM Gateway:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Microsoft.EnterpriseManagement.GatewayApprovalTool.exe /ManagementServerName=<managementserverFQDN> /GatewayName=<GatewayFQDN> /Action=Delete
</code></pre></div> </div>
</li>
</ol>
<p>Kevin Holman has a good guide for Management Server’s here (which some items apply for Gateway’s as well): <a href="https://kevinholman.com/2016/02/03/checklist-removing-migrating-old-management-servers-to-new-ones/">https://kevinholman.com/2016/02/03/checklist-removing-migrating-old-management-servers-to-new-ones/</a></p>
<hr />
<h2 id="powershell-script-to-move-agentless-managed-machines">Powershell Script to move Agentless-Managed Machines</h2>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#Author: Blake Drumm ([email protected])</span><span class="w">
</span><span class="c">#Date: August 8th, 2023</span><span class="w">
</span><span class="c">#------------------------------- </span><span class="w">
</span><span class="c"># Variables Section </span><span class="w">
</span><span class="c">#------------------------------- </span><span class="w">
</span><span class="nv">$FromGatewayServer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'GW01-2019.contoso-2019.com'</span><span class="w"> </span><span class="c"># Management Server or Gateway Server to move FROM</span><span class="w">
</span><span class="nv">$ToGatewayServer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'MS01-2019.contoso-2019.com'</span><span class="w"> </span><span class="c"># Management Server or Gateway Server to move TO </span><span class="w">
</span><span class="c">#-------------------------------</span><span class="w">
</span><span class="nv">$MSList</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMManagementServer</span><span class="w">
</span><span class="nv">$FromGatewayServer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$MSList</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="nv">$FromGatewayServer</span><span class="p">}</span><span class="w">
</span><span class="nv">$ToGatewayServer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$MSList</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="nv">$ToGatewayServer</span><span class="p">}</span><span class="w">
</span><span class="n">Get-SCOMAgentlessManagedComputer</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">ProxyAgentPrincipalName</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="nv">$FromGatewayServer</span><span class="o">.</span><span class="nf">DisplayName</span><span class="p">}</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Set-SCOMAgentlessManagedComputer</span><span class="w"> </span><span class="nt">-ManagedByManagementServer</span><span class="w"> </span><span class="nv">$ToGatewayServer</span><span class="w"> </span><span class="nt">-PassThru</span><span class="w">
</span></code></pre></div></div>
<hr />
<h2 id="powershell-script-to-move-agents">Powershell Script to move Agents</h2>
<p>You can find the below script (and others) here: <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/tree/master/Powershell/Agents%20Failover">https://github.com/blakedrumm/SCOM-Scripts-and-SQL/tree/master/Powershell/Agents%20Failover</a></p>
<p>Replace the following variables before running:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><MoveFrom_MS>
<MoveToPrimary_MS>
<MoveToSecondary_MS>
</code></pre></div></div>
<p>Be aware, the machines will need to be remotely manageable before you can run the below script. More information here: <a href="https://kevinholman.com/2010/02/20/how-to-get-your-agents-back-to-remotely-manageable-in-scom/">https://kevinholman.com/2010/02/20/how-to-get-your-agents-back-to-remotely-manageable-in-scom/</a></p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ===============================</span><span class="w">
</span><span class="c"># Author: Blake Drumm ([email protected])</span><span class="w">
</span><span class="c"># Created: September 30th, 2022</span><span class="w">
</span><span class="c"># Modified: September 30th, 2022</span><span class="w">
</span><span class="c"># Script location: https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Agents%20Failover/Set-AgentFailover.ps1</span><span class="w">
</span><span class="c"># ===============================</span><span class="w">
</span><span class="n">Import-Module</span><span class="w"> </span><span class="nx">OperationsManager</span><span class="w">
</span><span class="c">#===================================================================</span><span class="w">
</span><span class="c">#region Script Variables</span><span class="w">
</span><span class="c">#We will look for all Agents Managed by this Management Server.</span><span class="w">
</span><span class="nv">$movefromManagementServer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMManagementServer</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"<MoveFrom_MS>"</span><span class="w">
</span><span class="c">#Primary Management Server</span><span class="w">
</span><span class="nv">$movetoPrimaryMgmtServer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMManagementServer</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"<MoveToPrimary_MS>"</span><span class="w">
</span><span class="c">#Secondary Management Server</span><span class="w">
</span><span class="nv">$movetoFailoverMgmtServer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMManagementServer</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s1">'<MoveToSecondary_MS>'</span><span class="w">
</span><span class="c">#Gather the System Center Agent Class so we can get the Agents:</span><span class="w">
</span><span class="nv">$scomAgent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMClass</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">name</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="s2">"Microsoft.SystemCenter.Agent"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Get-SCOMClassInstance</span><span class="w">
</span><span class="c">#endregion Variables</span><span class="w">
</span><span class="c">#===================================================================</span><span class="w">
</span><span class="c">#===================================================================</span><span class="w">
</span><span class="c">#region MainScript</span><span class="w">
</span><span class="nv">$i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w">
</span><span class="kr">foreach</span><span class="w"> </span><span class="p">(</span><span class="nv">$agent</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="nv">$scomAgent</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$i</span><span class="o">++</span><span class="w">
</span><span class="nv">$i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$i</span><span class="w">
</span><span class="c">#Check the name of the current</span><span class="w">
</span><span class="nv">$scomAgentDetails</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMAgent</span><span class="w"> </span><span class="nt">-ManagementServer</span><span class="w"> </span><span class="nv">$movefromManagementServer</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">DisplayName</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="nv">$agent</span><span class="o">.</span><span class="nf">DisplayName</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$scomAgentDetails</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c">#Remove Failover Management Server</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"(</span><span class="nv">$i</span><span class="s2">/</span><span class="si">$(</span><span class="nv">$scomAgent</span><span class="o">.</span><span class="nf">count</span><span class="si">)</span><span class="s2">) </span><span class="si">$(</span><span class="nv">$agent</span><span class="o">.</span><span class="nf">DisplayName</span><span class="si">)</span><span class="se">`n`t`t</span><span class="s2">Removing Failover"</span><span class="w">
</span><span class="nv">$scomAgentDetails</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Set-SCOMParentManagementServer</span><span class="w"> </span><span class="nt">-FailoverServer</span><span class="w"> </span><span class="bp">$null</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-Null</span><span class="w">
</span><span class="c">#Set Primary Management Server</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`t`t</span><span class="s2">Current Primary: </span><span class="si">$(</span><span class="nv">$movefromManagementServer</span><span class="o">.</span><span class="nf">DisplayName</span><span class="si">)</span><span class="se">`n`t`t</span><span class="s2">Updating Primary to: </span><span class="si">$(</span><span class="nv">$movetoPrimaryMgmtServer</span><span class="o">.</span><span class="nf">DisplayName</span><span class="si">)</span><span class="s2">"</span><span class="w">
</span><span class="nv">$scomAgentDetails</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Set-SCOMParentManagementServer</span><span class="w"> </span><span class="nt">-PrimaryServer</span><span class="w"> </span><span class="nv">$movetoPrimaryMgmtServer</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-Null</span><span class="w">
</span><span class="nx">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$movetoFailoverMgmtServer</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="nv">$movetoFailoverMgmtServer</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="s1">'<MoveToSecondary_MS>'</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="c">#Set Secondary Management Server</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">" </span><span class="si">$(</span><span class="nv">$agent</span><span class="o">.</span><span class="nf">DisplayName</span><span class="si">)</span><span class="s2"> Failover: </span><span class="si">$(</span><span class="nv">$movetoFailoverMgmtServer</span><span class="o">.</span><span class="nf">DisplayName</span><span class="si">)</span><span class="se">`n`n</span><span class="s2">"</span><span class="w">
</span><span class="nv">$scomAgentDetails</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Set-SCOMParentManagementServer</span><span class="w"> </span><span class="nt">-FailoverServer</span><span class="w"> </span><span class="nv">$movetoFailoverMgmtServer</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-Null</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">else</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Verbose</span><span class="w"> </span><span class="s2">"Unable to locate any data."</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"Script completed!"</span><span class="w">
</span><span class="c">#endregion MainScript</span><span class="w">
</span><span class="c">#===================================================================</span><span class="w">
</span></code></pre></div></div>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/how-to-decommission-scom-gateway/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
April 25, 2023
https://blakedrumm.com/blog/how-to-decommission-scom-gateway/
https://blakedrumm.com/blog/how-to-decommission-scom-gateway/How to change SQL Server Reporting Services to use Kerberos instead of NTLM/assets/img/posts/sql-server-reporting-services.png<p>I had a customer ask if SCOM Reporting requires NTLM or not. So when I started digging for information on this, I found this blog post showing how to change SSRS to use Kerberos instead of NTLM:
<a href="https://mscloud.be/systemcenter/uncategorized/how-to-change-scom-reporting-to-use-kerberos-instead-of-ntlm-2/">How to change SCOM reporting to use Kerberos instead of NTLM - Cloud management at your fingertips (mscloud.be)</a></p>
<p>I found that the article is missing some screenshots and seems to no longer be maintained. So, I thought it would be a good time to publish something for this.</p>
<hr />
<h2 id="book-what-is-kerberos-and-ntlm">:book: What is Kerberos and NTLM</h2>
<p>If you are wondering, what is NTLM? What is Kerberos? How do these help or hurt? This article goes into detail to explain the differences: <br />
<a href="https://www.geeksforgeeks.org/difference-between-kerberos-and-ntlm/">Difference between Kerberos and NTLM</a></p>
<hr />
<h2 id="exclamation-scom-reporting-installation-quirk">:exclamation: SCOM Reporting Installation Quirk</h2>
<p>Something you need to take into account is that the SCOM installation for Reporting will overwrite the <code class="language-plaintext highlighter-rouge">rsreportserver.config</code> file and reverse any changes you may perform (which will set authentication back to NTLM). Which means you will need to apply the steps to change to Kerberos again <strong>AFTER</strong> SCOM Reporting Installation.</p>
<hr />
<h2 id="page_with_curl-how-to-change-ssrs-authentication">:page_with_curl: How to change SSRS Authentication</h2>
<h3 id="memo-manually-change-ssrs-authentication">:memo: Manually change SSRS Authentication</h3>
<ul>
<li>To change the report server authentication settings, edit the value in the <code class="language-plaintext highlighter-rouge">rsreportserver.config</code> file:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\ReportServer\rsreportserver.config
</code></pre></div> </div>
<p>Replace <code class="language-plaintext highlighter-rouge">RSWindowsNTLM</code> with <code class="language-plaintext highlighter-rouge">RSWindowsNegotiate</code> in the config file.</p>
<p>My config file: <a href="https://files.blakedrumm.com/rsreportserver.config">https://files.blakedrumm.com/rsreportserver.config</a></p>
</li>
</ul>
<h3 id="zap-automatically-change-ssrs-authentication-with-powershell">:zap: Automatically change SSRS Authentication with PowerShell</h3>
<ul>
<li>This script will allow you to automatically set the Authentication for SSRS to <strong>Windows Negotiate</strong> instead of <strong>NTLM</strong>:
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$RS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"root\Microsoft\SqlServer\ReportServer\"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">((</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="s1">'root\Microsoft\SqlServer\ReportServer'</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">__Namespace</span><span class="p">)</span><span class="o">.</span><span class="nf">CimInstanceProperties</span><span class="p">)</span><span class="o">.</span><span class="nf">Value</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-First</span><span class="w"> </span><span class="nx">1</span><span class="w">
</span><span class="nv">$RSV</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">__Namespace</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-First</span><span class="w"> </span><span class="nx">1</span><span class="p">)</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\Admin"</span><span class="w">
</span><span class="nv">$RSInfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nv">$RSV</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">MSReportServer_ConfigurationSetting</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="p">(</span><span class="n">Get-Content</span><span class="w"> </span><span class="p">(</span><span class="nv">$RSInfo</span><span class="p">)</span><span class="o">.</span><span class="nf">PathName</span><span class="p">)</span><span class="o">.</span><span class="nf">Replace</span><span class="p">(</span><span class="s2">"<RSWindowsNTLM"</span><span class="p">,</span><span class="s2">"<RSWindowsNegotiate"</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-File</span><span class="w"> </span><span class="p">(</span><span class="nv">$RSInfo</span><span class="p">)</span><span class="o">.</span><span class="nf">PathName</span><span class="w"> </span><span class="nt">-Encoding</span><span class="w"> </span><span class="n">UTF8</span><span class="w">
</span></code></pre></div> </div>
</li>
</ul>
<hr />
<h2 id="page_with_curl-set-ssrs-spns">:page_with_curl: Set SSRS SPN’s</h2>
<p>Using RSWindowsNegotiate will result in a Kerberos authentication error if you configured the Report Server service to run under a domain user account and you did not register a Service Principal Name (SPN) for the account. For more information on SPN’s for SSRS see: <br />
<a href="https://learn.microsoft.com/sql/reporting-services/report-server/register-a-service-principal-name-spn-for-a-report-server">Register a Service Principal Name (SPN) for a Report Server - SQL Server Reporting Services (SSRS) | Microsoft Learn</a></p>
<h3 id="memo-check-ssrs-spns">:memo: Check SSRS SPN’s</h3>
<ul>
<li>The following command allows you to check the SPN’s for the SSRS Server, you will need to replace the username with the service account running SSRS:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>setspn -l <domain>\<domain-user-account>
</code></pre></div> </div>
</li>
</ul>
<h3 id="memo-manually-set-ssrs-spns">:memo: Manually set SSRS SPN’s</h3>
<ul>
<li>The following command allows you to set the SPN’s for the SSRS Server:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>setspn -s http/<computer-name>.<domain-name> <domain>\<domain-user-account>
</code></pre></div> </div>
</li>
</ul>
<h3 id="zap-automatically-set-ssrs-spns">:zap: Automatically set SSRS SPN’s</h3>
<ul>
<li>The following script allows you to automatically set the SSRS SPN’s:
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$RS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"root\Microsoft\SqlServer\ReportServer\"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">((</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="s1">'root\Microsoft\SqlServer\ReportServer'</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">__Namespace</span><span class="p">)</span><span class="o">.</span><span class="nf">CimInstanceProperties</span><span class="p">)</span><span class="o">.</span><span class="nf">Value</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-First</span><span class="w"> </span><span class="nx">1</span><span class="w">
</span><span class="nv">$RSV</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">__Namespace</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-First</span><span class="w"> </span><span class="nx">1</span><span class="p">)</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\Admin"</span><span class="w">
</span><span class="nv">$RSInfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nv">$RSV</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">MSReportServer_ConfigurationSetting</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="c"># Get Computer FQDN</span><span class="w">
</span><span class="nv">$DNSComputerName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">COMPUTERNAME</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'.'</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nx">Win32_ComputerSystem</span><span class="p">)</span><span class="o">.</span><span class="nf">Domain</span><span class="w">
</span><span class="c"># Set SSRS SPN</span><span class="w">
</span><span class="nv">$setspn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">setspn</span><span class="w"> </span><span class="nt">-s</span><span class="w"> </span><span class="s2">"http/</span><span class="nv">$DNSComputerName</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="nv">$RSInfo</span><span class="o">.</span><span class="nf">WindowsServiceIdentityActual</span><span class="si">)</span><span class="s2">"</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$setspn</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="s2">"^Duplicate SPN found, aborting operation!$"</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"SPN is already set or duplicate SPN found."</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Check SSRS SPN</span><span class="w">
</span><span class="n">setspn</span><span class="w"> </span><span class="nt">-l</span><span class="w"> </span><span class="nv">$RSInfo</span><span class="o">.</span><span class="nf">WindowsServiceIdentityActual</span><span class="w">
</span></code></pre></div> </div>
</li>
</ul>
<hr />
<h2 id="closed_lock_with_key-set-the-kerberos-aes-encryption-support">:closed_lock_with_key: Set the Kerberos AES Encryption Support</h2>
<p>Enable “This account supports Kerberos AES 128 bit encryption.” and “This account supports Kerberos AES 256 bit encryption.”</p>
<h3 id="memo-manually-set-the-kerberos-aes-encryption-support">:memo: Manually set the Kerberos AES Encryption Support</h3>
<ol>
<li>Open a run box (<strong>Windows Key + R</strong>).</li>
<li>Type in <code class="language-plaintext highlighter-rouge">dsa.msc</code> and press Enter.</li>
<li>Select the domain, right click and select <strong>Find</strong>.</li>
<li>Locate the Service Account for your <strong>Data Reader Account</strong> and <strong>Data Access Service Account</strong>.</li>
<li>Open the properties and go to the Account Tab.</li>
<li>Scroll down in the <strong>Account options:</strong> section and locate “This account supports Kerberos AES 128 bit encryption.” and “This account supports Kerberos AES 256 bit encryption.” <br />
<img src="/assets/img/posts/kerberos-aes-encryption.png" alt="Example of Kerberos AES encryption support checkboxes (OMRead)" class="img-fluid" /> <br />
<br />
<img src="/assets/img/posts/kerberos-aes-encryption-2.png" alt="Example of Kerberos AES encryption support checkboxes (OMDAS)" class="img-fluid" /></li>
</ol>
<h3 id="zap-set-the-kerberos-aes-encryption-support-via-powershell">:zap: Set the Kerberos AES Encryption Support via PowerShell</h3>
<p>Enable Kerberos AES Encryption for <strong>OMDAS</strong> (Data Access Service Account) and <strong>OMRead</strong> (Data Reader account) via PowerShell, you only have to modify the bottom line in the below script to your UserNames:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm"><#
</span><span class="cs">.SYNOPSIS</span><span class="cm">
This PowerShell script is designed to manage Kerberos AES encryption settings for specified user accounts in Active Directory.
</span><span class="cs">.DESCRIPTION</span><span class="cm">
The Set-KerberosAESEncryption function enables or disables Kerberos Advanced Encryption Standard (AES) 128-bit and 256-bit encryption for given Active Directory user accounts. It provides options to either enable or disable these encryption settings based on the provided parameters.
The script uses the System.DirectoryServices.AccountManagement namespace for accessing and modifying the properties of Active Directory user accounts. It updates the 'msDS-SupportedEncryptionTypes' property to set or unset AES 128 and AES 256 encryption types.
</span><span class="cs">.PARAMETER</span><span class="cm">S
- UserNames: An array of user account names (strings) in Active Directory for which the encryption settings will be modified.
- EnableEncryption: A switch parameter. When used, the script sets the Kerberos AES 128 and 256-bit encryption for the specified user accounts.
- DisableEncryption: A switch parameter. When used, the script unsets the Kerberos AES 128 and 256-bit encryption for the specified user accounts.
.OUTPUT
The script outputs a table with the following columns for each user account processed:
- UserName: The name of the user account.
- PreviousEncryptionTypes: The encryption types (AES 128, AES 256, both, or Not Set) before the script execution.
- UpdatedEncryptionTypes: The encryption types after the script execution.
- UpdateApplied: Indicates whether an update was applied ('Yes' or 'No').
</span><span class="cs">.EXAMPLE</span><span class="cm">
To enable Kerberos AES encryption for users 'OMDAS' and 'OMRead':
Set-KerberosAESEncryption -UserNames @("OMDAS", "OMRead") -EnableEncryption
</span><span class="cs">.EXAMPLE</span><span class="cm">
To disable Kerberos AES encryption for users 'OMDAS' and 'OMRead':
Set-KerberosAESEncryption -UserNames @("OMDAS", "OMRead") -DisableEncryption
</span><span class="cs">.NOTES</span><span class="cm">
Ensure you have appropriate permissions to modify user properties in Active Directory before running this script. It's recommended to test the script in a non-production environment first.
Author: Blake Drumm ([email protected])
Date Created: November 21st, 2023
#></span><span class="w">
</span><span class="c"># Add required assembly references</span><span class="w">
</span><span class="n">Add-Type</span><span class="w"> </span><span class="nt">-AssemblyName</span><span class="w"> </span><span class="nx">System.DirectoryServices.AccountManagement</span><span class="w">
</span><span class="c"># Function to manage Kerberos AES encryption settings</span><span class="w">
</span><span class="kr">function</span><span class="w"> </span><span class="nf">Set-KerberosAESEncryption</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="kr">param</span><span class="w"> </span><span class="p">(</span><span class="w">
</span><span class="p">[</span><span class="n">string</span><span class="p">[]]</span><span class="nv">$UserNames</span><span class="p">,</span><span class="w">
</span><span class="p">[</span><span class="n">switch</span><span class="p">]</span><span class="nv">$EnableEncryption</span><span class="p">,</span><span class="w">
</span><span class="p">[</span><span class="n">switch</span><span class="p">]</span><span class="nv">$DisableEncryption</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="o">-NOT</span><span class="w"> </span><span class="nv">$EnableEncryption</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="o">-NOT</span><span class="w"> </span><span class="nv">$DisableEncryption</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"Missing required parameter: -EnableEncryption OR -DisableEncryption"</span><span class="w">
</span><span class="kr">break</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Define encryption type values</span><span class="w">
</span><span class="nv">$AES128</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="n">x08</span><span class="w">
</span><span class="nv">$AES256</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="n">x10</span><span class="w">
</span><span class="c"># Combine AES 128 and AES 256 bit encryption support</span><span class="w">
</span><span class="nv">$newEncryptionTypes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$AES128</span><span class="w"> </span><span class="o">-bor</span><span class="w"> </span><span class="nv">$AES256</span><span class="w">
</span><span class="c"># Function to convert encryption type value to readable format</span><span class="w">
</span><span class="kr">function</span><span class="w"> </span><span class="nf">ConvertTo-EncryptionTypeName</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="kr">param</span><span class="w"> </span><span class="p">(</span><span class="nv">$encryptionTypeValue</span><span class="p">)</span><span class="w">
</span><span class="kr">switch</span><span class="w"> </span><span class="p">(</span><span class="nv">$encryptionTypeValue</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"Not Set"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="mi">0</span><span class="n">x08</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"AES 128"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="mi">0</span><span class="n">x10</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"AES 256"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="mi">24</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"AES 128, AES 256"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="n">Default</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"Unknown"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Initialize an array to store output data</span><span class="w">
</span><span class="nv">$outputData</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@()</span><span class="w">
</span><span class="kr">foreach</span><span class="w"> </span><span class="p">(</span><span class="nv">$userName</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="nv">$UserNames</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="kr">try</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="c"># Create a principal context for the domain</span><span class="w">
</span><span class="nv">$context</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.DirectoryServices.AccountManagement.PrincipalContext</span><span class="p">([</span><span class="n">System.DirectoryServices.AccountManagement.ContextType</span><span class="p">]::</span><span class="n">Domain</span><span class="p">)</span><span class="w">
</span><span class="c"># Find the user</span><span class="w">
</span><span class="nv">$user</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">System.DirectoryServices.AccountManagement.UserPrincipal</span><span class="p">]::</span><span class="n">FindByIdentity</span><span class="p">(</span><span class="nv">$context</span><span class="p">,</span><span class="w"> </span><span class="nv">$userName</span><span class="p">)</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$user</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="bp">$null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="c"># Access the underlying DirectoryEntry</span><span class="w">
</span><span class="nv">$de</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$user</span><span class="o">.</span><span class="nf">GetUnderlyingObject</span><span class="p">()</span><span class="w">
</span><span class="c"># Get current encryption types</span><span class="w">
</span><span class="nv">$currentEncryptionTypes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$de</span><span class="o">.</span><span class="n">Properties</span><span class="p">[</span><span class="s2">"msDS-SupportedEncryptionTypes"</span><span class="p">]</span><span class="o">.</span><span class="nf">Value</span><span class="w">
</span><span class="nv">$currentEncryptionTypes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$currentEncryptionTypes</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="bp">$null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nv">$currentEncryptionTypes</span><span class="w"> </span><span class="o">-as</span><span class="w"> </span><span class="p">[</span><span class="n">int</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="c"># Determine if update is needed</span><span class="w">
</span><span class="nv">$changeNeeded</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="nv">$EnableEncryption</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="nv">$currentEncryptionTypes</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="nv">$newEncryptionTypes</span><span class="p">)</span><span class="w"> </span><span class="o">-or</span><span class="w">
</span><span class="p">(</span><span class="nv">$DisableEncryption</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="nv">$currentEncryptionTypes</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span><span class="c"># Update encryption types if needed</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$changeNeeded</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">$de</span><span class="o">.</span><span class="n">Properties</span><span class="p">[</span><span class="s2">"msDS-SupportedEncryptionTypes"</span><span class="p">]</span><span class="o">.</span><span class="nf">Value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$EnableEncryption</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nv">$newEncryptionTypes</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$null</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="nv">$de</span><span class="o">.</span><span class="nf">CommitChanges</span><span class="p">()</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Add data to the output array</span><span class="w">
</span><span class="nv">$updatedEncryptionTypes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$de</span><span class="o">.</span><span class="n">Properties</span><span class="p">[</span><span class="s2">"msDS-SupportedEncryptionTypes"</span><span class="p">]</span><span class="o">.</span><span class="nf">Value</span><span class="w">
</span><span class="nv">$updatedEncryptionTypes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$updatedEncryptionTypes</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="bp">$null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nv">$updatedEncryptionTypes</span><span class="w"> </span><span class="o">-as</span><span class="w"> </span><span class="p">[</span><span class="n">int</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="nv">$outputData</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">PSObject</span><span class="w"> </span><span class="nt">-Property</span><span class="w"> </span><span class="p">@{</span><span class="w">
</span><span class="nx">UserName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$userName</span><span class="w">
</span><span class="nx">PreviousEncryptionTypes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">ConvertTo</span><span class="err">-</span><span class="nx">EncryptionTypeName</span><span class="w"> </span><span class="err">-</span><span class="nx">encryptionTypeValue</span><span class="w"> </span><span class="nv">$currentEncryptionTypes</span><span class="w">
</span><span class="nx">UpdatedEncryptionTypes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">ConvertTo</span><span class="err">-</span><span class="nx">EncryptionTypeName</span><span class="w"> </span><span class="err">-</span><span class="nx">encryptionTypeValue</span><span class="w"> </span><span class="nv">$updatedEncryptionTypes</span><span class="w">
</span><span class="nx">UpdateApplied</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">if</span><span class="w"> </span><span class="err">(</span><span class="nv">$changeNeeded</span><span class="err">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"Yes"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="nx">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"No"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"User </span><span class="nv">$userName</span><span class="s2"> not found."</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="kr">catch</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"Error updating user </span><span class="nv">$userName</span><span class="se">`:</span><span class="s2"> </span><span class="bp">$_</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Output the results in a single table</span><span class="w">
</span><span class="nv">$outputData</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Format-Table</span><span class="w"> </span><span class="nt">-AutoSize</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c"># Example usage of the function</span><span class="w">
</span><span class="n">Set-KerberosAESEncryption</span><span class="w"> </span><span class="nt">-UserNames</span><span class="w"> </span><span class="s2">"OMDAS"</span><span class="p">,</span><span class="w"> </span><span class="s2">"OMRead"</span><span class="w"> </span><span class="nt">-EnableEncryption</span><span class="w">
</span></code></pre></div></div>
<hr />
<h2 id="memo-restart-ssrs-service">:memo: Restart SSRS Service</h2>
<p>The following script allows you to restart the SSRS Service:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"root\Microsoft\SqlServer\ReportServer\"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">((</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="s1">'root\Microsoft\SqlServer\ReportServer'</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">__Namespace</span><span class="p">)</span><span class="o">.</span><span class="nf">CimInstanceProperties</span><span class="p">)</span><span class="o">.</span><span class="nf">Value</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-First</span><span class="w"> </span><span class="nx">1</span><span class="w">
</span><span class="nv">$RSV</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nv">$RS</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">__Namespace</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-First</span><span class="w"> </span><span class="nx">1</span><span class="p">)</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\Admin"</span><span class="w">
</span><span class="nv">$RSInfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="nv">$RSV</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">MSReportServer_ConfigurationSetting</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w">
</span><span class="c"># Restart SSRS Service</span><span class="w">
</span><span class="n">Restart-Service</span><span class="w"> </span><span class="p">(</span><span class="nv">$RSInfo</span><span class="p">)</span><span class="o">.</span><span class="nf">ServiceName</span><span class="w">
</span></code></pre></div></div>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/how-to-change-reporting-to-use-kerberos-instead-of-ntlm/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
April 19, 2023
https://blakedrumm.com/blog/how-to-change-reporting-to-use-kerberos-instead-of-ntlm/
https://blakedrumm.com/blog/how-to-change-reporting-to-use-kerberos-instead-of-ntlm/All Operations Manager Event ID's/assets/img/posts/operations-manager-event-log.png<table id="scom_event_ids_table" class="table table-dark table-hover table-sm" data-toggle="table" data-url="/assets/js/post_asset/scom_event_ids.json" data-show-columns="true" data-cookie="true" data-cookie-id-table="saveId" data-pagination="true" data-search="true" data-click-to-select="true" data-show-copy-rows="true" data-show-print="true">
<thead>
<tr>
<th data-checkbox="true"></th>
<th scope="col" data-field="Event">Event</th>
<th scope="col" data-field="Source">Source</th>
<th scope="col" data-field="Log Name">Log Name</th>
<th scope="col" data-field="LongID">LongID</th>
<th scope="col" data-field="Description">Description</th>
</tr>
</thead>
</table>
<hr />
<p><img src="/assets/img/posts/excel-icon.png" alt="Excel Icon" class="img-fluid" /> <br />
Link to download excel file: <a href="https://files.blakedrumm.com/All%20SCOM%20Event%20Ids.xlsx">https://files.blakedrumm.com/All%20SCOM%20Event%20Ids.xlsx</a></p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/all-scom-event-ids/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
March 28, 2023
https://blakedrumm.com/blog/all-scom-event-ids/
https://blakedrumm.com/blog/all-scom-event-ids/SCOM Certificate Checker Script/assets/img/posts/scom-certificate-script.png<h2 id="book-introduction">:book: Introduction</h2>
<p>This tool will allow you to check your SCOM Certificate. It is very efficient and has been improved upon over time. You may edit line <code class="language-plaintext highlighter-rouge">751</code> to allow you to change what happens when you run from Powershell ISE. Copying and pasting the script to Powershell ISE after you run MOMCertImport on a certificate is the most common way to run the script, which requires no arguments or modifications. Just run the script and you will see where the issue may be.</p>
<h2 id="memo-authors">:memo: Authors</h2>
<ul>
<li>Tyson Paul (<strong><em>https://monitoringguys.com/</em></strong>)</li>
<li>Lincoln Atkinson (<strong><em>https://latkin.org/blog/</em></strong>)</li>
<li>Mike Kallhoff</li>
<li>Blake Drumm (<strong><em>https://blakedrumm.com/</em></strong>)</li>
</ul>
<h2 id="page_with_curl-where-to-get-it">:page_with_curl: Where to get it</h2>
<p><a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Test-SCOMCertificate.ps1">Test-SCOMCertificate.ps1</a> :arrow_left: <strong>Direct Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Test-SCOMCertificate.ps1">Personal File Server - Test-SCOMCertificate.ps1</a> :arrow_left: <strong>Alternative Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Test-SCOMCertificate.txt">Personal File Server - Test-SCOMCertificate.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></p>
<h2 id="classical_building-argument-list">:classical_building: Argument List</h2>
<table class="table table-hover table-text d-block overflow-auto">
<thead>
<tr>
<th>Argument List </th>
<th>Description </th>
</tr>
</thead>
<tbody>
<tr>
<td>-All </td>
<td>Check All Certificates in Local Machine Store. </td>
</tr>
<tr>
<td>-Servers </td>
<td>Each Server you want to Check SCOM Certificates on. </td>
</tr>
<tr>
<td>-SerialNumber </td>
<td>Check a specific Certificate serial number in the Local Machine Personal Store. Not reversed. </td>
</tr>
<tr>
<td>-OutputFile </td>
<td>Where to Output the File (txt, log, etc) for Script Execution. </td>
</tr>
</tbody>
</table>
<h2 id="question-examples">:question: Examples</h2>
<blockquote>
<h4 id="example-1">Example 1</h4>
<p>Check the certificate you have currently configured for SCOM on the local machine:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\</span><span class="err">></span><span class="w"> </span><span class="o">.</span><span class="nx">\Test-SCOMCertificate.ps1</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-2">Example 2</h4>
<p>Check for a specific Certificate Serial number in the Local Machine Personal Certificate store:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\</span><span class="err">></span><span class="w"> </span><span class="o">.</span><span class="nx">\Test-SCOMCertificate.ps1</span><span class="w"> </span><span class="nt">-SerialNumber</span><span class="w"> </span><span class="nx">1f00000008c694dac94bcfdc4a000000000008</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-3">Example 3</h4>
<p>Check all certificates on the local machine:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\</span><span class="err">></span><span class="w"> </span><span class="o">.</span><span class="nx">\Test-SCOMCertificate.ps1</span><span class="w"> </span><span class="nt">-All</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-4">Example 4</h4>
<p>Check All Certificates on 4 Servers and outputting the results to C:\Temp\Output.txt:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\</span><span class="err">></span><span class="w"> </span><span class="o">.</span><span class="nx">\Test-SCOMCertificate.ps1</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">ManagementServer1</span><span class="p">,</span><span class="w"> </span><span class="nx">ManagementServer2.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">Gateway.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">Agent1.contoso.com</span><span class="w"> </span><span class="nt">-All</span><span class="w"> </span><span class="nt">-OutputFile</span><span class="w"> </span><span class="nx">C:\Temp\Output.txt</span><span class="w">
</span></code></pre></div> </div>
</blockquote>
<h2 id="example-of-failure">Example of Failure</h2>
<p><img src="/assets/img/posts/example-of-failure-scom-cert-checker.png" alt="Picture of an example of the script failing" class="img-fluid" /></p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-certificate-checker-script/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
February 27, 2023
https://blakedrumm.com/blog/scom-certificate-checker-script/
https://blakedrumm.com/blog/scom-certificate-checker-script/SCOM SDK Crashing - Cannot Generate SSPI Context/assets/img/posts/udl-test-sspi-context.png<h2 id="book-introduction">:book: Introduction</h2>
<p>I had a case recently for a customer that is having issues when opening the SCOM Console. Ultimately this was due to the SCOM SDK Service crashing, with the following Event in the Operations Manager Event Log:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Log Name: Operations Manager
Source: OpsMgr Management Configuration
Date: 1/24/2023 12:11:06 PM
Event ID: 29112
Task Category: None
Level: Error
User: N/A
Computer: MS01.contoso.com
Description:
OpsMgr Management Configuration Service failed to execute bootstrap work item 'ConfigurationDataProviderInitializeWorkItem' due to the following exception
System.Data.SqlClient.SqlException (0x80131904): The target principal name is incorrect. Cannot generate SSPI context.
at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, DbConnectionPool pool, String accessToken, Boolean applyTransientFaultHandling, SqlAuthenticationProviderManager sqlAuthProviderManager)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at Microsoft.EnterpriseManagement.ManagementConfiguration.DataAccessLayer.ConnectionManagementOperation.Execute()
at Microsoft.EnterpriseManagement.ManagementConfiguration.DataAccessLayer.DataAccessOperation.ExecuteSynchronously(Int32 timeoutSeconds, WaitHandle stopWaitHandle)
at Microsoft.EnterpriseManagement.ManagementConfiguration.CmdbOperations.CmdbDataProvider.Initialize()
at Microsoft.EnterpriseManagement.ManagementConfiguration.Engine.ConfigurationDataProviderInitializeWorkItem.ExecuteWorkItem()
at Microsoft.EnterpriseManagement.ManagementConfiguration.Interop.ConfigServiceEngineWorkItem.Execute()
ClientConnectionId:c0z7eb24-124d-46ed-xe78-36q2ba9f7949
</code></pre></div></div>
<h2 id="page_with_curl-how-to-fix-1">:page_with_curl: How to fix #1</h2>
<p>In order to resolve this issue for my customer, first we verified if RC4 was disabled (RC4 was disabled) <strong><em>(More Information here: <a href="https://techcommunity.microsoft.com/t5/core-infrastructure-and-security/decrypting-the-selection-of-supported-kerberos-encryption-types/ba-p/1628797">Decrypting the Selection of Supported Kerberos Encryption Types - Microsoft Tech Community</a>)</em></strong>. Then we had to verify the user account running the Operations Manager SQL Service has AES Attributes enabled. Navigate to the user object in Active Directory and verify that the Account options have the following:</p>
<ul>
<li>Check This account supports Kerberos AES 128 bit encryption.</li>
<li>Check This account supports Kerberos AES 256 bit encryption.</li>
</ul>
<p><img src="/assets/img/posts/attributes-domain-controller.png" alt="Attributes for SCOM Account" class="img-fluid" /></p>
<p>We were no longer having an issue with the SDK Service crashing after this change.</p>
<p>Relevant Article: <a href="https://learn.microsoft.com/system-center/scom/install-with-rc4-disabled#configure-the-encryption-types-allowed-for-kerberos">https://learn.microsoft.com/system-center/scom/install-with-rc4-disabled#configure-the-encryption-types-allowed-for-kerberos</a></p>
<hr />
<h2 id="page_with_curl-how-to-fix-2">:page_with_curl: How to fix #2</h2>
<p>You may also resolve the above issue by fixing SPN information for the MSSQLSvc <em>(thank you Joana da Rocha Carvalho!)</em>:</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">nslookup</code> the SCOM SQL Database Instance(s)</li>
<li>Update the SPN information for the SQL Service Account with the following command:
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">setspn</span><span class="w"> </span><span class="nt">-S</span><span class="w"> </span><span class="nx">MSSQLSvc/SERVER.contoso.com:1433</span><span class="w"> </span><span class="nx">emea\SQLSVCaccount</span><span class="w">
</span></code></pre></div> </div>
</li>
<li>Check SPN for SQL Service Account:
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">setspn</span><span class="w"> </span><span class="nt">-L</span><span class="w"> </span><span class="nx">emea\SQLSVCaccount</span><span class="w">
</span></code></pre></div> </div>
</li>
</ol>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/cannot-generate-sspi-context/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 24, 2023
https://blakedrumm.com/blog/cannot-generate-sspi-context/
https://blakedrumm.com/blog/cannot-generate-sspi-context/SCOM Agent Installation Error - Microsoft ESENT Keys are required/assets/img/scom-agent-esent-error.png<h2 id="book-introduction">:book: Introduction</h2>
<p>I had a case recently for a customer that is having issues when installing an SCOM Agent (<strong><em>MOMAgent.msi</em></strong>) with an warning which stated:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Microsoft ESENT Keys are required to install this application.
Please see the release notes for more information.
</code></pre></div></div>
<h2 id="page_with_curl-how-to-fix">:page_with_curl: How to fix</h2>
<p>In order to resolve this issue for my customer, we had to run the installer as administrator. Which we accomplished by opening a Powershell window as administrator and navigating to the directory of the SCOM Agent installer (<strong><em>MOMAgent.msi</em></strong>).</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/esent-keys-required/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 5, 2023
https://blakedrumm.com/blog/esent-keys-required/
https://blakedrumm.com/blog/esent-keys-required/Create Custom PowerShell CPU Monitor/assets/img/posts/custom-cpu-usage-monitor-alert.png<h2 id="book-introduction">:book: Introduction</h2>
<p>Recently I had a case and I needed to assist my customer with a CPU Monitor that targets all Windows Computers. The customer is using the PowerShell Authoring Community MP by Cookdown. I will document my steps to get this working as intended.</p>
<h2 id="red_circle-prerequisites">:red_circle: Prerequisites</h2>
<ul>
<li>Import Cookdown PowerShell Monitoring - Community Management Pack (<a href="https://www.cookdown.com/scom-essentials/powershell-authoring/">https://www.cookdown.com/scom-essentials/powershell-authoring/</a>)</li>
</ul>
<h2 id="heavy_check_mark-example-mp">:heavy_check_mark: Example MP</h2>
<p>You can get a copy of the Management Pack I created in this guide, here: <br />
<a href="https://files.blakedrumm.com/custom.monitor.for.cpu.usage.xml">Custom Monitor for CPU Usage</a> :arrow_left: <strong>Direct Download Link</strong></p>
<blockquote>
<h2 id="notebook-note">:notebook: Note</h2>
<p>This guide will require you to edit the Management Pack directly, be aware that you need to be careful when editing any Management Pack to ensure you do not accidently change the wrong thing.</p>
</blockquote>
<p> </p>
<h2 id="page_with_curl-start-of-guide">:page_with_curl: Start of Guide</h2>
<h3 id="step-1-create-a-new-unit-monitor">Step 1. Create a new Unit Monitor</h3>
<p>You will need to create a new Unit Monitor.</p>
<ol>
<li>Open the SCOM Console and navigate to the <strong><em>Authoring Tab</em></strong> -> <strong><em>Monitors</em></strong> -> Right Click <strong><em>Monitors</em></strong> -> Hover over <strong><em>Create a Monitor</em></strong> and select <strong><em>Unit Monitor…</em></strong>: <br />
<img src="/assets/img/posts/create-a-unit-monitor.png" alt="Create Unit Monitor in SCOM Console" class="img-fluid" /></li>
<li>Open the <strong><em>Scripting</em></strong> folder -> <strong><em>PowerShell Based</em></strong> -> <strong><em>PowerShell Script Two State Monitor (Community)</em></strong> <br />
<img src="/assets/img/posts/select-unit-monitor-type-scripting.png" alt="Select Scripting and PowerShell Script" class="img-fluid" /></li>
<li>Select the appropriate Management Pack to save the new Monitor. <br />
<strong>It is HIGHLY recommended to save to a new MP instead of any existing MPs!</strong></li>
<li>Select <strong>Next ></strong></li>
<li>Type in an appropriate name / description, I used: <strong>Custom CPU Monitor</strong></li>
<li>Change the Monitor Target to <strong>Windows Computer</strong> <br />
<img src="/assets/img/posts/windows-computer-target.png" alt="Select Windows Computer as Target" class="img-fluid" /></li>
<li>Click <strong>Next ></strong> <br />
<img src="/assets/img/posts/create-unit-monitor-step1.png" alt="Verify data matches" class="img-fluid" /></li>
<li>Run every <strong>15 minutes</strong> by default, this is a good interval to start with. Click <strong>Next ></strong></li>
<li>Type in the File Name you want to use, I used: <strong>my_custom_cpu_monitoring_script.ps1</strong></li>
<li>Copy and Paste the below script into the <strong><em>Script</em></strong> section and click <strong>Next ></strong>:
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$api</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nt">-ComObject</span><span class="w"> </span><span class="s2">"MOM.ScriptAPI"</span><span class="p">;</span><span class="w">
</span><span class="nv">$PropertyBag</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$api</span><span class="o">.</span><span class="nf">CreatePropertyBag</span><span class="p">();</span><span class="w">
</span><span class="p">[</span><span class="n">int</span><span class="p">]</span><span class="nv">$Result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">int</span><span class="p">]((</span><span class="n">Get-Counter</span><span class="w"> </span><span class="s2">"\Processor(_Total)\% Processor Time"</span><span class="p">)</span><span class="o">.</span><span class="nf">CounterSamples</span><span class="o">.</span><span class="nf">CookedValue</span><span class="p">);</span><span class="w">
</span><span class="nv">$PropertyBag</span><span class="o">.</span><span class="nf">AddValue</span><span class="p">(</span><span class="s2">"CPUUsage"</span><span class="p">,</span><span class="w"> </span><span class="nv">$Result</span><span class="p">);</span><span class="w">
</span><span class="nv">$PropertyBag</span><span class="w">
</span></code></pre></div> </div>
<p><img src="/assets/img/posts/create-unit-monitor-script-pane.png" alt="Copy and paste the above script to your script pane" class="img-fluid" /></p>
</li>
<li>Copy and paste the below, when everything below has been copied, click <strong>Next ></strong>:
<ul>
<li>Parameter Name column: <code class="language-plaintext highlighter-rouge">Property[@Name="CPUUsage"]</code></li>
<li>Operator: <code class="language-plaintext highlighter-rouge">Greater than or equal to</code></li>
<li>Value: <code class="language-plaintext highlighter-rouge">50</code>
<img src="/assets/img/posts/create-unit-monitor-unhealthy.png" alt="Verify values are set for Unhealthy expression" class="img-fluid" /></li>
</ul>
</li>
<li>Copy and paste the below, when everything below has been copied, click <strong>Next ></strong>:
<ul>
<li>Parameter Name column: <code class="language-plaintext highlighter-rouge">Property[@Name="CPUUsage"]</code></li>
<li>Operator: <code class="language-plaintext highlighter-rouge">Less than</code></li>
<li>Value: <code class="language-plaintext highlighter-rouge">50</code>
<img src="/assets/img/posts/create-unit-monitor-healthy.png" alt="Verify values are set for Healthy expression" class="img-fluid" /></li>
</ul>
</li>
<li>Optional: Change Unhealthy from Warning to Critical.
<img src="/assets/img/posts/create-unit-monitor-configurehealth.png" alt="Configure Monitor Health" class="img-fluid" /></li>
<li>Click the <strong><em>Generate alerts for this monitor</em></strong> checkbox and change the Alert Description text to this:
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The CPU has reached at or above 50% usage.
Current CPU usage is: $Data/Context/Property[@Name="CPUUsage"]$%
</code></pre></div> </div>
</li>
<li>Done creating the unit monitor, now onto the more advanced stuff!</li>
</ol>
<h3 id="step-2-modify-the-management-pack">Step 2. Modify the Management Pack</h3>
<p>We will need to modify the Management Pack in order to allow the expressions to evaluate correctly. The Monitor is setup to use string values instead of integers, which will cause problems when we try to evaluate the health of the monitor.</p>
<ol>
<li>Go to <strong><em>Administration Tab</em></strong> -> <strong><em>Management Packs</em></strong> -> <strong><em>Installed Management Packs</em></strong> -> Search for the Management Pack where your Monitor is saved. Select and export the Management Pack to any location. <br />
<img src="/assets/img/posts/create-unit-monitor-export-mp.png" alt="Export Management Pack" class="img-fluid" /></li>
<li>Navigate to the exported Management Pack xml file, open the MP XML with Notepad.</li>
<li>Find and replace: <br />
<code class="language-plaintext highlighter-rouge"><XPathQuery>Property[@Name="CPUUsage"]</XPathQuery></code>
<ul>
<li>Replace any occurrences with the following: <br />
<code class="language-plaintext highlighter-rouge"><XPathQuery Type="Integer">Property[@Name="CPUUsage"]</XPathQuery></code></li>
<li>The above change allows us to interpret the output as integer, instead of string.</li>
</ul>
</li>
<li>Find and replace: <br />
<code class="language-plaintext highlighter-rouge"><Value Type="String">50</Value></code>
<ul>
<li>Replace any occurrences with the following: <br />
<code class="language-plaintext highlighter-rouge"><Value Type="Integer">50</Value></code></li>
<li>The above change allows us to interpret the output as integer, instead of string.</li>
</ul>
</li>
<li>Modify Line 5 (the version of the Management Pack) in the xml file from: <br />
<code class="language-plaintext highlighter-rouge"><Version>1.0.0.0</Version></code> <br />
to <br />
<code class="language-plaintext highlighter-rouge"><Version>1.0.0.1</Version></code></li>
<li>Save the Management Pack XML and import the Management Pack back into your environment.</li>
</ol>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/create-custom-powershell-cpu-monitor/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
December 17, 2022
https://blakedrumm.com/blog/create-custom-powershell-cpu-monitor/
https://blakedrumm.com/blog/create-custom-powershell-cpu-monitor/Reconfigure System Center Operations Manager for Database Move Tool/assets/img/scom-db-move-tool.png<h2 id="book-introduction">:book: Introduction</h2>
<p>Welcome to the official page for the Reconfigure System Center Operations Manager for Database Move Tool. This tool is compatible with all versions of Operations Manager and is designed to help you manage SQL connections used by Operations Manager.</p>
<p>This script automates the steps outlined here: <a href="https://learn.microsoft.com/system-center/scom/manage-move-opsdb">https://learn.microsoft.com/system-center/scom/manage-move-opsdb</a></p>
<blockquote>
<h4 id="spiral_notepad-note">:spiral_notepad: Note</h4>
<p>The script does not edit the Reporting Services <strong>Data Warehouse Data Source</strong> -> <strong><em>Connection String</em></strong> <br />
(shown here (change to https if you are using SSL Certificates): <code class="language-plaintext highlighter-rouge">http://<reportingServerURL>/Reports/manage/catalogitem/properties/Data%20Warehouse%20Main</code>) <br />
You will need to update the Connection String value to the correct data, here is an example of mine:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>data source=SQL01-2022;initial catalog=OperationsManagerDW;Integrated Security=SSPI
</code></pre></div> </div>
<p><img src="/assets/img/posts/sql-server-reporting-services-data-source-example.png" alt="SQL Server Reporting Services Data Source Example" class="img-fluid" /></p>
</blockquote>
<h3 id="features">Features</h3>
<ul>
<li>Update / Verify the System Center Operations Manager SQL
<ul>
<li>SQL Instance Configuration for CLR and SQL Service Broker.</li>
<li>Database Tables for data related to SQL Connections in SCOM.</li>
</ul>
</li>
<li>Update / Verify the Registry data
<ul>
<li>Local SCOM Management Servers.</li>
<li>Remote SCOM Management Servers.</li>
</ul>
</li>
<li>Update / Verify the Configuration File
<ul>
<li>Local SCOM Management Servers.</li>
<li>Remote SCOM Management Servers.</li>
</ul>
</li>
<li>Language Changer combo-box which adds automatic support for 8 Languages:
<ul>
<li>English</li>
<li>Spanish (Español)</li>
<li>Arabic (عربي)</li>
<li>Turkish (Türkçe)</li>
<li>Chinese (中国人)</li>
<li>Portuguese (Português)</li>
<li>French (Français)</li>
<li>German (Deutsch)
<h4 id="a-huge-thank-you-to-the-following-individuals-for-assisting-with-translation-in-the-different-languages">A HUGE THANK YOU to the following individuals for assisting with translation in the different languages:</h4>
</li>
<li>Rafael Lujan (Spanish)</li>
<li>Fayez Al Saadi (Arabic)</li>
<li>Murat Coskun (Turkish)</li>
<li>Wendi Cai (Chinese)</li>
<li>Wagner da Costa Carvalho (Portuguese)</li>
<li>Joana da Rocha Carvalho (French)</li>
<li>Stefan Wuchenauer (German)</li>
</ul>
</li>
</ul>
<h3 id="requirements">Requirements</h3>
<ul>
<li>System Center Operations Manager installation</li>
<li>Powershell 5</li>
</ul>
<h2 id="arrow_down_small-latest-version">:arrow_down_small: Latest Version</h2>
<p><a href="https://github.com/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/releases/latest" class="img-shields-io"><img src="https://img.shields.io/github/v/release/blakedrumm/SCOM-Reconfigure-DB-Move-Tool" alt="Latest Version" /></a> <br />
<a href="https://github.com/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/releases" class="img-shields-io"><img src="https://img.shields.io/github/downloads/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/total.svg?style=for-the-badge&color=brightgreen" alt="Download Count Releases" /></a> <br />
<a href="https://aka.ms/SCOM-DB-Move-Tool" class="img-shields-io"><img src="https://img.shields.io/github/downloads/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/latest/SCOM-Reconfigure-DB-Move-Tool-EXE.zip?style=for-the-badge&color=brightgreen" alt="Download Count Latest" /></a></p>
<p>Check the changelog for the latest version: <a href="https://github.com/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/releases/latest">Latest Changes</a></p>
<h2 id="page_with_curl-how-to-use">:page_with_curl: How to Use</h2>
<p><a href="https://github.com/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/releases/latest/download/SCOM-Reconfigure-DB-Move-Tool-EXE.zip" target="_"><button class="btn btn-primary navbar-btn">Get Started</button></a></p>
<p><a href="https://aka.ms/SCOM-DB-Move-Tool">https://aka.ms/SCOM-DB-Move-Tool</a></p>
<p>You have multiple ways to download the SCOM Reconfigure DB Move GUI Tool:</p>
<ol>
<li>Download and install the MSI: <a href="https://github.com/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/releases/latest/download/SCOM-Reconfigure-DB-Move-Tool-MSI.zip">MSI Download</a></li>
<li>Download and run the EXE: <a href="https://github.com/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/releases/latest/download/SCOM-Reconfigure-DB-Move-Tool-EXE.zip">EXE Downloads</a></li>
<li>Download or Copy the Powershell Script to Powershell ISE: <a href="https://github.com/blakedrumm/SCOM-Reconfigure-DB-Move-Tool/releases/latest/download/SCOM-Reconfigure-DB-Move-Tool.ps1">Powershell Script</a></li>
<li>Download or Copy the Powershell Script to Powershell ISE: <a href="https://files.blakedrumm.com/SCOM-ReconfigureDatabaseLocations.txt">Text Format Alternative Download Link</a></li>
</ol>
<p>The script by default will attempt to gather the current database connection from the local registry. If it is unable to locate the registry keys the Database Connection box will be empty. If it is empty you will need to manually type the values in here. The Values to Set section is required for the script to run and you will need to manually populate these fields. The Management Servers section is also required for you to be able to set which Management Servers to update the Database information on.</p>
<p>This script will log actions to the Application Event Log. Look for the Event Source: <code class="language-plaintext highlighter-rouge">SCOMDBMoveTool</code></p>
<h2 id="page_facing_up-more-information">:page_facing_up: More Information</h2>
<p>You will get prompted each time you run the script to accept the license agreement, unless you select do not ask me again, when you select this it will save a file to your ProgramData Directory:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\ProgramData\SCOM-DBMoveTool-AgreedToLicense.log
</code></pre></div></div>
<p>Attribution for the icon:
<a href="https://www.flaticon.com/free-icons/database" title="database icons">Database icons created by manshagraphics - Flaticon</a></p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-db-move-tool/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
November 23, 2022
https://blakedrumm.com/blog/scom-db-move-tool/
https://blakedrumm.com/blog/scom-db-move-tool/Remove Data from the SCOM Database Instantly - The PowerShell Way!/assets/img/posts/remove-scombasemanagedentity.png<h2 id="book-introduction">:book: Introduction</h2>
<p>I have had many cases where I’ve had to run the following SQL Queries by Kevin Holman: <a href="https://kevinholman.com/2018/05/03/deleting-and-purging-data-from-the-scom-database/">Deleting and Purging data from the SCOM Database (kevinholman.com)</a> <strong><em>(A big thank you to Kevin Holman for his guide!)</em></strong></p>
<p>After the 6th or 7th time running the tsql queries I decided that I should automate this process in Powershell, and make it very easy to do this automatically for as many servers as needed. This script will query the Operations Manager database and run all the steps in Kevin Holman’s queries. The script will ask questions at each step to verify the action is correct. You have to answer <strong>Y</strong> or <strong>N</strong> before the script will proceed.</p>
<blockquote>
<h3 id="exclamation-important">:exclamation: Important!</h3>
<p>It is recommended to only run the script when requested by a Microsoft Support Engineer. <strong>This script can be dangerous if used incorrectly.</strong> <br />
<br />
If you absolutely need to run the script, make sure you have full backups of your SCOM SQL Instances / Databases!</p>
</blockquote>
<h2 id="arrow_down-how-to-get-it">:arrow_down: How to get it</h2>
<p>You can get a copy of the script here: <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Quick%20Fixes/Remove-SCOMBaseManagedEntity.ps1">Remove-SCOMBaseManagedEntity.ps1</a> :arrow_left: <strong>Direct Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Remove-SCOMBaseManagedEntity.ps1">Personal File Server - Remove-SCOMBaseManagedEntity.ps1</a> :arrow_left: <strong>Alternative Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Remove-SCOMBaseManagedEntity.txt">Personal File Server - Remove-SCOMBaseManagedEntity.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></p>
<blockquote>
<h2 id="notebook-note">:notebook: Note</h2>
<p>You may edit line <a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Quick%20Fixes/Remove-SCOMBaseManagedEntity.ps1#L769">769</a> in the script to change what happens when the script is run without any arguments or parameters, this also allows you to change what happens when the script is run from the Powershell ISE.</p>
</blockquote>
<p> </p>
<h2 id="classical_building-argument-list">:classical_building: Argument List</h2>
<table class="table table-hover table-text d-block overflow-auto">
<thead>
<tr>
<th>Parameter</th>
<th>Alias</th>
<th>ValueFromPipeline</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>AssumeYes</td>
<td>yes</td>
<td> </td>
<td>Switch</td>
<td>Optionally assume yes to any question asked by this script.</td>
</tr>
<tr>
<td>Database</td>
<td> </td>
<td> </td>
<td>String</td>
<td>The name of the OperationsManager Database for SCOM.</td>
</tr>
<tr>
<td>DontStop</td>
<td>ds</td>
<td> </td>
<td>Switch</td>
<td>Optionally force the script to not stop when an error occurs connecting to the Management Server.</td>
</tr>
<tr>
<td>Id</td>
<td> </td>
<td> </td>
<td>Array</td>
<td>You may provide any Base Managed Entity Id’s to be deleted specifically from the Operations Manager Database.</td>
</tr>
<tr>
<td>InputFile</td>
<td> </td>
<td> </td>
<td>String</td>
<td>A file you would like to have the script input as a list of Agents. The file should have a new line for each server.</td>
</tr>
<tr>
<td>ManagementServer</td>
<td>ms</td>
<td> </td>
<td>String</td>
<td>SCOM Management Server that we will remotely connect to. If running on a Management Server, there is no need to provide this parameter.</td>
</tr>
<tr>
<td>Name</td>
<td> </td>
<td> </td>
<td>Array</td>
<td>The Base Managed Entity Display Name of the object you are wanting to delete from the Operations Manager Database.</td>
</tr>
<tr>
<td>Servers</td>
<td> </td>
<td>True</td>
<td>Array</td>
<td>Each Server (comma separated) you want to Remove related BME ID’s related to the Display Name in the OperationsManager Database. This will also remove from Agent Managed.</td>
</tr>
<tr>
<td>SqlServer</td>
<td> </td>
<td> </td>
<td>String</td>
<td>SQL Server/Instance, Port that hosts OperationsManager Database for SCOM.</td>
</tr>
</tbody>
</table>
<h2 id="page_with_curl-how-to-use-it">:page_with_curl: How to use it</h2>
<blockquote>
<h4 id="example-1">Example 1</h4>
<p>Remove SCOM BME Related Data from the OperationsManager DB, for Agent1 in the Management Group:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Get-SCOMAgent</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">Agent1.contoso.com</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">%</span><span class="p">{</span><span class="o">.</span><span class="n">\Remove-SCOMBaseManagedEntity.ps1</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">DisplayName</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-2">Example 2</h4>
<p>Remove SCOM BME Related Data for 2 Agent machines:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Remove-SCOMBaseManagedEntity.ps1</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">IIS-Server.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">WindowsServer.contoso.com</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-3">Example 3</h4>
<p>Remove SCOM BME Related Data for 2 Agent machines automatically with no prompts / questions:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Remove-SCOMBaseManagedEntity.ps1</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">IIS-Server.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">WindowsServer.contoso.com</span><span class="w"> </span><span class="nt">-AssumeYes</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-4">Example 4</h4>
<p>Remove SCOM BME IDs from the Operations Manager Database:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Remove-SCOMBaseManagedEntity.ps1</span><span class="w"> </span><span class="nt">-Id</span><span class="w"> </span><span class="nx">C1E9B41B-0A35-C069-16EB-00AC43BB9C47</span><span class="p">,</span><span class="w"> </span><span class="nx">CB29ECDE-BCE8-2213-D5DD-0353116EDA6B</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-5">Example 5</h4>
<p>If you need to input a file that contains Agents (CSV or TXT):</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Remove-SCOMBaseManagedEntity.ps1</span><span class="w"> </span><span class="nt">-InputFile</span><span class="w"> </span><span class="nx">C:\Temp\List_Of_Servers.txt</span><span class="w">
</span></code></pre></div> </div>
</blockquote>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/remove-data-from-scom-database/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
October 2, 2022
https://blakedrumm.com/blog/remove-data-from-scom-database/
https://blakedrumm.com/blog/remove-data-from-scom-database/Data Reader account provided is not same as that in the management group/assets/img/posts/opsmgr-setup-data-reader-account-issue.jpg<p><sub>Thank you to Luis Décio for the original creation of the KB!</sub></p>
<p>During installation of SCOM Reporting services, you may see the following error:
Data Reader account provided is not same as that in the management group.</p>
<h2 id="how-to-fix">How to fix</h2>
<h3 id="reconfigure-the-data-warehouse-report-deployment-account-profile">Reconfigure the “Data Warehouse Report Deployment Account” Profile</h3>
<p>Set the Data Warehouse Report Deployment Account to the Class “Collection Server” and “Data Warehouse Synchronization Server”</p>
<p><img src="/assets/img/posts/dw-report-deployment-account-profile.png" alt="/assets/img/posts/dw-report-deployment-account-profile.png" class="img-fluid" /></p>
<h3 id="reconfigure-the-data-warehouse-account-profile">Reconfigure the “Data Warehouse Account” Profile</h3>
<p>Data Warehouse Action Account to the Class “Collection Server”, “Data Warehouse Synchronization Server”, “Data Set” and “Operations Manager APM Data Transfer Service”</p>
<p><img src="/assets/img/posts/data-warehouse-account-profile.jpg" alt="/assets/img/posts/data-warehouse-account-profile.jpg" class="img-fluid" /></p>
<p>After configuring the above, the SCOM Reporting component installed successfully with the <strong>Data Warehouse Report Deployment Account</strong> as expected.</p>
<hr />
<h2 id="automate-with-powershell">Automate with Powershell</h2>
<p>You can use Powershell to automate fixing the DW RunAs Profiles. I would suggest that you remove all RunAs accounts from both RunAs profiles (“Data Warehouse Account” and “Data Warehouse Report Deployment Account”) prior to running the below Powershell script.</p>
<p><strong>Blog post from Udish Mudiar:</strong> <a href="https://udishtech.com/associate-scom-data-warehouse-profile-using-powershell/">https://udishtech.com/associate-scom-data-warehouse-profile-using-powershell/</a></p>
<p>Here is my own take on Udish’s Powershell script: <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Quick%20Fixes/Resolve-DWRunAsProfileAssociation.ps1">https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Quick%20Fixes/Resolve-DWRunAsProfileAssociation.ps1</a></p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Original Author: Udish Mudiar</span><span class="w">
</span><span class="c"># Original Blog Post: https://udishtech.com/associate-scom-data-warehouse-profile-using-powershell/</span><span class="w">
</span><span class="c"># =========================================================================================================================</span><span class="w">
</span><span class="c"># Modified by: Blake Drumm ([email protected])</span><span class="w">
</span><span class="c"># Last Modified: March 8th, 2024</span><span class="w">
</span><span class="c"># Blog Post: https://blakedrumm.com/blog/data-reader-account-provided-is-not-same-as-that-in-the-management-group/</span><span class="w">
</span><span class="kr">function</span><span class="w"> </span><span class="nf">Invoke-TimeStamp</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$TimeStamp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">Get-Date</span><span class="p">)</span><span class="o">.</span><span class="nf">DateTime</span><span class="w">
</span><span class="nx">return</span><span class="w"> </span><span class="s2">"</span><span class="nv">$TimeStamp</span><span class="s2"> - "</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"</span><span class="se">`n`n</span><span class="s2">------------------------------------------------------------"</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Green</span><span class="w">
</span><span class="c">#Associate Run As Account association in Data Warehouse and Report Deployment Run As Profile.</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="s2">Script started"</span><span class="w">
</span><span class="n">Import-Module</span><span class="w"> </span><span class="nx">OperationsManager</span><span class="w">
</span><span class="c">#Get the run as profiles</span><span class="w">
</span><span class="nv">$DWActionAccountProfile</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMRunAsProfile</span><span class="w"> </span><span class="nt">-DisplayName</span><span class="w"> </span><span class="s2">"Data Warehouse Account"</span><span class="w">
</span><span class="nv">$ReportDeploymentProfile</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMRunAsProfile</span><span class="w"> </span><span class="nt">-DisplayName</span><span class="w"> </span><span class="s2">"Data Warehouse Report Deployment Account"</span><span class="w">
</span><span class="c">#Get the run as accounts</span><span class="w">
</span><span class="nv">$DWActionAccount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMrunAsAccount</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"Data Warehouse Action Account"</span><span class="w">
</span><span class="nv">$DWReportDeploymentAccount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMrunAsAccount</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"Data Warehouse Report Deployment Account"</span><span class="w">
</span><span class="c">#Get all the required classes</span><span class="w">
</span><span class="nv">$CollectionServerClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMClass</span><span class="w"> </span><span class="nt">-DisplayName</span><span class="w"> </span><span class="s2">"Collection Server"</span><span class="w">
</span><span class="nv">$DataSetClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMClass</span><span class="w"> </span><span class="nt">-DisplayName</span><span class="w"> </span><span class="s2">"Data Set"</span><span class="w">
</span><span class="nv">$APMClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMClass</span><span class="w"> </span><span class="nt">-DisplayName</span><span class="w"> </span><span class="s2">"Operations Manager APM Data Transfer Service"</span><span class="w">
</span><span class="nv">$DWSyncClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMClass</span><span class="w"> </span><span class="nt">-DisplayName</span><span class="w"> </span><span class="s2">"Data Warehouse Synchronization Server"</span><span class="w">
</span><span class="c">#Setting the association</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="s2">Setting the Run As Account Association for Data Warehouse Account Profile"</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$APMClass</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Set-SCOMRunAsProfile</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="nt">-Action</span><span class="w"> </span><span class="s2">"Add"</span><span class="w"> </span><span class="nt">-Profile</span><span class="w"> </span><span class="nv">$DWActionAccountProfile</span><span class="w"> </span><span class="nt">-Account</span><span class="w"> </span><span class="nv">$DWActionAccount</span><span class="w"> </span><span class="nt">-Class</span><span class="w"> </span><span class="nv">$CollectionServerClass</span><span class="p">,</span><span class="w"> </span><span class="nv">$DataSetClass</span><span class="p">,</span><span class="w"> </span><span class="nv">$APMClass</span><span class="p">,</span><span class="w"> </span><span class="nv">$DWSyncClass</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">else</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Set-SCOMRunAsProfile</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="nt">-Action</span><span class="w"> </span><span class="s2">"Add"</span><span class="w"> </span><span class="nt">-Profile</span><span class="w"> </span><span class="nv">$DWActionAccountProfile</span><span class="w"> </span><span class="nt">-Account</span><span class="w"> </span><span class="nv">$DWActionAccount</span><span class="w"> </span><span class="nt">-Class</span><span class="w"> </span><span class="nv">$CollectionServerClass</span><span class="p">,</span><span class="w"> </span><span class="nv">$DataSetClass</span><span class="p">,</span><span class="w"> </span><span class="nv">$DWSyncClass</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="s2">Completed Successfully!"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="s2">Unable to set the RunAs accounts, try removing all accounts from inside the RunAs Profile (</span><span class="se">`"</span><span class="s2">Data Warehouse Account</span><span class="se">`"</span><span class="s2">), and run the script again."</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="nv">$error</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="s2">Setting the Run As Account Association for Data Warehouse Report Deployment Account Profile"</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Set-SCOMRunAsProfile</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="nt">-Action</span><span class="w"> </span><span class="s2">"Add"</span><span class="w"> </span><span class="nt">-Profile</span><span class="w"> </span><span class="nv">$ReportDeploymentProfile</span><span class="w"> </span><span class="nt">-Account</span><span class="w"> </span><span class="nv">$DWReportDeploymentAccount</span><span class="w"> </span><span class="nt">-Class</span><span class="w"> </span><span class="nv">$CollectionServerClass</span><span class="p">,</span><span class="w"> </span><span class="nv">$DWSyncClass</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="s2">Completed Successfully!"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="s2">Unable to set the RunAs accounts, try removing all accounts from inside the RunAs Profile (</span><span class="se">`"</span><span class="s2">Data Warehouse Report Deployment Account</span><span class="se">`"</span><span class="s2">), and run the script again."</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="nv">$error</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="si">$(</span><span class="n">Invoke-TimeStamp</span><span class="p">)</span><span class="s2">Script ended"</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s1">'------------------------------------------------------------'</span><span class="w"> </span><span class="nt">-ForegroundColor</span><span class="w"> </span><span class="nx">Green</span><span class="w">
</span></code></pre></div></div>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/data-reader-account-provided-is-not-same-as-that-in-the-management-group/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
September 19, 2022
https://blakedrumm.com/blog/data-reader-account-provided-is-not-same-as-that-in-the-management-group/
https://blakedrumm.com/blog/data-reader-account-provided-is-not-same-as-that-in-the-management-group/SCOM Uptime Availability Report/assets/img/posts/uptime-availability-report.png<p>In order to properly report on the uptime of a machine, you will need to target the Health Service Watcher object class. This class will allow you to return the availability of the machine itself, and not all of the rollup monitors underneath that may affect the report accuracy.</p>
<hr />
<p><img src="/assets/img/posts/open-availability-report.png" alt="Open Availability Report" class="img-fluid" /></p>
<ol>
<li>Open SCOM Console, Click on the <em>Reporting</em> tab</li>
<li>Click on <strong>Microsoft Generic Report Library</strong></li>
<li>Open the <strong>Availability</strong> Report</li>
<li>Add Object: <br />
<img src="/assets/img/posts/add-object-report.png" alt="Add object to report" class="img-fluid" /></li>
<li>Click on <strong>Options…</strong> -> Click on <strong>Add</strong> -> Type <strong>Health Service Watcher</strong> in the search field -> Add <strong>Health Service Watcher</strong>: <br />
<img src="/assets/img/posts/add-object-hsw-class.png" alt="Add Health Service Watcher Object Class" class="img-fluid" /></li>
<li>Click OK on the Options Window: <br />
<img src="/assets/img/posts/health-service-watcher-options.png" alt="Options - Health Service Watcher" class="img-fluid" /></li>
<li>Type in the machines you want to discover (or you can just press search and it will return all related items): <br />
<img src="/assets/img/posts/select-hsw-agentwatcher-objects.png" alt="Select Health Service Watcher Computer Objects" class="img-fluid" /></li>
<li>Modify the time range and run the report.</li>
<li>Resulting output: <br />
<img src="/assets/img/posts/availability-report-output.png" alt="Availability Report Results" class="img-fluid" /></li>
</ol>
<blockquote>
<h3 id="notebook-note">:notebook: Note</h3>
<p>Quick tip, you can modify the parameters for the report at any time with the Show or Hide Parameter Area button: <br />
<img src="/assets/img/posts/show-hide-parameter-area-reporting.png" alt="Show and Hide Parameter in Reports" class="img-fluid" /></p>
</blockquote>
<hr />
<h2 id="dynamic-agent-health-service-watcher-group">Dynamic Agent Health Service Watcher Group</h2>
<p>If you would like to make it easier to run the report again, you can create a group for the Health Service Watchers. Just create a group in <strong>Authoring</strong> -> <strong>Groups</strong>, with the following Dynamic Member Rule: <br />
<img src="/assets/img/posts/scom-agent-hsw-group.png" alt="Dynamic Member Rule" class="img-fluid" /></p>
<p><strong>Membership Result:</strong> <br />
<img src="/assets/img/posts/all-agent-hsw-objects-group.png" alt="Membership Result" class="img-fluid" /></p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-uptime-availability-report/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
August 17, 2022
https://blakedrumm.com/blog/scom-uptime-availability-report/
https://blakedrumm.com/blog/scom-uptime-availability-report/Event 26319 - Assembly Trust Issues with SQL 2017+/assets/img/posts/event-26319-error-assembly-trust-issues.png<p><sub>Thank you to Lorne Sepaugh for the original creation of the KB!</sub></p>
<h2 id="symptom">Symptom</h2>
<p>I had a customer today that had an issue with being unable to open any SCOM Console without receiving the following error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Date: 6/8/2022 1:57:24 AM
Application: Operations Manager
Application Version: 10.19.10505.0
Severity: Error
Message:
An error occurred in the Microsoft .NET Framework while trying to load assembly id 65537. The server may be running out of resources, or the assembly may not be trusted. Run the query again, or check documentation to see how to solve the assembly trust issues. For more information about this error:
System.IO.FileLoadException: Could not load file or assembly 'microsoft.enterprisemanagement.sql.userdefineddatatype, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An error relating to security occurred. (Exception from HRESULT: 0x8013150A)
System.IO.FileLoadException:
at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.Load(String assemblyString)
</code></pre></div></div>
<p>This error is due to a change in the SQL 2017 security approach for CLR, as stated in the SQL Server 2017 docs: <br />
<img src="/assets/img/posts/clr-sql-2017-security-approach.png" alt="CLR SQL 2017 documentation highlight" class="img-fluid" /></p>
<p>There are two assemblies used by SCOM that are marked as <em>UNSAFE</em> and not allowed to run by default in one of these scenarios - as such we need to mark them as safe and trusted on each server instance. The assemblies are:</p>
<ul>
<li>Microsoft.EnterpriseManagement.SQL.DataAccessLayer</li>
<li>Microsoft.EnterpriseManagement.SQL.UserDefinedDataType</li>
</ul>
<h2 id="how-to-resolve">How to Resolve</h2>
<h3 id="prerequisites">Prerequisites</h3>
<p><strong>*If using availability groups, this is to be completed after the databases are added</strong></p>
<ul>
<li>Ensure that CLR is enabled on all SQL Server instances with this script:
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Sp_configure</span> <span class="s1">'show advanced options'</span><span class="p">,</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">GO</span>
<span class="n">RECONFIGURE</span><span class="p">;</span>
<span class="k">GO</span>
<span class="n">Sp_configure</span> <span class="s1">'clr enabled'</span><span class="p">,</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">GO</span>
<span class="n">RECONFIGURE</span><span class="p">;</span>
<span class="k">GO</span>
</code></pre></div> </div>
</li>
<li>Make sure that you have SQL admin access, or a DBA on hand</li>
<li>(Optional) Stop all the SCOM services on each management server - don’t forget to restart when finished</li>
<li>Make sure you have a database backup</li>
</ul>
<h3 id="step-1-verify-clr-strict-security-state">Step 1: Verify CLR Strict Security State</h3>
<p>Run this query in SQL Management Studio:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">sys</span><span class="p">.</span><span class="n">configurations</span> <span class="k">WHERE</span> <span class="n">name</span> <span class="k">LIKE</span> <span class="s1">'clr strict security'</span><span class="p">;</span>
</code></pre></div></div>
<p>You should get a return like this, “value_in_use” and “value” should be 1: <br />
<img src="/assets/img/posts/clr-value-in-use.png" alt="Example showing sys.configurations value_in_use" class="img-fluid" /></p>
<p>This table describes what the values mean:</p>
<table class="table table-hover table-text d-block overflow-auto">
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>Disabled - Provided for backwards compatibility. Disabled value is not recommended</td>
</tr>
<tr>
<td>1</td>
<td>Enabled - Causes the Database Engine to ignore the PERMISSION_SET information on the assemblies, and always interpret them as UNSAFE. Enabled is the default value for SQL Server 2017 (14.x)</td>
</tr>
</tbody>
</table>
<p> </p>
<blockquote>
<h3 id="note">Note</h3>
<p>By default, CLR strict security will be <strong>OFF</strong> after upgrading to SQL Server 2017</p>
</blockquote>
<p>If the value is 0 - check this doc for more info on how to set it to 1 - <a href="https://docs.microsoft.com/sql/database-engine/configure-windows/clr-strict-security?view=sql-server-2017">https://docs.microsoft.com/sql/database-engine/configure-windows/clr-strict-security?view=sql-server-2017</a></p>
<h3 id="step-2-create-the-trusted-assemblies">Step 2: Create the Trusted Assemblies</h3>
<p>To create the Trusted Assemblies, run the below TSQL Query on each SQL 2017+ instance(s) hosting the Operations Manager Database:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">USE</span> <span class="n">master</span><span class="p">;</span>
<span class="k">GO</span>
<span class="c1">-- First Trusted Assembly</span>
<span class="k">DECLARE</span> <span class="o">@</span><span class="n">clrName1</span> <span class="n">nvarchar</span><span class="p">(</span><span class="mi">4000</span><span class="p">)</span> <span class="o">=</span> <span class="s1">'Microsoft.EnterpriseManagement.Sql.DataAccessLayer'</span>
<span class="n">PRINT</span> <span class="n">N</span><span class="s1">'Trusted Assembly: '</span> <span class="o">+</span> <span class="k">CAST</span><span class="p">(</span><span class="o">@</span><span class="n">clrName1</span> <span class="k">AS</span> <span class="n">nvarchar</span><span class="p">(</span><span class="mi">120</span><span class="p">))</span>
<span class="k">DECLARE</span> <span class="o">@</span><span class="n">hash1</span> <span class="nb">varbinary</span><span class="p">(</span><span class="mi">64</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="n">xEC312664052DE020D0F9631110AFB4DCDF14F477293E1C5DE8C42D3265F543C92FCF8BC1648FC28E9A0731B3E491BCF1D4A8EB838ED9F0B24AE19057BDDBF6EC</span><span class="p">;</span>
<span class="c1">-- Drop trusted assembly if exists</span>
<span class="n">IF</span> <span class="k">EXISTS</span> <span class="p">(</span><span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="n">sys</span><span class="p">.</span><span class="n">trusted_assemblies</span> <span class="k">where</span> <span class="n">description</span> <span class="o">=</span> <span class="o">@</span><span class="n">clrName1</span><span class="p">)</span>
<span class="k">BEGIN</span>
<span class="n">PRINT</span> <span class="n">N</span><span class="s1">' - Dropping Trusted Assembly'</span>
<span class="k">EXEC</span> <span class="n">SYS</span><span class="p">.</span><span class="n">sp_drop_trusted_assembly</span> <span class="o">@</span><span class="n">hash1</span>
<span class="k">END</span>
<span class="c1">--Add to trusted assembly</span>
<span class="n">PRINT</span> <span class="n">N</span><span class="s1">' - Adding Trusted Assembly'</span>
<span class="k">EXEC</span> <span class="n">sys</span><span class="p">.</span><span class="n">sp_add_trusted_assembly</span> <span class="o">@</span><span class="n">hash</span> <span class="o">=</span> <span class="o">@</span><span class="n">hash1</span><span class="p">,</span>
<span class="o">@</span><span class="n">description</span> <span class="o">=</span> <span class="o">@</span><span class="n">clrName1</span><span class="p">;</span>
<span class="n">PRINT</span> <span class="n">N</span><span class="s1">' '</span>
<span class="c1">-- Second Trusted Assembly</span>
<span class="k">DECLARE</span> <span class="o">@</span><span class="n">clrName2</span> <span class="n">nvarchar</span><span class="p">(</span><span class="mi">4000</span><span class="p">)</span> <span class="o">=</span> <span class="s1">'Microsoft.EnterpriseManagement.Sql.UserDefinedDataType'</span>
<span class="n">PRINT</span> <span class="n">N</span><span class="s1">'Trusted Assembly: '</span> <span class="o">+</span> <span class="k">CAST</span><span class="p">(</span><span class="o">@</span><span class="n">clrName2</span> <span class="k">AS</span> <span class="n">nvarchar</span><span class="p">(</span><span class="mi">120</span><span class="p">))</span>
<span class="k">DECLARE</span> <span class="o">@</span><span class="n">hash2</span> <span class="nb">varbinary</span><span class="p">(</span><span class="mi">64</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="n">xFAC2A8ECA2BE6AD46FBB6EDFB53321240F4D98D199A5A28B4EB3BAD412BEC849B99018D9207CEA045D186CF67B8D06507EA33BFBF9A7A132DC0BB1D756F4F491</span><span class="p">;</span>
<span class="c1">-- Drop trusted assembly if exists</span>
<span class="n">IF</span> <span class="k">EXISTS</span> <span class="p">(</span><span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="n">sys</span><span class="p">.</span><span class="n">trusted_assemblies</span> <span class="k">where</span> <span class="n">description</span> <span class="o">=</span> <span class="o">@</span><span class="n">clrName2</span><span class="p">)</span>
<span class="k">BEGIN</span>
<span class="n">PRINT</span> <span class="n">N</span><span class="s1">' - Dropping Trusted Assembly'</span>
<span class="k">EXEC</span> <span class="n">SYS</span><span class="p">.</span><span class="n">sp_drop_trusted_assembly</span> <span class="o">@</span><span class="n">hash2</span>
<span class="k">END</span>
<span class="c1">--Add to trusted assembly</span>
<span class="n">PRINT</span> <span class="n">N</span><span class="s1">' - Adding Trusted Assembly'</span>
<span class="k">EXEC</span> <span class="n">sys</span><span class="p">.</span><span class="n">sp_add_trusted_assembly</span> <span class="o">@</span><span class="n">hash</span> <span class="o">=</span> <span class="o">@</span><span class="n">hash2</span><span class="p">,</span>
<span class="o">@</span><span class="n">description</span> <span class="o">=</span> <span class="o">@</span><span class="n">clrName2</span><span class="p">;</span>
</code></pre></div></div>
<p>You can verify the currently trusted assemblies with the following query:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">USE</span> <span class="n">OperationsManager</span><span class="p">;</span>
<span class="k">GO</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">sys</span><span class="p">.</span><span class="n">assemblies</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">sys</span><span class="p">.</span><span class="n">trusted_assemblies</span>
</code></pre></div></div>
<p>Once done on all SQL Server instance(s) that host the Operations Manager Database, restart the SCOM Console on the management servers and everything should load correctly.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/event-26319-assembly-trust-issues/" alt="Page Views" class="img-fluid" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
August 5, 2022
https://blakedrumm.com/blog/event-26319-assembly-trust-issues/
https://blakedrumm.com/blog/event-26319-assembly-trust-issues/Resolve SCOM Agent Deployment Error: 80070643/assets/img/posts/SCOM-Agent-Deployment-Error-80070643.png<h2 id="book-introduction">:book: Introduction</h2>
<p>I had a case where my customer is experiencing an error on their SCOM Console when attempting to resolve an agent Pending Upgrade in Pending Management. The Agent needed to be upgraded from the SCOM 2019 Agent to the SCOM 2022 Agent. We reviewed the Log file: <code class="language-plaintext highlighter-rouge">Agent1AgentInstall.Log</code> located in the following directory: <code class="language-plaintext highlighter-rouge">C:\Program Files\Microsoft System Center\Operations Manager\Server\AgentManagement\AgentLogs</code>.</p>
<p><strong>Discovery Wizard Error:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The Agent Management Operation Agent Install failed for remote computer Agent1.contoso.com.
Install account: CONTOSO\SCOMAdmin
Error Code: 80070643
Error Description: Fatal error during installation.
Microsoft Installer Error Description:
For more information, see Windows Installer log file "C:\Program Files\Microsoft System Center\Operations Manager\Server\AgentManagement\AgentLogs\Agent1AgentInstall.log" on the Management Server.
</code></pre></div></div>
<h2 id="page_with_curl-how-to-fix">:page_with_curl: How to fix</h2>
<p>The MSI error highlighted below was the main cause for the installation failure:</p>
<blockquote>
<p>Action start 16:18:53: _SuppressComputerReboot. <br />
MSI (s) (AC:F0) [16:18:53:021]: Skipping action: SetIS_NETFRAMEWORK_472_OR_LATER_INSTALLED (condition is false) <br />
MSI (s) (AC:F0) [16:18:53:021]: Doing action: LaunchConditions <br />
Action ended 16:18:53: _SuppressComputerReboot. Return value 1. <br />
Action start 16:18:53: LaunchConditions. <br />
MSI (s) (AC:F0) [16:18:53:021]: Product: Microsoft Monitoring Agent – <span style="color:yellow">The .NET Framework 4.7.2 is required to install this application.</span></p>
<p>The .NET Framework 4.7.2 is required to install this application. <br />
Action ended 16:18:53: LaunchConditions. Return value 3. <br />
Action ended 16:18:53: INSTALL. Return value 3.</p>
</blockquote>
<p>We also attempted a manual install and this will also show you the error: <br />
<img src="/assets/img/posts/dotNET-4_7_2-missing.png" alt="DotNET Missing MSI Error" class="img-fluid" /></p>
<p>After installing <a href="https://dotnet.microsoft.com/download/dotnet-framework/net472">.NET Framework 4.7.2</a> as required for the SCOM 2022 Agent, the installation succeeded. <br />
<a href="https://docs.microsoft.com/system-center/scom/system-requirements?view=sc-om-2022#microsoft-monitoring-agent-operating-system">SCOM 2022 Agent Requirements</a></p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/resolve-scom-agent-deployment-80070643/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
July 29, 2022
https://blakedrumm.com/blog/resolve-scom-agent-deployment-80070643/
https://blakedrumm.com/blog/resolve-scom-agent-deployment-80070643/SCOM Unix/Linux Discovery Errors + How To Fix Them/assets/img/posts/unix-linux-discovery-wizard.png<h2 id="errors-you-may-see">Errors you may see</h2>
<hr />
<h3 id="error-example-1">Error Example 1</h3>
<p><strong>DiscoveryResult.ErrorData type. Please file bug report - Parameter Name: s</strong> <br />
When discovering a Unix/Linux machine, the wizard shows the machine as unmanageable in the discovery results with below error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Unexpected DiscoveryResult.ErrorData type. Please file bug report.
ErrorData: System.ArgumentNullException
Value cannot be null.
Parameter name: s
at System.Activities.WorkflowApplication.Invoke(Activity activity, IDictionary`2 inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout)
at System.Activities.WorkflowInvoker.Invoke(Activity workflow, IDictionary`2 inputs, TimeSpan timeout, WorkflowInstanceExtensionManager extensions)
at Microsoft.SystemCenter.CrossPlatform.ClientActions.DefaultDiscovery.InvokeWorkflow(IManagedObject managementActionPoint, DiscoveryTargetEndpoint criteria, IInstallableAgents installableAgents)
</code></pre></div></div>
<h3 id="how-to-fix">How to Fix</h3>
<p>Sometimes this can happen because WinHTTP proxy settings have been configured on the management servers in the Unix/Linux Resource Pool, and the agent which we are trying to discover is not included in the Bypass List</p>
<p>Open a CMD prompt as Administrator on the management servers in the Unix/Linux Resource Pool and run the following command</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>netsh winhttp show proxy
</code></pre></div></div>
<p>If there is a WinHTTP proxy server configured, add the FQDN for the server which we are trying to discover in the Bypass List by running the following command</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>netsh winhttp set proxy proxy-server="<proxyserver:port>" bypass-list="*.ourdomain.com;*.yourdomain.com*;<serverFQDN>"
</code></pre></div></div>
<p>Once the Bypass List has been configured, check if discovery of the agent is now successful</p>
<blockquote>
<h2 id="note">Note</h2>
<p>You can disable WinHTTP Proxy by running the following command, this will remove a proxy server and configure <strong>“Direct Access”</strong>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>netsh winhttp reset proxy
</code></pre></div> </div>
</blockquote>
<hr />
<h3 id="error-example-2">Error Example 2</h3>
<p><strong>DiscoveryResult.ErrorData type. Please file bug report - Parameter name: lhs</strong> <br />
When discovering a Linux machine, the wizard shows the machine as unmanageable in the discovery results with below error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Discovery not successful
Message: Unspecified failure
Details: Unexpected DiscoveryResult.ErrorData type. Please file bug report.
ErrorData: System.ArgumentNullException
Value cannot be null.
Parameter name: lhs
at System.Activities.WorkflowApplication.Invoke(Activity activity, IDictionary`2 inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout)
at System.Activities.WorkflowInvoker.Invoke(Activity workflow, IDictionary`2 inputs, TimeSpan timeout, WorkflowInstanceExtensionManager extensions)
at Microsoft.SystemCenter.CrossPlatform.ClientActions.DefaultDiscovery.InvokeWorkflow(IManagedObject managementActionPoint, DiscoveryTargetEndpoint criteria, IInstallableAgents installableAgents)
</code></pre></div></div>
<h3 id="how-to-fix-1">How to fix</h3>
<p>Sometimes this can happen because of omsagent shell files in the installed kits folder.</p>
<p>Navigate to the following directory in file explorer: <br />
<code class="language-plaintext highlighter-rouge">C:\Program Files\Microsoft System Center\Operations Manager\Server\AgentManagement\UnixAgents\DownloadedKits</code></p>
<p>If there are omsagent files listed here, move them to a temporary directory outside of the SCOM files.</p>
<p><img src="/assets/img/posts/unix-linux-discovery-example-fix.png" alt="Example of how to fix" class="img-fluid" /></p>
<p>Once they have been moved from the DownloadedKits folder, retry discovery and discovery should now succeed (or you should get a different error which would indicate additional troubleshooting is needed such as sudoers, connectivity, etc.)</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/unix-linux-discovery-errors/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
June 22, 2022
https://blakedrumm.com/blog/unix-linux-discovery-errors/
https://blakedrumm.com/blog/unix-linux-discovery-errors/Error while installing SCOM 2019 Reporting/assets/img/posts/reporting-error-scom-ssrs.png<h2 id="issue-description">Issue Description</h2>
<p>The issue I have seen is the following error message in the SCOM Reporting Services installer:</p>
<p><strong><em>“Unable to connect to the Data Access service for this management server. Ensure the Data Access service is running and that the service, the management group, and setup are all the same version.”</em></strong></p>
<p>The problem stems from an SCOM 2019 Update Rollup that was previously applied to the Management Server and this causes the SCOM Reporting Services to fail due to the Reporting Services installer expecting the RTM version to be present.</p>
<p>The regression was introduced in <a href="https://support.microsoft.com/en-us/topic/update-rollup-1-for-system-center-operations-manager-2019-kb4533415-e5ce3191-2403-684f-1980-43aa61b50cb6">Update Rollup 1 for System Center Operations Manager 2019 (KB4533415)</a></p>
<ul>
<li>The “Operations Manager Products” view in the Admin console did not update the Version column for the installed component version. This column now reflects the updated version of all the listed components.</li>
</ul>
<h2 id="solution">Solution</h2>
<p>The following may resolve the above error for you:</p>
<ol>
<li>Start by connecting to the Operations Manager database via SQL Server Management Studio. <strong>(Create a backup of your Databases prior to any direct edits)</strong></li>
<li>
<p>Get the current version of the Management Server you are connecting SSRS with note the version <em>(we will use this later to revert the changes to the DB)</em></p>
<h3 id="get-version">Get Version</h3>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">-- SCOM 2019 RTM</span>
<span class="c1">-- 10.19.10050.0</span>
<span class="c1">-- SCOM 2019 UR1</span>
<span class="c1">-- 10.19.10311.0</span>
<span class="c1">-- SCOM 2019 UR1 - Hotfix for Alert Management</span>
<span class="c1">-- 10.19.10349.0</span>
<span class="c1">-- SCOM 2019 UR2</span>
<span class="c1">-- 10.19.10407.0</span>
<span class="c1">-- SCOM 2019 UR2 - Hotfix for Event Log Channel</span>
<span class="c1">-- 10.19.10475.0</span>
<span class="c1">-- SCOM 2019 UR3</span>
<span class="c1">-- 10.19.10505.0</span>
<span class="c1">-- SCOM 2019 UR3 - Hotfix for Web Console</span>
<span class="c1">-- 10.19.10550.0</span>
<span class="c1">-- SCOM 2019 UR3 - Hotfix Oct 2021</span>
<span class="c1">-- 10.19.10552.0</span>
<span class="k">select</span>
<span class="n">PrincipalName</span><span class="p">,</span>
<span class="k">Version</span>
<span class="k">from</span> <span class="n">MTV_HealthService</span>
<span class="k">where</span>
<span class="n">IsManagementServer</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">and</span>
<span class="n">PrincipalName</span> <span class="o">=</span> <span class="s1">'MS01-2019.contoso.com'</span>
</code></pre></div> </div>
<p><img src="/assets/img/posts/ssrs-example-1.png" alt="Example output for Management Server version SQL Query" class="img-fluid" /></p>
</li>
<li>We will run the following query to update the Management Server to the RTM version of SCOM 2019 (<em>10.19.10050.0</em>):
<h3 id="update-version-to-rtm">Update Version to RTM</h3>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">update</span> <span class="n">MTV_HealthService</span>
<span class="k">set</span> <span class="k">Version</span> <span class="o">=</span> <span class="s1">'10.19.10050.0'</span>
<span class="c1">-- SCOM 2019 RTM</span>
<span class="k">where</span> <span class="n">PrincipalName</span> <span class="o">=</span> <span class="s1">'MS01-2019.contoso.com'</span>
</code></pre></div> </div>
</li>
<li>Install SCOM Reporting Services! :sunglasses: :thumbsup: <br />
<img src="/assets/img/posts/install-scom-reporting.png" alt="Install SCOM Reporting Services" class="img-fluid" /></li>
<li>After SCOM Reporting Services installs, you will need to revert the changes to the SCOM SQL Operations Manager database, run the following SQL Query to return the Management Server version back to the version returned in Step 2:
<h3 id="revert-change">Revert Change</h3>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">update</span> <span class="n">MTV_HealthService</span>
<span class="k">set</span> <span class="k">Version</span> <span class="o">=</span> <span class="s1">'10.19.10552.0'</span>
<span class="c1">-- SCOM 2019 UR3 - Hotfix Oct 2021</span>
<span class="k">where</span> <span class="n">PrincipalName</span> <span class="o">=</span> <span class="s1">'MS01-2019.contoso.com'</span>
</code></pre></div> </div>
</li>
</ol>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=/blog/fix-install-bug-scom-2019-reporting/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
June 9, 2022
https://blakedrumm.com/blog/fix-install-bug-scom-2019-reporting/
https://blakedrumm.com/blog/fix-install-bug-scom-2019-reporting/Rebuild Performance Counters/assets/img/posts/recreate-perf-counters.png<h2 id="how-to-rebuild">How to Rebuild</h2>
<p>Rebuild the Performance counters with the following Powershell Script, you can copy and paste the below script to a Powershell ISE Window running as <strong>Administrator</strong>:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Push-Location</span><span class="w"> </span><span class="bp">$PWD</span><span class="w">
</span><span class="nv">$FirstPath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'C:\Windows\System32'</span><span class="w">
</span><span class="nv">$SecondPath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'C:\Windows\SysWOW64'</span><span class="w">
</span><span class="n">cd</span><span class="w"> </span><span class="nv">$FirstPath</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">'---------------------------------------------------------'</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"Recreating Performance Counters in: </span><span class="nv">$FirstPath</span><span class="s2">"</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">' - Running: lodctr /R'</span><span class="w">
</span><span class="n">lodctr</span><span class="w"> </span><span class="nx">/R</span><span class="w">
</span><span class="n">cd</span><span class="w"> </span><span class="nv">$SecondPath</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s2">"</span><span class="se">`n</span><span class="s2">Recreating Performance Counters in: </span><span class="nv">$SecondPath</span><span class="s2">"</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">' - Running: lodctr /R'</span><span class="w">
</span><span class="n">lodctr</span><span class="w"> </span><span class="nx">/R</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">'---------------------------------------------------------'</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">'Resyncing the Performance Counters with Windows Management Instrumentation (WMI)'</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">' - Running: C:\Windows\System32\wbem\WinMgmt.exe /RESYNCPERF'</span><span class="w">
</span><span class="n">C:\Windows\System32\wbem\WinMgmt.exe</span><span class="w"> </span><span class="nx">/RESYNCPERF</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">'---------------------------------------------------------'</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">'Restarting Service: Performance Logs & Alerts (pla)'</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Get-Service</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"pla"</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Restart-Service</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-Null</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"A Failure has occurred: </span><span class="se">`n</span><span class="nv">$error</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="p">()</span><span class="w">
</span><span class="n">Write-Output</span><span class="w"> </span><span class="s1">'Restarting Service: Windows Management Instrumentation (winmgmt)'</span><span class="w">
</span><span class="kr">try</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Get-Service</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"winmgmt"</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Restart-Service</span><span class="w"> </span><span class="nt">-Force</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">Stop</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-Null</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">catch</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"A Failure has occurred: </span><span class="se">`n</span><span class="nv">$error</span><span class="s2">"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Pop-Location</span><span class="w">
</span></code></pre></div></div>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/rebuild-perf-counters/" alt="Page Views" /></p>
<!--
## Introduction
The following event id inspired me to write this article:
```
Log Name: Operations Manager
Source: Health Service Modules
Date: 5/16/2022 2:47:00 PM
Event ID: 10103
Task Category: None
Level: Warning
Keywords: Classic
User: N/A
Computer: <ManagementServerFQDN>
Description:
In PerfDataSource, could not resolve counter instance OpsMgr DW Writer Module, Dropped Data Item Count, All Instances. Module will not be unloaded.
One or more workflows were affected by this.
Workflow name: Microsoft.SystemCenter.DataWarehouse.CollectionRule.Performance.Writer.DroppedDataItemCount
Instance name: <ManagementServerFQDN>
Instance ID: {3Z4DF6FB-B78C-33D9-BE0F-C84F7278AB92}
Management group: <ManagementGroupName>
```
The above tells me: `could not resolve counter instance OpsMgr DW Writer Module` for some reason SCOM is no longer able to resolve some Performance Counter names on the Management Server, which causes some of the workflows for the SCOM Data Warehouse to fail.
-->
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
June 6, 2022
https://blakedrumm.com/blog/rebuild-perf-counters/
https://blakedrumm.com/blog/rebuild-perf-counters/Custom SQL Management Pack Invoke-SqlCmd Exception/assets/img/posts/invoke-sqlcmd.png<h2 id="introduction">Introduction</h2>
<p>The customer noticed the issue was occurring inside of one of their custom Management Packs (MP) for SCOM SQL Blocking monitoring. They deployed this custom MP to two SCOM Management Groups. The Agents where we were seeing the issue were dual (multi) homed SCOM Agents that were SQL Servers (due to the way the MP was designed).</p>
<h2 id="script-section">Script Section</h2>
<p>The command inside of the custom Management Pack was <code class="language-plaintext highlighter-rouge">Invoke-SqlCmd</code>, which is apart of the built in <a href="https://docs.microsoft.com/en-us/sql/powershell/sql-server-powershell?view=sql-server-ver15">SQL Powershell Cmdlets</a>:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">...</span><span class="w">
</span><span class="nv">$conn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"MSSQL-2019"</span><span class="w">
</span><span class="nv">$ScriptName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Custom.SQLBlocking.Timed.Monitor.DataSource.ps1"</span><span class="w">
</span><span class="p">[</span><span class="n">int</span><span class="p">]</span><span class="nv">$WaitTimeMS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$WaitTime</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1000</span><span class="w">
</span><span class="nv">$blocked_session</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$null</span><span class="w">
</span><span class="nv">$sql1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"use master
SELECT r.session_id,
r.blocking_session_id,
s.login_name,
s.login_time,
s.program_name,
s.host_name,
s.memory_usage as Memory,
DB_NAME(r.database_id) AS DatabaseName,
r.wait_time,
r.command,
r.status,
r.cpu_time,
t.text as Query_Text
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(sql_handle) t
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
WHERE r.blocking_session_id <> 0 and wait_time > </span><span class="nv">$WaitTimeMS</span><span class="s2">"</span><span class="w">
</span><span class="nv">$error</span><span class="o">.</span><span class="nf">Clear</span><span class="w">
</span><span class="kr">Try</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">$blocked_session</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Invoke-Sqlcmd</span><span class="w"> </span><span class="nt">-Query</span><span class="w"> </span><span class="nv">$sql1</span><span class="w"> </span><span class="nt">-ServerInstance</span><span class="w"> </span><span class="nv">$conn</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">Catch</span><span class="w"> </span><span class="p">{</span><span class="nv">$momapi</span><span class="o">.</span><span class="nf">LogScriptEvent</span><span class="p">(</span><span class="nv">$ScriptName</span><span class="p">,</span><span class="w"> </span><span class="nx">9994</span><span class="p">,</span><span class="w"> </span><span class="nx">0</span><span class="p">,</span><span class="w"> </span><span class="nv">$error</span><span class="p">)}</span><span class="w">
</span><span class="o">...</span><span class="w">
</span></code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">Invoke-SqlCmd</code> in the above context should be able to successfully run with Local System (or a User Account) as the Action Account.</p>
<h2 id="catching-the-error">Catching the error</h2>
<p>We noticed the following error after the script above ran as a part of the Management Pack:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Custom.SQLBlocking.Timed.Monitor.DataSource.ps1 : ManagedBatchParser.ParserException
at ManagedBatchParser.Parser.Parse()
at Microsoft.SqlServer.Management.PowerShell.ExecutionProcessor.ExecuteTSql(String sqlCommand)
</code></pre></div></div>
<h2 id="resolution">Resolution</h2>
<p>You will need to set the time intervals between the rules / monitors to run at a different interval than the other Management Group that is reporting to this same Agent / Group to cause it to be multi-homed.</p>
<p><strong>OR</strong></p>
<p>You can remove the other Management Group and allow only 1 Management Server in the Agent Management control panel.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/custom-sql-mp-exception/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
May 2, 2022
https://blakedrumm.com/blog/custom-sql-mp-exception/
https://blakedrumm.com/blog/custom-sql-mp-exception/Verify Assemblies are loaded with GACUtil/assets/img/posts/gacutil-check.png<h2 id="what-is-gac">What is GAC?</h2>
<p>Each computer where the Common Language Runtime is installed has a machine-wide code cache called the Global Assembly Cache. The Global Assembly Cache stores assemblies specifically designated to be shared by several applications on the computer. More information can be found here: <a href="https://docs.microsoft.com/dotnet/framework/app-domains/gac">https://docs.microsoft.com/dotnet/framework/app-domains/gac</a></p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Download and install the <strong>.NET 4.8 Framework Developer Pack</strong> on the affected machine: <a href="https://dotnet.microsoft.com/download/dotnet-framework/net48">https://dotnet.microsoft.com/download/dotnet-framework/net48</a></p>
<h2 id="check-the-currently-installed-assemblies">Check the currently installed Assemblies</h2>
<ol>
<li>Open a <strong><em>Powershell</em></strong> or <strong><em>Command Prompt</em></strong> as <strong>Administrator</strong></li>
<li>Navigate to the installation directory: <br />
<code class="language-plaintext highlighter-rouge">cd "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools"</code></li>
<li>Run this GACUtil Command to List the Assemblies installed: <br />
<strong>Powershell:</strong>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="o">.</span><span class="n">\gacutil</span><span class="w"> </span><span class="nx">/L</span><span class="w">
</span></code></pre></div> </div>
<p><strong>Command Prompt:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> gacutil /L
</code></pre></div> </div>
</li>
</ol>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/verify-assemblies-loaded-with-gacutil/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
April 22, 2022
https://blakedrumm.com/blog/verify-assemblies-loaded-with-gacutil/
https://blakedrumm.com/blog/verify-assemblies-loaded-with-gacutil/System Center Operations Manager - Data Warehouse Grooming Tool/assets/img/scom-dw-grooming-tool.png<h2 id="book-introduction">:book: Introduction</h2>
<p>This tool can be used to modify the System Center Operations Manager Data Warehouse Grooming retention days, allows you to see grooming history, you can manually run grooming, and you may also export the current configuration so you can keep a backup of your settings. You have the option of resetting the values to Defaults for the typical data sets in the Data Warehouse.</p>
<h2 id="arrow_down_small-latest-version">:arrow_down_small: Latest Version</h2>
<p><a href="https://github.com/blakedrumm/SCOM-DW-Grooming-Tool/releases/latest" class="img-shields-io"><img src="https://img.shields.io/github/v/release/blakedrumm/SCOM-DW-Grooming-Tool" alt="Latest Version" /></a> <br />
<a href="https://github.com/blakedrumm/SCOM-DW-Grooming-Tool/releases" class="img-shields-io"><img src="https://img.shields.io/github/downloads/blakedrumm/SCOM-DW-Grooming-Tool/total.svg?style=for-the-badge&color=brightgreen" alt="Download Count Releases" /></a> <br />
<a href="https://aka.ms/SCOM-DW-Tool" class="img-shields-io"><img src="https://img.shields.io/github/downloads/blakedrumm/SCOM-DW-Grooming-Tool/latest/SCOM-DW-GroomingGUI-EXE-64bit.zip?style=for-the-badge&color=brightgreen" alt="Download Count Latest" /></a></p>
<p>Check the changelog for the latest version: <a href="https://github.com/blakedrumm/SCOM-DW-Grooming-Tool/releases/latest">Latest Changes</a></p>
<h2 id="page_with_curl-how-to-use">:page_with_curl: How to Use</h2>
<p><a href="https://github.com/blakedrumm/SCOM-DW-Grooming-Tool/releases/latest/download/SCOM-DW-GroomingGUI-EXE-64bit.zip" target="_"><button class="btn btn-primary navbar-btn">Get Started</button></a></p>
<p><a href="https://aka.ms/SCOM-DW-Grooming-Tool">https://aka.ms/SCOM-DW-Grooming-Tool</a></p>
<p>You have multiple ways to download the SCOM DW Grooming GUI Tool:</p>
<ol>
<li>Download and install the MSI: <a href="https://github.com/blakedrumm/SCOM-DW-Grooming-Tool/releases/latest/download/SCOM-DW-GroomingGUI-MSI.zip">MSI Download</a></li>
<li>Download and run the EXE: <a href="https://github.com/blakedrumm/SCOM-DW-Grooming-Tool/releases/latest/download/SCOM-DW-GroomingGUI-EXE-64bit.zip">EXE Downloads</a></li>
<li>Download or Copy the Powershell Script to Powershell ISE: <a href="https://github.com/blakedrumm/SCOM-DW-Grooming-Tool/releases/latest/download/SCOM-DW-GroomingGUI.ps1">Powershell Script</a></li>
<li>Download or Copy the Powershell Script to Powershell ISE: <a href="https://files.blakedrumm.com/SCOM-DW-GroomingGUI.txt">Text Format Alternative Download Link</a></li>
</ol>
<p>You will need to provide the Data Warehouse DB Server Name or Address, and the Data Warehouse Database Name. The script may auto detect these variables from the local registry on the machine you are running the script from. You can run on any machine that has network connectivity to the SCOM DW SQL Server. To get started, you will need to press the <strong>Get Current Settings</strong> button. This will allow the script to gather the information from the Data Warehouse database server. Once you make the changes you can save the change with <strong>Set</strong>.</p>
<p>This script will log some actions to the Application Event Log. Look for the Event Source: <code class="language-plaintext highlighter-rouge">SCOMDWTool</code></p>
<h2 id="page_facing_up-more-information">:page_facing_up: More Information</h2>
<p>You will get prompted each time you run the script to accept the license agreement, unless you select do not ask me again, when you select this it will save a file to your ProgramData Directory: <code class="language-plaintext highlighter-rouge">C:\ProgramData\SCOM-DataWarehouseGUI-AgreedToLicense.log</code></p>
<p>If you have any questions or concerns, please leave a comment and I will do my best to assist!</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-dw-grooming-tool/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
March 22, 2022
https://blakedrumm.com/blog/scom-dw-grooming-tool/
https://blakedrumm.com/blog/scom-dw-grooming-tool/How to create a Certificate Template for Operations Manager/assets/img/posts/certificate-authority-template-guide/certificate-authority.png<h2 id="steps-to-create-certificate-template">Steps to Create Certificate Template</h2>
<h3 id="step-1">Step 1</h3>
<p>Open the Certificate Authority Tool: <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-1.png" alt="Open the Certificate Authority Tool" class="img-fluid" /></p>
<h3 id="step-2">Step 2</h3>
<p>Expand the tree on the left and Right Click on <strong>Certificate Templates</strong> and select <strong>Manage</strong>: <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-2.png" alt="Open the Manage Certificate Templates Snap-In" class="img-fluid" /></p>
<h3 id="step-3">Step 3</h3>
<p>Right Click on the <strong>IPSec (Offline request)</strong> template display name, and select Duplicate Template: <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-3.png" alt="Select Duplicate Template on the IPSec (Offline request) template" class="img-fluid" /></p>
<h3 id="step-4">Step 4</h3>
<p>Confirm the <strong>Compatibility</strong> tab: <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-4.png" alt="Confirm Compatibility Tab" class="img-fluid" /></p>
<h3 id="step-5">Step 5</h3>
<p>Confirm you have modified the following in the <strong>General</strong> tab:</p>
<ul>
<li><strong>Template Display Name:</strong> <br />
<code class="language-plaintext highlighter-rouge">System Center Operations Manager</code></li>
<li><strong>Validity period:</strong> <br />
<code class="language-plaintext highlighter-rouge">5 years</code> (change this per your security policy)</li>
<li>Check <code class="language-plaintext highlighter-rouge">Publish certificate in Active Directory</code></li>
</ul>
<p><img src="/assets/img/posts/certificate-authority-template-guide/step-5.png" alt="Confirm General Tab" class="img-fluid" /></p>
<h3 id="step-6">Step 6</h3>
<p>Confirm you have modified the following in the <strong>Request Handling</strong> tab:</p>
<ul>
<li>Check <strong>Allow private key to be exportable</strong> (this is required for Server Authentication)</li>
</ul>
<p><img src="/assets/img/posts/certificate-authority-template-guide/step-6.png" alt="Confirm Request Handling Tab" class="img-fluid" /></p>
<h3 id="step-7">Step 7</h3>
<p>Confirm you have modified the following in the <strong>Cryptography</strong> tab:</p>
<ul>
<li>Verify <strong>Microsoft RSA SChannel Cryptographic Provider</strong> is Checked</li>
<li>Under <strong>Providers</strong> Check <strong>Microsoft Enhanced Cryptographic Provider v1.0</strong> and move it to below <strong>Microsoft RSA SChannel Cryptographic Provider</strong></li>
<li>Verify <strong>Minimum key size</strong> is set to <code class="language-plaintext highlighter-rouge">2048</code> or <code class="language-plaintext highlighter-rouge">1024</code> (2048 adds CPU overhead)</li>
</ul>
<p><img src="/assets/img/posts/certificate-authority-template-guide/step-7.png" alt="Confirm Cryptography Tab" class="img-fluid" /></p>
<h3 id="step-8">Step 8</h3>
<p>Confirm that <strong>None</strong> is selected for the <strong>Key Attestation</strong> tab: <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-8.png" alt="Confirm Key Attestation Tab" class="img-fluid" /></p>
<h3 id="step-9">Step 9</h3>
<p>Confirm you have modified the following in the <strong>Extensions</strong> tab: <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-9.png" alt="Confirm Extensions Tab" class="img-fluid" /></p>
<ul>
<li>Click on <strong>Application Policies</strong> and <strong>Edit</strong>
<ul>
<li>Remove <strong>IP security IKE intermediate</strong> <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-9-1.png" alt="Confirm Extensions Tab - Application Policies Extension Removal" class="img-fluid" /></li>
<li>Add:
<ul>
<li><strong>Client Authentication</strong></li>
<li><strong>Server Authentication</strong> <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-9-2.png" alt="Confirm Extensions Tab - Application Policies Extension Adding" class="img-fluid" />
<ul>
<li>Click <strong>OK</strong></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Click on <strong>Key Usage</strong> and <strong>Edit</strong>
<ul>
<li>Confirm you have checked:
<ul>
<li><strong>Make this extension critical</strong></li>
<li>Click <strong>OK</strong> <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-9-3.png" alt="Confirm Extensions Tab - Key Usage Extension Adding" class="img-fluid" /></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="step-10">Step 10</h3>
<p>Confirm you have modified the following in the <strong>Security</strong> tab:</p>
<ul>
<li>You can add multiple types of objects here: Users, Computers, Service Accounts, Groups, or Built-in security principals. <br />
For simplicity I will keep the defaults and <strong>only</strong> add the following permissions on <strong>Authenticated Users</strong>:
<ul>
<li><strong>Read</strong></li>
<li><strong>Enroll</strong> <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-10.png" alt="Confirm Security Tab" class="img-fluid" /></li>
<li>Click <strong>OK</strong> to confirm / create the Certificate Template <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-10-1.png" alt="Certificate Template Created" class="img-fluid" /></li>
</ul>
</li>
</ul>
<h3 id="step-11">Step 11</h3>
<p>Close the certificate templates Console.</p>
<ul>
<li>In the Certificate Authority tool, right click on <strong>Certificate Templates</strong>
<ul>
<li>Hover over <strong>New</strong> -> Select <strong>Certificate Template to Issue</strong> <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-11.png" alt="Deploy with Certificate Template to Issue" class="img-fluid" /></li>
<li>Select the Certificate Template Display Name you created in Step 5: <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-11-1.png" alt="Select Certificate Template you Created" class="img-fluid" />
<ul>
<li>Click <strong>OK</strong></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="step-12">Step 12</h3>
<p>Verify you are seeing the Certificate Template on your Management Server.</p>
<ul>
<li>Open Local Machine Certificate Store: <code class="language-plaintext highlighter-rouge">certlm.msc</code></li>
<li>Open Personal -> Certificates</li>
<li>Right Click Certificates and hover over <strong>All Tasks</strong> -> Select <strong>Request New Certificate…</strong> <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-12.png" alt="Select Request New Certificate on Management Server" class="img-fluid" />
<ul>
<li>Skip through the first screen
<ul>
<li>Click <strong>Next</strong></li>
</ul>
</li>
<li>Verify that you have selected <strong>Active Directory Enrollment Policy</strong>
<ul>
<li>Click <strong>Next</strong>
<!-- {:class="img-fluid"} --></li>
</ul>
</li>
<li>
<p>Select the checkbox next to the Certificate Template you created and click on the Warning sign below the Certificate Template, it says <strong>click here to configure settings.</strong> <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-12-1.png" alt="Certificate Template showing up on Management Server" class="img-fluid" /></p>
</li>
<li>Example of how to configure the certificate to be used by a Management Server <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-12-2.png" alt="Configure Certificate" class="img-fluid" />
<ul>
<li>Click <strong>OK</strong></li>
</ul>
</li>
<li>Click on <strong>Enroll</strong> <br />
<img src="/assets/img/posts/certificate-authority-template-guide/step-12-3.png" alt="Configure Certificate" class="img-fluid" /></li>
</ul>
</li>
</ul>
<h3 id="step-13">Step 13</h3>
<p>In order to use certificates with System Center Operations Manager you will need to generate / perform run the MOMCertImport tool on atleast one of the Management Servers, and any servers that will communicate via Certificates (DMZ servers, Workgroup Machines, etc.).</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">MOMCertImport.exe</code> is located in your System Center Operations Manager Installation Media inside of <code class="language-plaintext highlighter-rouge">SupportTools\AMD64</code>.
<ul>
<li>Right Click on <code class="language-plaintext highlighter-rouge">MOMCertImport.exe</code> and select <strong>Run as administrator</strong>
<ul>
<li>Select the certificate you generated via the System Center Operations Manager Certificate Template.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="step-14">Step 14</h3>
<p>Restart the Microsoft Monitoring Agent with the following Powershell Command:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Restart-Service</span><span class="w"> </span><span class="nx">HealthService</span><span class="w">
</span></code></pre></div></div>
<p>After restarting the Microsoft Monitoring Agent (HealthService). You will wait until you see the following Event (<strong>Event ID:</strong> 20053) in the Operations Manager Event Log confirming that the certificate has been loaded:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Log Name: Operations Manager
Source: OpsMgr Connector
Date: 2/28/2022 10:35:36 AM
Event ID: 20053
Task Category: None
Level: Information
Keywords: Classic
User: N/A
Computer: MS01-2019.contoso.com
Description:
The OpsMgr Connector has loaded the specified authentication certificate successfully.
</code></pre></div></div>
<blockquote>
<h2 id="bangbang-important">:bangbang: Important</h2>
<p>You may experience issues when a certificate Re-enrolls automatically. Operations Manager needs the certificate to be imported with MOMCertImport.exe prior to being able to be used by SCOM. Unfortunately, there is not an automated method for SCOM Certificate Management.</p>
</blockquote>
<blockquote>
<h2 id="notebook-note">:notebook: Note</h2>
<p>You may experience issues with connectivity between the remote machine and the Management Server(s), verify you have checked these things:</p>
<ol>
<li>Ensure all SPN’s are correctly registered for Management Servers, Operations Manager & Data Warehouse Databases, and services that are utilizing them.</li>
<li>Event ID <code class="language-plaintext highlighter-rouge">20071</code> and <code class="language-plaintext highlighter-rouge">21016</code> on Gateway point to Firewall, SPN, or Certificate issue in most cases.</li>
<li>Run the Gateway Approval Tool using the SDK (Data Access Service) account OR an account with high permission level (SysAdmin privileges) to Operations Manager SQL DB.</li>
<li>Verify you selected the appropriate certificate when you run MOMCertImport, check the certificate properties.
<ul>
<li>You may also check the following registry path: <code class="language-plaintext highlighter-rouge">HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft OperationsManager\3.0\Machine Settings</code>
<ul>
<li>Check the key: <code class="language-plaintext highlighter-rouge">ChannelCertificateSerialNumber</code> this is the serial number of the certificate you imported, reversed.</li>
</ul>
</li>
</ul>
</li>
<li>Verify that there are not any other certificates in the Local Machine Personal Store that have matching Subject Names.</li>
<li>Operations Manager only uses the first CN name in the Subject of the Certificate.</li>
<li>Cryptography API Key Storage Provider (<a href="/windows/win32/secgloss/k-gly?redirectedfrom=MSDN#_security_key_storage_provider_gly">KSP</a>) is not supported for Operations Manager certificates.</li>
</ol>
</blockquote>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/create-operations-manager-certificate-template/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
February 28, 2022
https://blakedrumm.com/blog/create-operations-manager-certificate-template/
https://blakedrumm.com/blog/create-operations-manager-certificate-template/SCOM Unix/Linux RunAs Account View - System.Xml.XmlException/assets/img/posts/unix-linux-runas-accounts-missing.png<p>I received a case today for a customer who is having issues when attempting to open the RunAs Account view for Unix/Linux RunAs Accounts in the SCOM Console (<strong>Administration Tab-> Run As Configuration -> Unix/Linux Accounts</strong>). We were unable to return any Unix/Linux RunAs Accounts in the SCOM Console, even though we can create new ones, they are not populating in the list of RunAs Accounts for Unix/Linux.</p>
<p>We noticed an exception that will pop-up intermittently (while Console is idle or active):</p>
<h2 id="pop-up-exception">Pop-Up Exception</h2>
<pre>
__Date:__ 2/1/2022 1:29:19 PM
__Application:__ Operations Manager
__Application Version:__ 10.19.10505.0
__Severity:__ Error
__Message:__
System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.LoadXml(String xml)
at Microsoft.SystemCenter.CrossPlatform.ClientLibrary.CredentialManagement.Core.ScxRunAsAccountHelper. DeserializeToScxRunAsAccount(ScxCredentialRef credentialRef)
at System.Linq.Enumerable.WhereSelectListIterator\`2.MoveNext()
at System.Collections.Generic.List\`1..ctor(IEnumerable\`1 collection)
at System.Linq.Enumerable.ToList\[TSource](IEnumerable\`1 source)
at Microsoft.SystemCenter.CrossPlatform.ClientLibrary.CredentialManagement.Core.ScxRunAsAccountHelper. EnumerateScxRunAsAccount(IManagementGroupConnection managementGroupConnection)
at Microsoft.SystemCenter.CrossPlatform.UI.OM.Integration.Administration.ScxRunAsAccountInfoFactory.EnumerateScxRunAsAccount()
at Microsoft.SystemCenter.CrossPlatform.UI.OM.Integration.Administration.ScxRunAsAccountHelper.<span style="color:yellow"><GetScxRunAsAccountInstances></span>b__6(Object sender, ConsoleJobEventArgs e)
at Microsoft.EnterpriseManagement.Mom.Internal.UI.Console.ConsoleJobExceptionHandler.ExecuteJob(IComponent component, EventHandler`1 job, Object sender, ConsoleJobEventArgs args)
</pre>
<h2 id="full-exception">Full Exception</h2>
<pre>
DetailID = 4
Count: 1
Type: System.Xml.XmlException
Message: Data at the root level is invalid. Line 1, position 1.
Stack:
[HelperMethodFrame]
System.Xml.XmlTextReaderImpl.Throw(System.Exception)
System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
System.Xml.XmlTextReaderImpl.ParseDocumentContent()
System.Xml.XmlLoader.Load(System.Xml.XmlDocument, System.Xml.XmlReader, Boolean)
System.Xml.XmlDocument.Load(System.Xml.XmlReader)
System.Xml.XmlDocument.LoadXml(System.String)
Microsoft.SystemCenter.CrossPlatform.ClientLibrary.CredentialManagement.Core.ScxRunAsAccountHelper.DeserializeToScxRunAsAccount(Microsoft.SystemCenter.CrossPlatform.ClientLibrary.Common.SDKAbstraction.ScxCredentialRef)
System.Linq.Enumerable+WhereSelectListIterator`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()
System.Collections.Generic.List`1[[System.__Canon, mscorlib]]..ctor(System.Collections.Generic.IEnumerable`1<System.__Canon>)
System.Linq.Enumerable.ToList[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1<System.__Canon>)
Microsoft.SystemCenter.CrossPlatform.ClientLibrary.CredentialManagement.Core.ScxRunAsAccountHelper.EnumerateScxRunAsAccount(Microsoft.SystemCenter.CrossPlatform.ClientLibrary.Common.SDKAbstraction.IManagementGroupConnection)
Microsoft.SystemCenter.CrossPlatform.UI.OM.Integration.Administration.ScxRunAsAccountInfoFactory.EnumerateScxRunAsAccount()
Microsoft.SystemCenter.CrossPlatform.UI.OM.Integration.Administration.ScxRunAsAccountHelper.<span style="color:yellow"><GetScxRunAsAccountInstances></span>b__6(System.Object, Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Console.ConsoleJobExceptionHandler.ExecuteJob(System.ComponentModel.IComponent, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs>, System.Object, Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs)
Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobsService.RunJob(Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobDescription)
Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobsService.RunAsyncJobInThisThread(Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobDescription)
Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobsService.RunJob(Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobDescription)
Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobsService.RunJob(System.ComponentModel.IComponent, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs>, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobErrorEventArgs>, System.Object[])
Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobsService.RunJob(System.ComponentModel.IComponent, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs>, System.Object[])
Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobs.RunJob(System.ComponentModel.IComponent, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs>, System.Object[])
Microsoft.SystemCenter.CrossPlatform.UI.OM.Integration.Administration.RunAsAccountQuery.DoQuery(System.String)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.Query`1[[System.__Canon, mscorlib]].DoQuery(System.String, System.Nullable`1<System.DateTime>)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.Query`1[[System.__Canon, mscorlib]].FullUpdateQuery(Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.CacheSession, Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.IndexTable ByRef, Boolean, System.DateTime)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.Query`1[[System.__Canon, mscorlib]].InternalSyncQuery(Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.CacheSession, Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.IndexTable, Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.UpdateReason, Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.UpdateType)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.Query`1[[System.__Canon, mscorlib]].InternalQuery(Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.CacheSession, Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.UpdateReason)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.Query`1[[System.__Canon, mscorlib]].TryDoQuery(Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.UpdateReason, Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.CacheSession)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Console.ConsoleJobExceptionHandler.ExecuteJob(System.ComponentModel.IComponent, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs>, System.Object, Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs)
Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobsService.RunJob(Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobDescription)
Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobsService.RunAsyncJobInThisThread(Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobDescription)
Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobsService.RunJob(Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobDescription)
Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobsService.RunJob(System.ComponentModel.IComponent, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs>, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobErrorEventArgs>, System.Object[])
Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobsService.RunJob(System.ComponentModel.IComponent, System.EventHandler`1<Microsoft.EnterpriseManagement.ConsoleFramework.ConsoleJobEventArgs>, System.Object[])
Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.Query`1[[System.__Canon, mscorlib]].DoQuery(Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.UpdateReason, Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.CacheSession)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.QueryBase.Update(Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.UpdateReason, Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.CacheSession)
Microsoft.EnterpriseManagement.Mom.Internal.UI.Cache.DataCache.Polling()
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
System.Threading.ThreadHelper.ThreadStart()
[GCFrame]
[DebuggerU2MCatchHandlerFrame]
</pre>
<h2 id="how-to-resolve">How to Resolve</h2>
<p>First we ran the following Powershell command output to gather RunAs Accounts related to Unix/Linux:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Get-SCOMRunAsAccount</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">AccountType</span><span class="w"> </span><span class="o">-like</span><span class="w"> </span><span class="s2">"SCX*"</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>We compared the above output to the accounts we can choose in the RunAs Profile for Unix/Linux Action Account. We noticed an entry that was not in the <code class="language-plaintext highlighter-rouge">Get-SCOMRunAsAccount</code> command run above:
<img src="/assets/img/posts/unix-linux-runas-accounts-orphaned.png" alt="Orphaned RunAs Accounts" class="img-fluid" /></p>
<p>I asked the customer if he is comfortable with removing the RunAs Account and re-adding the Account. He said this was fine, so we proceeded to remove the RunAs Account like this:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Get-SCOMRunAsAccount</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="s2">"Test"</span><span class="p">}</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Remove-SCOMRunAsAccount</span><span class="w">
</span></code></pre></div></div>
<h1 id="conclusion">Conclusion</h1>
<p>Removing the <strong>Orphaned RunAs account</strong> allowed the Unix/Linux RunAs Account view to populate as intended. You can only remove these Orphaned RunAs accounts with the Powershell Commands: <code class="language-plaintext highlighter-rouge">Get-SCOMRunAsAccount</code> and <code class="language-plaintext highlighter-rouge">Remove-SCOMRunAsAccount</code></p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-unix-linux-runasaccount-view-error/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
February 1, 2022
https://blakedrumm.com/blog/scom-unix-linux-runasaccount-view-error/
https://blakedrumm.com/blog/scom-unix-linux-runasaccount-view-error/How to resolve SCOM Notifications Stopped & No New Alerts/assets/img/posts/SCOM-Notification-Bell-Email.png<p>First thing I noticed was that the SCOM Management Servers had an SCOM Agent Installed on it. We verifing by navigating to the following location, you can see the <strong>Agent Management Groups</strong>:
<img src="/assets/img/posts/agent-registry-scom-ms.png" alt="Management Server - Bad Registry Keys" class="img-fluid" /></p>
<p>Apparently the Operations Manager Management Server received a package from SCCM, and this attempted to automatically install the SCOM Agent (Microsoft Monitoring Agent). And during this process the installer overwrote some registry keys inside of the following location: <br />
<code class="language-plaintext highlighter-rouge">HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\</code></p>
<blockquote>
<h2 id="precaution">Precaution</h2>
<p>Take care when directly modifying the Registry via <a href="https://support.microsoft.com/windows/how-to-open-registry-editor-in-windows-10-deab38e6-91d6-e0aa-4b7c-8878d9e07b11">regedit.exe</a>. If you insist on making changes, always backup the registry first. There is always the possibility you can cause more damage than you are fixing.</p>
</blockquote>
<p>I had the customer Delete the <strong>Agent Management Groups</strong> key and we matched / created the Registry Values for <strong>Server Management Groups</strong> compared to my lab environment. We needed to create the Management Group Name Key in my situation.
<img src="/assets/img/posts/management-server-registry.png" alt="Management Server - Good Registry Keys" class="img-fluid" /></p>
<p>After doing this we cleared the cache on the SCOM Management Servers by running the following PowerShell script: <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Clear-SCOMCache.ps1">SCOM-Scripts-and-SQL/Clear-SCOMCache.ps1 at master · blakedrumm/SCOM-Script-and-SQL</a></p>
<p>We waited for a few minutes after clearing the SCOM Management Server cache. The Management Servers were coming back online, but they were still not receiving new Alerts, and there were not any Notification Emails.</p>
<p>While reviewing the Operations Manager Event Logs, we found that there were 2115 Errors indicating an issue with the insertion of Discovery and other related data:</p>
<hr />
<h2 id="event-1">Event 1</h2>
<pre>
__Log Name:__ Operations Manager
__Source:__ HealthService
__Date:__ 1/20/2022 3:42:02 PM
__Event ID:__ 2115
__Task Category:__ None
__Level:__ Warning
__Keywords:__ Classic
__User:__ N/A
__Computer:__ ManagementServer1.contoso.com
__Description:__
A Bind Data Source in Management Group ManagementGroup1 has posted items to the workflow, but has not received a response in 480 seconds. This indicates a performance or functional problem with the workflow.
__Workflow Id :__ <span style="color:yellow">Microsoft.SystemCenter.CollectEventData</span>
__Instance :__ ManagementServer1.contoso.com
__Instance Id :__ {AEC38E5Z-67A9-0406-20DB-ACC33BB9C4A4}
</pre>
<hr />
<h2 id="event-2">Event 2</h2>
<pre>
__Log Name:__ Operations Manager
__Source:__ HealthService
__Date:__ 1/20/2022 3:42:02 PM
__Event ID:__ 2115
__Task Category:__ None
__Level:__ Warning
__Keywords:__ Classic
__User:__ N/A
__Computer:__ ManagementServer1.contoso.com
__Description:__
A Bind Data Source in Management Group ManagementGroup1 has posted items to the workflow, but has not received a response in 480 seconds. This indicates a performance or functional problem with the workflow.
__Workflow Id :__ <span style="color:yellow">Microsoft.SystemCenter.CollectPerformanceData</span>
__Instance :__ ManagementServer1.contoso.com
__Instance Id :__ {AEC38E5Z-67A9-0406-20DB-ACC33BB9C4A4}
</pre>
<hr />
<h2 id="event-3">Event 3</h2>
<pre>
__Log Name:__ Operations Manager
__Source:__ HealthService
__Date:__ 1/20/2022 3:42:02 PM
__Event ID:__ 2115
__Task Category:__ None
__Level:__ Warning
__Keywords:__ Classic
__User:__ N/A
__Computer:__ ManagementServer1.contoso.com
__Description:__
A Bind Data Source in Management Group ManagementGroup1 has posted items to the workflow, but has not received a response in 480 seconds. This indicates a performance or functional problem with the workflow.
__Workflow Id :__ <span style="color:yellow">Microsoft.SystemCenter.CollectPublishedEntityState</span>
__Instance :__ ManagementServer1.contoso.com
__Instance Id :__ {AEC38E5Z-67A9-0406-20DB-ACC33BB9C4A4}
</pre>
<hr />
<h2 id="event-4">Event 4</h2>
<pre>
__Log Name:__ Operations Manager
__Source:__ HealthService
__Date:__ 1/20/2022 3:42:03 PM
__Event ID:__ 2115
__Task Category:__ None
__Level:__ Warning
__Keywords:__ Classic
__User:__ N/A
__Computer:__ ManagementServer1.contoso.com
__Description:__
A Bind Data Source in Management Group ManagementGroup1 has posted items to the workflow, but has not received a response in 480 seconds. This indicates a performance or functional problem with the workflow.
__Workflow Id :__ <span style="color:yellow">Microsoft.SystemCenter.CollectSignatureData</span>
__Instance :__ ManagementServer1.contoso.com
__Instance Id :__ {AEC38E5Z-67A9-0406-20DB-ACC33BB9C4A4}
</pre>
<hr />
<h2 id="event-5">Event 5</h2>
<pre>
__Log Name:__ Operations Manager
__Source:__ HealthService
__Date:__ 1/20/2022 3:42:30 PM
__Event ID:__ 2115
__Task Category:__ None
__Level:__ Warning
__Keywords:__ Classic
__User:__ N/A
__Computer:__ ManagementServer1.contoso.com
__Description:__
A Bind Data Source in Management Group ManagementGroup1 has posted items to the workflow, but has not received a response in 480 seconds. This indicates a performance or functional problem with the workflow.
__Workflow Id :__ <span style="color:yellow">Microsoft.SystemCenter.CollectDiscoveryData</span>
__Instance :__ ManagementServer1.contoso.com
__Instance Id :__ {AEC38E5Z-67A9-0406-20DB-ACC33BB9C4A4}
</pre>
<hr />
<p>We reviewed the current SQL Logs and found that there were authentication failures that indicated the <strong>Computer Account</strong> for the SCOM Management Server didnt have permission to the Database. This lead us to check the <strong>Default Action Account</strong> in Run As Profiles. We modified the <strong>Default Action Account</strong> for the Management Servers to be assigned an <strong>Windows Action Account</strong> instead of <strong>Local System</strong>. This resolved the issue and now Notifications and Alerts are being being sent normally.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-notifications-and-alerts-stopped-working/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 28, 2022
https://blakedrumm.com/blog/scom-notifications-and-alerts-stopped-working/
https://blakedrumm.com/blog/scom-notifications-and-alerts-stopped-working/UNIX/Linux System Center Operations Manager Agents Troubleshooting Tips/assets/img/posts/prerequisite-software-unix-linux.png<p><sub>This post was last updated on September 27th, 2023</sub></p>
<h2 id="build-list-containing-the-scom-linux-agent-versions">Build list containing the SCOM Linux Agent versions</h2>
<p>The following url contains the versions of the SCX Agent: <a href="https://docs.microsoft.com/system-center/scom/release-build-versions">https://docs.microsoft.com/system-center/scom/release-build-versions</a></p>
<h2 id="verify-the-versions-for-all-prerequisite-software">Verify the versions for all prerequisite software</h2>
<p>You can run the following command on a monitored and not monitored server to compare the software installed, or verify with the official list <a href="https://docs.microsoft.com/system-center/scom/plan-supported-crossplat-os">https://docs.microsoft.com/system-center/scom/plan-supported-crossplat-os</a>:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rpm <span class="nt">-qa</span> | egrep <span class="s2">"^glibc|^openssl|^pam|^scx|^omi"</span>
</code></pre></div></div>
<table class="table table-hover table-text d-block overflow-auto">
<thead>
<tr>
<th>Agent Version</th>
<th>Version</th>
<th>Management Group Version</th>
<th>Release Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>scx-1.5.1-242.e16.x86_64</td>
<td>7.5.1068.0</td>
<td>SCOM 2012 R2 UR12</td>
<td>01/27/2017</td>
</tr>
</tbody>
</table>
<p> </p>
<p><strong>Working Example:</strong> <br />
<img src="/assets/img/posts/prerequisite-software-unix-linux-example2.png" alt="Example 2 - Prerequisite Software" class="img-fluid" /></p>
<p><strong>Non-working Example:</strong> <br />
<img src="/assets/img/posts/prerequisite-software-unix-linux-example3-notworking.png" alt="Example 3 - Prerequisite Software" class="img-fluid" /></p>
<p> </p>
<hr />
<p> </p>
<h2 id="clearing-the-system-security-services-daemon-sssd-cache">Clearing the System Security Services Daemon (SSSD) Cache</h2>
<p>The System Security Services Daemon (SSSD) provides access to identity and authentication providers. Basically rather than relying on locally configured authentication, SSSD is used to lookup its local cache. The entries within this cache may come from different remote identity providers, such as an LDAP directory, Kerberos, or Active Directory for example.</p>
<p>SSSD caches the results of users and credentials from these remote locations so that if the identity provider goes offline, the user credentials are still available and users can still login. This helps to improve performance and facilitates scalability with a single user that can login over many systems, rather than using local accounts everywhere.</p>
<p>The cached results can potentially be problematic if the stored records become stale and are no longer in sync with the identity provider, so it is important to know how to flush the SSSD cache to fix various problems and update the cache.</p>
<blockquote>
<h3 id="notebook-note">:notebook: Note</h3>
<p>It’s recommend to only clear the sssd cache if the identity provider servers performing the authentication within the domain are available, otherwise users will not be able to log in once the sssd cache has been flushed.</p>
</blockquote>
<h3 id="stop-sssd-service">Stop SSSD Service</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Service sssd stop;
</code></pre></div></div>
<h3 id="clear-sssd-cache">Clear SSSD Cache</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm -rf /var/lib/sss/db/*;
</code></pre></div></div>
<h3 id="start-sssd-service">Start SSSD Service</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service sssd start
</code></pre></div></div>
<p>SSSD should now start up correctly with an empty cache, any user login will now first go directly to the defined identity provider for authentication, and then be cached locally afterwards.</p>
<p> </p>
<hr />
<p> </p>
<h2 id="tail-the-logs">Tail the Logs</h2>
<h3 id="enable-verbose-scx-logs">Enable Verbose SCX Logs</h3>
<p>Use the below command to enable verbose logging for the SCX Provider:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scxadmin <span class="nt">-log-set</span> all verbose
</code></pre></div></div>
<h3 id="enable-verbose-logging-for-omi-server">Enable Verbose logging for OMI Server</h3>
<p>Use the below command to modify the omiserver.conf file. Change loglevel to one of the following valid options, verbose being highest:
<strong>ERROR, WARNING, INFO, DEBUG, VERBOSE</strong></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>vim /etc/opt/omi/conf/omiserver.conf
</code></pre></div></div>
<p>If loglevel does not exist in the file you can add the following lines to the file and change the loglevel value</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">##</span>
<span class="c">## loglevel -- set the loggiing options for OMI server</span>
<span class="c">## Valid options are: ERROR, WARNING, INFO, DEBUG, VERBOSE (debug build)</span>
<span class="c">## If commented out, then default value is: WARNING</span>
<span class="c">##</span>
loglevel <span class="o">=</span> INFO
</code></pre></div></div>
<p>After saving and quitting vim, restart the service with below command for logging to be enabled</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> /opt/omi/bin/service_control restart
</code></pre></div></div>
<h3 id="secure-log">Secure Log</h3>
<p>You can run the following command to show current log data pertaining to authentication and authorization privileges:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tail</span> <span class="nt">-f</span> /var/log/secure
</code></pre></div></div>
<h3 id="messages-log">Messages Log</h3>
<p>You can run the following command to show all the global system messages, including the messages that are logged during system startup:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tail</span> <span class="nt">-f</span> /var/log/messages
</code></pre></div></div>
<h3 id="omi">OMI</h3>
<h4 id="server-log">Server Log</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tail</span> <span class="nt">-f</span> /var/opt/omi/log/omiserver.log
</code></pre></div></div>
<h4 id="agent-log">Agent Log</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tail</span> <span class="nt">-f</span> /var/opt/microsoft/scx/log/omiagent.root.root.log
</code></pre></div></div>
<h3 id="scx">SCX</h3>
<h4 id="agent-log-1">Agent Log</h4>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tail</span> <span class="nt">-f</span> /var/opt/microsoft/scx/log/scx.log
</code></pre></div></div>
<p> </p>
<hr />
<p> </p>
<h2 id="verify-openssl-s_client">Verify OpenSSL s_client</h2>
<p>The OpenSSL s_client command is a helpful test client for troubleshooting remote SSL or TLS connections:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client <span class="nt">-connect</span> server.domain.com:1270
openssl s_client <span class="nt">-connect</span> server.domain.com:1270 <span class="nt">-tls1</span>
openssl s_client <span class="nt">-connect</span> server.domain.com:1270 <span class="nt">-ssl3</span>
</code></pre></div></div>
<p> </p>
<hr />
<h2 id="check-linux-ciphers">Check Linux Ciphers</h2>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl ciphers <span class="nt">-V</span>
</code></pre></div></div>
<p> </p>
<h2 id="get-mb--gb-size-of-file">Get MB / GB size of file</h2>
<p>Run the following command to gather the MB / GB size of a file:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">du</span> <span class="nt">-sh</span> /var/opt/microsoft/scx/log/scx.log
</code></pre></div></div>
<p> </p>
<hr />
<p> </p>
<h2 id="winrm-enumerate-scx-agent">WinRM Enumerate SCX Agent</h2>
<p>From the Management Server(s) in the Unix/Linux Resource Pool, verify that the following command resolves correctly:</p>
<h3 id="basic-authentication">Basic Authentication</h3>
<pre><code class="language-cmd">winrm enumerate http://schemas.microsoft.com/wbem/wscim/1/cim-schema/2/SCX_Agent?__cimnamespace=root/scx -username:<username> -password:<password> -r:https://<LINUXSERVERFQDN>:1270/wsman -auth:basic -skipCAcheck -skipCNcheck -skipRevocationcheck -encoding:utf-8
</code></pre>
<h3 id="kerberos-authentication">Kerberos Authentication</h3>
<pre><code class="language-cmd">winrm e http://schemas.microsoft.com/wbem/wscim/1/cim-schema/2/SCX_Agent?__cimnamespace=root/scx -r:https://<LINUXSERVERFQDN>:1270 -u:<[email protected]> -p:<password> -auth:Kerberos -skipcacheck -skipcncheck -encoding:utf-8
</code></pre>
<blockquote>
<h3 id="notebook-note-1">:notebook: Note 1</h3>
<p>Verify that you have enabled Kerberos via the Management Server Registry on each Management Server in the resource pool you are using to monitor the Unix/Linux agents: <a href="https://docs.microsoft.com/system-center/scom/manage-linux-kerberos-auth">https://docs.microsoft.com/system-center/scom/manage-linux-kerberos-auth</a></p>
</blockquote>
<h4 id="example-1">Example 1</h4>
<h5 id="issue">Issue</h5>
<p>You may experience an error that contains the following when running the above Commands:</p>
<pre>
WSManFault
Message = The server certificate on the destination computer (<LINUXSERVERFQDN>:1270) has the following errors:
Encountered an internal error in the SSL library.
Error number: -2147012721 0x80072F8F
A security error occurred
</pre>
<p>or this error via the Discovery Wizard:</p>
<pre>
Agent verification failed. Error detail: The server certificate on the destination computer (<LINUXSERVERFQDN>:1270) has the following errors:
Encountered an internal error in the SSL library.
It is possible that:
1. The destination certificate is signed by another certificate authority not trusted by the management server.
2. The destination has an invalid certificate, e.g., its common name (CN) does not match the fully qualified domain name (FQDN) used for the connection. The FQDN used for the connection is: <LINUXSERVERFQDN>.
3. The servers in the resource pool have not been configured to trust certificates signed by other servers in the pool.
</pre>
<h5 id="resolution">Resolution</h5>
<ol>
<li>You could potentially import (<strong>Merge</strong>) the below known working ciphers by copying the text to a new file on your server called <code class="language-plaintext highlighter-rouge">example.reg</code>, right click and Merge the file into your registry:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002]
"Functions"="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P521,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P521,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P521,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P521,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P521,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P521,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P521,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P521,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P521,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256"
</code></pre></div> </div>
</li>
<li>An alternative to importing the above registry is to download and run <a href="https://www.nartac.com/Products/IISCrypto">IISCrypto</a> and select <strong>Best Practices</strong>.</li>
</ol>
<blockquote>
<h3 id="notebook-note-1">:notebook: Note</h3>
<p>Be sure to verify if the Linux agent supports the same ciphers as the Management Server / Gateway.
List of Ciphers Supported for Linux / Unix SCOM Agents: <a href="https://docs.microsoft.com/system-center/scom/manage-security-crossplat-config-sslcipher#cipher-suite-support-matrix">https://docs.microsoft.com/system-center/scom/manage-security-crossplat-config-sslcipher#cipher-suite-support-matrix</a></p>
</blockquote>
<p> </p>
<hr />
<h2 id="enumerate-omi-information-on-unixlinux-machine">Enumerate OMI Information on UNIX/Linux Machine</h2>
<p>Enumerate the <strong>SCX_OperatingSystem</strong> via omicli:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opt/omi/bin/omicli ei root/scx SCX_OperatingSystem
</code></pre></div></div>
<p>Enumerate the <strong>SCX_ProcessorStatisticalInformation</strong> via omicli:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opt/omi/bin/omicli ei root/scx SCX_ProcessorStatisticalInformation
</code></pre></div></div>
<p>Some OMI WMI Namespaces on the Linux Agent:</p>
<blockquote>
<p>SCX_Agent <br />
SCX_DiskDrive <br />
SCX_DiskDriveStatisticalInformation <br />
SCX_EthernetPortStatistics <br />
SCX_FileSystem <br />
SCX_FileSystemStatisticalInformation <br />
SCX_IPProtocolEndpoint <br />
SCX_LogFile <br />
SCX_MemoryStatisticalInformation <br />
SCX_OperatingSystem <br />
SCX_ProcessorStatisticalInformation <br />
SCX_StatisticalInformation <br />
SCX_UnixProcess <br />
SCX_UnixProcessStatisticalInformation</p>
</blockquote>
<p> </p>
<hr />
<p> </p>
<h2 id="certificate-troubleshooting">Certificate Troubleshooting</h2>
<blockquote>
<h3 id="unixlinux-certificate">UNIX/Linux Certificate</h3>
<h4 id="check-certificate">Check Certificate</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl x509 <span class="nt">-in</span> /etc/opt/omi/ssl/omi.pem <span class="nt">-text</span> <span class="nt">-noout</span>
</code></pre></div> </div>
<h4 id="generate-certificate-with-custom-name">Generate Certificate with custom name</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opt/microsoft/scx/bin/tools/scxsslconfig <span class="nt">-f</span> <span class="nt">-d</span> contoso.com <span class="nt">-h</span> redhat
</code></pre></div> </div>
<h4 id="generate-certificate">Generate Certificate</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opt/microsoft/scx/bin/tools/scxsslconfig <span class="nt">-f</span>
</code></pre></div> </div>
<h4 id="remove-old-certificate">Remove Old Certificate</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">rm</span> /etc/opt/omi/ssl/omikey.pem <span class="nt">--force</span>
</code></pre></div> </div>
</blockquote>
<p> </p>
<blockquote>
<h3 id="configure-the-xplat-certificates-exportimport-for-each-management-server-in-the-resource-pool">Configure the Xplat certificates (export/import) for each management server in the resource pool</h3>
<p>The below steps show how to configure Xplat certificates easily for Management Servers with Powershell. You can automate this process for as many management servers as you need!</p>
<h4 id="windows-management-server-commands">Windows Management Server Commands</h4>
<h5 id="export-certificate-on-ms1-admin-powershell-prompt">Export Certificate On MS1 (Admin Powershell Prompt)</h5>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>& "C:\Program Files\Microsoft System Center\Operations Manager\Server\scxcertconfig.exe" -export \\MS2\c$\MS1.cer
</code></pre></div> </div>
<h5 id="export-certificate-on-ms2-admin-powershell-prompt">Export Certificate On MS2 (Admin Powershell Prompt)</h5>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>& "C:\Program Files\Microsoft System Center\Operations Manager\Server\scxcertconfig.exe" -export \\MS1\c$\MS2.cer
</code></pre></div> </div>
<p> </p>
<h5 id="import-certificate-on-ms1-admin-powershell-prompt">Import Certificate On MS1 (Admin Powershell Prompt)</h5>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>& "C:\Program Files\Microsoft System Center\Operations Manager\Server\scxcertconfig.exe" -import \\MS1\c$\MS2.cer
</code></pre></div> </div>
<h5 id="import-certificate-on-ms2-admin-powershell-prompt">Import Certificate On MS2 (Admin Powershell Prompt)</h5>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>& "C:\Program Files\Microsoft System Center\Operations Manager\Server\scxcertconfig.exe" -import \\MS2\c$\MS1.cer
</code></pre></div> </div>
</blockquote>
<p> </p>
<blockquote>
<h3 id="location-for-certificates">Location for Certificates</h3>
<h4 id="scom-2012-linux-agent">SCOM 2012 Linux Agent:</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/opt/microsoft/scx/ssl/scx.pem
/etc/opt/microsoft/scx/ssl/scx-host-<HostName>.pem
</code></pre></div> </div>
<p> </p>
<h4 id="scom-2016-linux-agent-and-newer">SCOM 2016 Linux Agent and newer:</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/opt/omi/ssl/omi.pem
/etc/opt/omi/ssl/omi-host-<HostName>.pem
</code></pre></div> </div>
</blockquote>
<p> </p>
<hr />
<p> </p>
<h2 id="linux-agent-certificate-hostname-detection-steps-during-initial-installation">Linux Agent Certificate Hostname Detection steps during initial Installation</h2>
<p>The following steps are what happens (from a high level) during initial installation of the Linux / Unix Agent to generate a Certificate for the Agent.</p>
<ol>
<li>Try <code class="language-plaintext highlighter-rouge">hostname -f</code> (this will fail on some Linux systems)</li>
<li>Attempt to obtain the domain name from <code class="language-plaintext highlighter-rouge">/etc/resolve.conf</code></li>
<li>Attempt to obtain long hostname with <code class="language-plaintext highlighter-rouge">nslookup</code> command</li>
</ol>
<p> </p>
<hr />
<p> </p>
<h2 id="purge-scx-agent-installation">Purge SCX Agent Installation</h2>
<p>On the Unix/Linux Machine locate the SCOM Linux Agent installation file, and run the following command to uninstall and purge the SCOM Linux Agent installation:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sh ./scx-<version>.<<span class="nb">type</span><span class="o">></span>.<version>.<<span class="nb">arch</span><span class="o">></span>.sh <span class="nt">--purge</span> <span class="nt">--force</span>
</code></pre></div></div>
<hr />
<p> </p>
<h2 id="linux-regular-expression-regex">Linux Regular Expression (Regex)</h2>
<p>The SCOM console uses .NET Regex and the SCX Agent uses POSIX Regex.</p>
<hr />
<p> </p>
<h2 id="firewalld-service">Firewalld Service</h2>
<p>Check that the SCOM Linux Agent (omiengine) Port is listening, which would mean the SCX Linux Agent service is listening:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>netstat <span class="nt">-tulpn</span> | <span class="nb">grep</span> <span class="nt">-i</span> 1270
</code></pre></div></div>
<ol>
<li>
<p>To open port <em>1270</em> (<strong>any</strong> ip address) for System Center Operations Manager (SCOM) on a Red Hat server using Firewalld, you can execute the following commands:</p>
<ol>
<li>
<p><strong>Open the Port</strong>: To open port 1270, you would typically use the <code class="language-plaintext highlighter-rouge">--add-port</code> option to specify the port and the protocol (either TCP or UDP, depending on your requirement).</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>firewall-cmd <span class="nt">--zone</span><span class="o">=</span>public <span class="nt">--add-port</span><span class="o">=</span>1270/tcp <span class="nt">--permanent</span>
</code></pre></div> </div>
<p>The <code class="language-plaintext highlighter-rouge">--zone=public</code> flag specifies that you’re modifying the public zone, but you could replace <code class="language-plaintext highlighter-rouge">public</code> with the name of another zone if that’s more appropriate for your setup. The <code class="language-plaintext highlighter-rouge">--permanent</code> flag makes sure the rule survives reboots.</p>
</li>
<li>
<p><strong>Reload Firewalld</strong>: After adding the port, you’ll need to reload Firewalld to apply the changes:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>firewall-cmd <span class="nt">--reload</span>
</code></pre></div> </div>
</li>
<li>
<p><strong>Check the Rules</strong>: To make sure the port has been opened, you can list the rules for the public zone as follows:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>firewall-cmd <span class="nt">--zone</span><span class="o">=</span>public <span class="nt">--list-ports</span>
</code></pre></div> </div>
<p>This should display the ports that are open, and 1270 should be among them if the previous commands were successful.</p>
</li>
</ol>
<p>These commands are based on the assumption that you are using the <code class="language-plaintext highlighter-rouge">firewall-cmd</code> utility, which is the default frontend for Firewalld on Red Hat.</p>
</li>
<li>
<p>To open port <em>1270</em> (<strong>specific</strong> ip address) for System Center Operations Manager (SCOM) on a Red Hat server using Firewalld, you can execute the following commands:</p>
<p>Here’s how you can open port 1270 for a specific IP address (e.g., <code class="language-plaintext highlighter-rouge">192.168.1.10</code>):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>firewall-cmd <span class="nt">--zone</span><span class="o">=</span>public <span class="nt">--add-rich-rule</span><span class="o">=</span><span class="s1">'rule family="ipv4" source address="192.168.1.10" port port=1270 protocol=tcp accept'</span> <span class="nt">--permanent</span>
</code></pre></div> </div>
<p>This adds a “rich rule” to the public zone, specifying that only traffic from the IP address <code class="language-plaintext highlighter-rouge">192.168.1.10</code> is allowed to access port 1270 over TCP. Replace <code class="language-plaintext highlighter-rouge">192.168.1.10</code> with the specific IP address that needs access to your SCOM service on port 1270.</p>
<p>After adding the rule, don’t forget to reload the firewall to apply the changes:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>firewall-cmd <span class="nt">--reload</span>
</code></pre></div> </div>
<p>To check if the rule has been successfully added, you can list all the rich rules for the public zone like so:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>firewall-cmd <span class="nt">--zone</span><span class="o">=</span>public <span class="nt">--list-rich-rules</span>
</code></pre></div> </div>
<p>This should show your newly added rule among the list.</p>
</li>
</ol>
<p><strong>Note:</strong> Be sure to check any security policies or guidelines in your organization before opening ports on a server.</p>
<p> </p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-unix-linux-troubleshooting-tips/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 26, 2022
https://blakedrumm.com/blog/scom-unix-linux-troubleshooting-tips/
https://blakedrumm.com/blog/scom-unix-linux-troubleshooting-tips/SCOM ACS Collector Troubleshooting Tips/assets/img/posts/system-center-operations-manager-acs.png<p>A customer of mine was having problems with Audit Collection Services in SCOM 2019 UR3. I figured this information may prove helpful someday to someone. Enjoy!</p>
<hr />
<h2 id="sql-queries">SQL Queries</h2>
<p>Here are some ACS SQL Queries you can utilize: <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/tree/master/SQL%20Queries/OperationsManagerAC">https://github.com/blakedrumm/SCOM-Scripts-and-SQL/tree/master/SQL%20Queries/OperationsManagerAC</a></p>
<hr />
<h2 id="verify-acs-collector-performance">Verify ACS collector performance</h2>
<ol>
<li>Open Performance Monitor, right click on Start Menu and select run. <br />
In run box type the following:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>perfmon.msc
</code></pre></div> </div>
</li>
<li>
<p>Once Opened go to Monitoring Tools Folder, then right click on <strong>Performance Monitor</strong> and go to <strong>Properties</strong>: <br />
<img src="/assets/img/posts/ACS-perfmonitor-properties.png" alt="Performance Monitor Properties" class="img-fluid" /></p>
</li>
<li>
<p>Select the Data tab: <br />
<img src="/assets/img/posts/ACS-PerformanceMonitorProperties-General.png" alt="Performance Monitor Properties - General" class="img-fluid" /></p>
</li>
<li>
<p>Clear the currently selected counters by removing each counter listed with the <strong>Remove</strong> Button, then select <strong>Add</strong>: <br />
<img src="/assets/img/posts/ACS-PerformanceMonitorProperties-DataSets.png" alt="Performance Monitor Properties - Data Sets" class="img-fluid" /></p>
</li>
<li>
<p>Locate the <strong>ACS Collector</strong> in available counters, select it, and click on the <strong>Add</strong> button: <br />
<img src="/assets/img/posts/ACS-CollectorPerformanceCounter.png" alt="ACS Collector Performance Counter" class="img-fluid" /> <br />
This is how it should look when it is added: <br />
<img src="/assets/img/posts/ACS-CollectorPerformanceCounter-Added.png" alt="ACS Collector Performance Counter - Added" class="img-fluid" /></p>
</li>
<li>
<p>Click <strong>OK</strong> to confirm the property settings.</p>
</li>
<li>
<p>Click on the following button to change the view type, change to <strong>Report</strong>: <br />
<img src="/assets/img/posts/ACS-ChangeToReportView.png" alt="Change to Report View" class="img-fluid" /></p>
</li>
<li>View your performance data for ACS: <br />
<img src="/assets/img/posts/ACS-PerformanceData.png" alt="ACS Performance Data" class="img-fluid" /></li>
</ol>
<hr />
<h2 id="gather-partition-table-history">Gather Partition Table History</h2>
<p>You can run the following tsql query against the OperationsManagerAC</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Status:</span>
<span class="c1">-- 0: active, set by collector</span>
<span class="c1">-- 1: inactive, mark for closing during collector startup & indexing, set manually</span>
<span class="c1">-- 2: archived, ready for deletion, set from outside the collector</span>
<span class="c1">-- 100 - 108: closed, indexing in progress</span>
<span class="c1">-- 109: indexing complete</span>
<span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="n">dtpartition</span> <span class="k">order</span> <span class="k">by</span> <span class="n">partitionstarttime</span>
</code></pre></div></div>
<hr />
<h2 id="enable-acs-collector-logging">Enable ACS Collector Logging</h2>
<h3 id="traceflags">TraceFlags</h3>
<p>TraceFlags consists of three groups that are OR’d (added) together. They are Verbosity Level, Component, and Log Output Method. Verbosity Level refers to the number and type of events that are logged to the trace log when trace logging is enabled, while Component can only be used if the Verbosity Level is set to Level Debug and is used to enable/disable logging for various internal components. Log Output Method is used to specify the location that tracing information is written to.</p>
<h4 id="verbosity-level-settings">Verbosity Level settings</h4>
<div class="responsive-table">
<table>
<thead>
<tr>
<th scope="col">Value</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00000000</td>
<td>No logging.</td>
</tr>
<tr>
<td>0x00000001</td>
<td>Level Error. Logs only errors.</td>
</tr>
<tr>
<td>0x00000002</td>
<td>Level Warning. Logs errors and warnings.</td>
</tr>
<tr>
<td>0x00000003</td>
<td>Level Informational. Logs errors, warnings, and information.</td>
</tr>
<tr>
<td>0x00000004</td>
<td>Level Debug. Logs everything and is very verbose.</td>
</tr>
</tbody>
</table>
</div>
<hr />
<h4 id="component-settings">Component settings</h4>
<div class="responsive-table">
<table>
<thead>
<tr>
<th scope="col">Value</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00000010</td>
<td>General</td>
</tr>
<tr>
<td>0x00000020</td>
<td>Networking</td>
</tr>
<tr>
<td>0x00000080</td>
<td>Event tracking</td>
</tr>
</tbody>
</table>
</div>
<hr />
<h4 id="log-output-method-settings">Log Output Method settings</h4>
<div class="responsive-table">
<table>
<thead>
<tr>
<th scope="col">Value</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00020000</td>
<td>Log to debug out</td>
</tr>
<tr>
<td>0x00040000</td>
<td>Log to the console, if available (only when running the collector from the command line)</td>
</tr>
<tr>
<td>0x00080000</td>
<td>Log to file in `%SystemRoot%\Temp` directory</td>
</tr>
</tbody>
</table>
</div>
<hr />
<blockquote>
<p>%SystemRoot% = C:\Windows\</p>
</blockquote>
<p>Trace log files are located in the <code class="language-plaintext highlighter-rouge">%SystemRoot%\Temp</code> directory. For the Collector, the log files are written to <code class="language-plaintext highlighter-rouge">%SystemRoot%\Temp\AdtServer.log</code> and <code class="language-plaintext highlighter-rouge">%SystemRoot%\Temp\AdtSrvDll.log</code>. When a log file fills to capacity, the system overwrites the oldest entries with the most recent entries. Log files have a default size of 1 MB and begin to overwrite the oldest entries once they are full.</p>
<ol>
<li>To enable logging, open RegEdit navigate to the following location: <br />
<code class="language-plaintext highlighter-rouge">HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\AdtAgent\Parameters</code></li>
<li>
<p>Create the TraceFlags <strong>DWORD (32-bit) Value</strong> and set it to <strong>Hexadecimal</strong> <code class="language-plaintext highlighter-rouge">80003</code> unless otherwise advised. Trace logging begins immediately; no restart of the Collector is needed. Additionally, Change permission must be granted to <code class="language-plaintext highlighter-rouge">%SystemRoot%\Temp</code> for the <strong>NetworkService</strong> account.</p>
<blockquote>
<h3 id="note">Note</h3>
<p>For example, to log errors, warnings, and information messages to a file change the traceflags registry value to <code class="language-plaintext highlighter-rouge">0x00080003</code>. This is a combination of <code class="language-plaintext highlighter-rouge">0x00080000</code> <em>[file]</em> and <code class="language-plaintext highlighter-rouge">0x00000003</code> <em>[errors +warnings+informational]</em>.</p>
</blockquote>
</li>
<li>To disable logging, delete the <strong>TraceFlags</strong> value or set it to <code class="language-plaintext highlighter-rouge">0</code>.</li>
</ol>
<hr />
<h2 id="change-the-scheduled-time-the-sql-scripts-run-that-are-in-the-acs-installation-folder">Change the scheduled time the SQL Scripts run that are in the ACS Installation Folder</h2>
<p>In order for you to change the time the jobs will run the partitioning, grooming and reindexing. You need to edit the dtConfig table and change the <strong>“table switch offset in seconds since midnight UTC”</strong> value to another time in UTC (<a href="https://www.google.com/search?q=UTC+Converter">Google UTC Converter</a>):</p>
<p>Get current configuration:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="n">dtConfig</span>
</code></pre></div></div>
<p>Get current SQL UTC time:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">GETUTCDATE</span><span class="p">()</span> <span class="k">AS</span> <span class="s1">'Current UTC Time'</span>
</code></pre></div></div>
<p>Get 10 minutes ahead of current UTC time:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">DATEADD</span><span class="p">(</span><span class="k">MINUTE</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="n">GETUTCDATE</span><span class="p">())</span>
</code></pre></div></div>
<p>Get seconds from midnight for dtConfig <strong>“table switch offset in seconds since midnight UTC”</strong> ahead in seconds, in this example we add 10 minutes to the current UTC time:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">Declare</span> <span class="o">@</span><span class="n">d</span> <span class="nb">DateTime</span>
<span class="k">Select</span> <span class="o">@</span><span class="n">d</span> <span class="o">=</span> <span class="n">DATEADD</span><span class="p">(</span><span class="k">MINUTE</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="n">GETUTCDATE</span><span class="p">())</span>
<span class="k">Select</span> <span class="p">(</span><span class="n">DatePart</span><span class="p">(</span><span class="n">HOUR</span><span class="p">,</span> <span class="o">@</span><span class="n">d</span><span class="p">)</span> <span class="o">*</span> <span class="mi">3600</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">DatePart</span><span class="p">(</span><span class="k">MINUTE</span><span class="p">,</span> <span class="o">@</span><span class="n">d</span><span class="p">)</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span> <span class="o">+</span> <span class="n">DatePart</span><span class="p">(</span><span class="k">SECOND</span><span class="p">,</span> <span class="o">@</span><span class="n">d</span><span class="p">)</span>
</code></pre></div></div>
<p>Update configuration to midnight UTC, which is 7:00 PM (EST):</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">UPDATE</span> <span class="p">[</span><span class="n">dbo</span><span class="p">].[</span><span class="n">dtConfig</span><span class="p">]</span>
<span class="k">SET</span> <span class="p">[</span><span class="n">Value</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1">-- Default: 25200 (2:00 AM (EST))</span>
<span class="k">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span>
<span class="k">GO</span>
</code></pre></div></div>
<p>Be mindful that the scripts are usually run overnight when there is not alot of activity in the ACS Database. So take precautions if changing this when alot of logons/logoffs are happening in your environment.</p>
<hr />
<h2 id="set-filter-for-acs-data">Set filter for ACS Data</h2>
<ol>
<li>On the ACS server, Go to the registry: <code class="language-plaintext highlighter-rouge">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\AdtServer\Parameters</code></li>
<li>Right click the key Parameters, select Permissions</li>
<li>Select the row “Network service”</li>
<li>Click edit</li>
<li>Set “Apply to” as “This key and subkeys”</li>
<li>Select Full control in the column Allow, click OK</li>
<li>Run <strong>CMD</strong> as an <strong>Administrator</strong></li>
<li>Run the below command:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd C:\Windows\System32\Security\AdtServer
</code></pre></div> </div>
</li>
<li>Run the below command to check current query we being used by SCOM ACS. (<em>There should be a no filter clause to exclude the collected event</em>):
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adtadmin –getquery
</code></pre></div> </div>
</li>
<li>Run the following command to add filter for the collected events:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adtadmin /setquery /query:"SELECT * FROM AdtsEvent WHERE NOT (EventID=528 or EventID=540 or EventID=680)”
</code></pre></div> </div>
<blockquote>
<h3 id="note-1">Note</h3>
<p>Change the event IDs to the events you don’t want collected. See the below example for a basic filter. Since every environment has its own concerns, please double check which events can be ignored to reduce data collection amount.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adtadmin /setquery /query:"SELECT * FROM AdtsEvent WHERE NOT (((EventId=528 AND String01='5') OR (EventId=576 AND (String01='SeChangeNotifyPrivilege' OR HeaderDomain='NT Authority')) OR (EventId=538 OR EventId=566 OR EventId=672 OR EventId=680)))"
</code></pre></div> </div>
</blockquote>
</li>
</ol>
<hr />
<h2 id="install-acs-from-command-line">Install ACS from Command Line</h2>
<p>In order to install the ACS Collector from the command line you are required to provide an XML, this an example of the XML that is required:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="utf-8" ?></span>
<span class="nt"><InstallationOptions></span>
<span class="nt"><AcsCollector></span>
<span class="c"><!-- Interval (in seconds) between heartbeats. --></span>
<span class="nt"><HeartBeatInterval></span>60<span class="nt"></HeartBeatInterval></span>
<span class="c"><!-- Number of failed heart beats before collector
disconnects the forwarder. --></span>
<span class="nt"><HeartBeatFailedCount></span>3<span class="nt"></HeartBeatFailedCount></span>
<span class="c"><!-- Time (in seconds) to wait before disconnecting forwarders
which have not yet sent the initial data packet on a
new connection. --></span>
<span class="nt"><ConnectNoDataThreshold></span>10<span class="nt"></ConnectNoDataThreshold></span>
<span class="c"><!-- The TCP port on which the collector should listen
for forwarder connections. --></span>
<span class="nt"><AdtAgentPort></span>51909<span class="nt"></AdtAgentPort></span>
<span class="c"><!-- Maximum length of database queue. This value will be
rounded up to a power of two if necessary. --></span>
<span class="nt"><MaximumQueueLength></span>0x40000<span class="nt"></MaximumQueueLength></span>
<span class="c"><!-- Lower bound (in seconds) of randomly chosen backoff
time sent to agent if the collector is overloaded. --></span>
<span class="nt"><BackOffMinTime></span>120<span class="nt"></BackOffMinTime></span>
<span class="c"><!-- Upper bound (in seconds) of randomly chosen backoff
time sent to agent if the collector is overloaded. --></span>
<span class="nt"><BackOffMaxTime></span>480<span class="nt"></BackOffMaxTime></span>
<span class="c"><!-- (percentage of max queue length) --></span>
<span class="nt"><BackOffThreshold></span>50<span class="nt"></BackOffThreshold></span>
<span class="c"><!-- (percentage of max queue length) --></span>
<span class="nt"><DisconnectThreshold></span>75<span class="nt"></DisconnectThreshold></span>
<span class="c"><!-- Asset value new agents get assigned.
-1 means they get the value of their group instead. --></span>
<span class="nt"><DefaultAssetValue></span>-1<span class="nt"></DefaultAssetValue></span>
<span class="c"><!-- Group ID of the group new agents get assigned to. --></span>
<span class="nt"><DefaultGroup></span>0<span class="nt"></DefaultGroup></span>
<span class="c"><!-- Number of simultaneous database connections to use
for event insertion. --></span>
<span class="nt"><DbEventConnections></span>8<span class="nt"></DbEventConnections></span>
<span class="c"><!-- Number of simultaneous database connections to use
for string insertion. --></span>
<span class="nt"><DbStringConnections></span>8<span class="nt"></DbStringConnections></span>
<span class="c"><!-- Minimum asset value required in order to report
application log events regarding an agent. --></span>
<span class="nt"><ReportThreshold></span>1<span class="nt"></ReportThreshold></span>
<span class="c"><!-- Minimum asset value required in order to store events
from an agent. --></span>
<span class="nt"><StoreThreshold></span>1<span class="nt"></StoreThreshold></span>
<span class="c"><!-- (seconds) --></span>
<span class="nt"><CheckPointInterval></span>198<span class="nt"></CheckPointInterval></span>
<span class="c"><!-- (seconds) --></span>
<span class="nt"><PurgingInterval></span>198<span class="nt"></PurgingInterval></span>
<span class="c"><!-- If running in grooming mode, the collector only kicks
off a grooming cycle if the database queue has at most
MaxPurgingQueue entries. --></span>
<span class="nt"><MaxPurgingQueue></span>500<span class="nt"></MaxPurgingQueue></span>
<span class="c"><!-- 0 = Event timestamps will be reported in UTC.
1 = Event timestamps will be reported in local time. --></span>
<span class="nt"><ConvertToLocalTime></span>1<span class="nt"></ConvertToLocalTime></span>
<span class="c"><!-- Size (in bytes) of memory to use for caching principal data. --></span>
<span class="nt"><PrincipalCacheSize></span>0x8000<span class="nt"></PrincipalCacheSize></span>
<span class="c"><!-- Size (in bytes) of memory to use for caching string data. --></span>
<span class="nt"><StringCacheSize></span>0x20000<span class="nt"></StringCacheSize></span>
<span class="c"><!-- Time, in seconds, to backoff unwanted agents --></span>
<span class="nt"><BackOffUnwanted></span>21600<span class="nt"></BackOffUnwanted></span>
<span class="c"><!-- Maximum time (in minutes) a connection can exist before it
gets disconnected for rekeying purposes. --></span>
<span class="nt"><TlsRekeyInterval></span>600<span class="nt"></TlsRekeyInterval></span>
<span class="c"><!-- --></span>
<span class="nt"><AcceptSockets></span>4<span class="nt"></AcceptSockets></span>
<span class="c"><!-- Time, in seconds, before a new connection gets
disconnected if the client doesn't send any data --></span>
<span class="nt"><MaxAcceptIdle></span>15<span class="nt"></MaxAcceptIdle></span>
<span class="c"><!-- Time, in seconds, before a connection attempt times out --></span>
<span class="nt"><MaxConnectIdle></span>15<span class="nt"></MaxConnectIdle></span>
<span class="c"><!-- Interval (in seconds) between recalculation of queue
statistics. --></span>
<span class="nt"><MinUpdateInterval></span>21<span class="nt"></MinUpdateInterval></span>
<span class="c"><!-- Name of ODBC data source --></span>
<span class="nt"><DataSource></span>acs<span class="nt"></DataSource></span>
<span class="c"><!-- 0 = SQL Server runs on a different machine
1 = SQL Server runs on collector machine --></span>
<span class="nt"><DbServerLocal></span>1<span class="nt"></DbServerLocal></span>
<span class="c"><!-- Name of machine running SQL Server --></span>
<span class="nt"><DbServerName></span>acs-sql<span class="nt"></DbServerName></span>
<span class="c"><!-- Name of SQL Server instance to use. Usually blank. --></span>
<span class="nt"><DbServerInstance></DbServerInstance></span>
<span class="c"><!-- Name of collector database --></span>
<span class="nt"><DbName></span>OperationsManagerAC<span class="nt"></DbName></span>
<span class="c"><!-- 0 = Specified data and log directories will be used.
1 = SQL Server's data and log directories will be used. --></span>
<span class="nt"><UseDefaultPaths></span>1<span class="nt"></UseDefaultPaths></span>
<span class="c"><!-- Path (on DB server) where data file should be created
Necessary only if UseDefaultPaths is set to 0 --></span>
<span class="nt"><DataFilePath></span>d:\acsdata<span class="nt"></DataFilePath></span>
<span class="c"><!-- Initial data file size in MB --></span>
<span class="nt"><DbDataFileInitialSize></span>1024<span class="nt"></DbDataFileInitialSize></span>
<span class="c"><!-- Maximum data file size in MB, 0 means unlimited --></span>
<span class="nt"><DbDataFileMaximumSize></span>65536<span class="nt"></DbDataFileMaximumSize></span>
<span class="c"><!-- File growth amount in MB --></span>
<span class="nt"><DbDataFileIncrementSize></span>1024<span class="nt"></DbDataFileIncrementSize></span>
<span class="c"><!-- Path (on DB server) where log file should be created.
Necessary only if UseDefaultPaths is set to 0 --></span>
<span class="nt"><LogFilePath></span>e:\acslog<span class="nt"></LogFilePath></span>
<span class="c"><!-- Initial log file size in MB --></span>
<span class="nt"><DbLogFileInitialSize></span>128<span class="nt"></DbLogFileInitialSize></span>
<span class="c"><!-- Maximum log file size in MB, 0 means unlimited --></span>
<span class="nt"><DbLogFileMaximumSize></span>4096<span class="nt"></DbLogFileMaximumSize></span>
<span class="c"><!-- File growth amount in MB --></span>
<span class="nt"><DbLogFileIncrementSize></span>128<span class="nt"></DbLogFileIncrementSize></span>
<span class="c"><!-- (hours) time to keep events --></span>
<span class="nt"><EventRetentionPeriod></span>24<span class="nt"></EventRetentionPeriod></span>
<span class="c"><!-- Number of partitions to use --></span>
<span class="nt"><PartitionCount></span>1<span class="nt"></PartitionCount></span>
<span class="c"><!-- Time when partition switching should occur.
Expressed in seconds since midnight in UTC --></span>
<span class="nt"><PartitionSwitchOffset></span>0<span class="nt"></PartitionSwitchOffset></span>
<span class="c"><!-- Type of authentication collector should use
when connecting to the database:
0 = Use SQL authentication (not recommended)
1 = Use Windows authentication (recommended) --></span>
<span class="nt"><UseWindowsAuth></span>1<span class="nt"></UseWindowsAuth></span>
<span class="c"><!-- only necessary when using SQL authentication --></span>
<span class="nt"><DbUser></span>SampleAdtServerDbUser<span class="nt"></DbUser></span>
<span class="c"><!-- only necessary when using SQL authentication --></span>
<span class="nt"><DbPassword></span>SampleAdtServerDbPwd<span class="nt"></DbPassword></span>
<span class="nt"></AcsCollector></span>
<span class="nt"></InstallationOptions></span>
</code></pre></div></div>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/acs-collector-troubleshooting-tips/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 24, 2022
https://blakedrumm.com/blog/acs-collector-troubleshooting-tips/
https://blakedrumm.com/blog/acs-collector-troubleshooting-tips/Maintenance Schedule Failing Intermittently/assets/img/posts/maintenance-mode-schedule.png<p>The customer had setup Maintenance Scheduled Jobs that were to run Daily against a group of servers. This Maintenance Schedule would work as intended for a while (up to a week), but would stop working intermittently. The “Next Run” date/time for the Maintenance Mode Scheduled Job would be empty and to fix this we would need to change, “The schedule is effective beginning” date, to today. Or recreate the maintenance schedule job.</p>
<p><img src="/assets/img/posts/maintenance-mode-schedule-properties.png" alt="Maintenance Mode Scheduled Job Properties" class="img-fluid" /></p>
<p><strong>In order to resolve this issue we had to run the SCOM Console as the SDK (System Center Data Access Service) Account and recreate the Maintenance Scheduled Jobs. This allowed the Maintenance Mode Scheduled jobs to run without any issues.</strong></p>
<h2 id="conclusion">Conclusion</h2>
<p>So the issue was due to the users’ personal Active Directory account being locked out when setting up the Maintenance Schedule. To resolve we just need to run as the Data Access Service (SDK) Account.</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/maintenance-mode-scheduled-jobs-failing-intermittently/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 11, 2022
https://blakedrumm.com/blog/maintenance-mode-scheduled-jobs-failing-intermittently/
https://blakedrumm.com/blog/maintenance-mode-scheduled-jobs-failing-intermittently/Resolve Post Install error with Unix / Linux Install for SCOM Agent/assets/img/posts/scx-agent-list.png<h2 id="introduction">Introduction</h2>
<p>My customer was running Solaris 10 (SunOS 5.10), they were having issues when attempting to install the SCOM Agent (scx-1.6.8-1.solaris.10.sparc.sh). So we dug further into things to verify why the installer was failing on the <strong>PostInstall</strong> step.</p>
<p>Discovery error is shown when attempting to discover from the SCOM Console via the Discovery Wizard:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Task invocation failed with error code -2130771918. Error message was: The SCXCertWriteAction module encountered a DoProcess exception. The workflow "Microsoft.Unix.Agent.GetCert.Task" has been unloaded.
Module: SCXCertWriteAction
Location: DoProcess
Exception type: ScxCertLibException
Exception message: Unable to create certificate context
; {ASN1 bad tag value met.
}
Additional data: Sudo path: /etc/opt/microsoft/scx/conf/sudodir/
Management group: SCOM2019
Workflow name: Microsoft.Unix.Agent.GetCert.Task
Object name: UNIX/Linux Resource Pool
Object ID: {6F1686BA-C068-4C9F-F1ED-29CDD800528A}
</code></pre></div></div>
<h2 id="what-we-did">What we did</h2>
<p>I asked the customer to copy the SCOM Linux / Unix Agent install files (<code class="language-plaintext highlighter-rouge">C:\Program Files\Microsoft System Center\Operations Manager\Server\AgentManagement\UnixAgents\DownloadedKits</code>) to the Solaris Machine so we can attempt a manual installation.</p>
<p>Extract the Solaris Installer file:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sh scx-1.6.8-1.solaris.10.sparc.sh <span class="nt">--extract</span>
</code></pre></div></div>
<p>We looked at the output after running the install manually:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>solaris10:root@/home/ops_monitoring/scxbundle.24766] pkgadd <span class="nt">-d</span> scx-1.6.8-1.solaris.10.sparc.pkg
The following packages are available:
1 MSFTscx Microsoft System Center 2012 Operations Manager <span class="k">for </span>UNIX/Linux agent
<span class="o">(</span>sparc<span class="o">)</span> 1.6.8-1
Select package<span class="o">(</span>s<span class="o">)</span> you wish to process <span class="o">(</span>or <span class="s1">'all'</span> to process
all packages<span class="o">)</span><span class="nb">.</span> <span class="o">(</span>default: all<span class="o">)</span> <span class="o">[</span>?,??,q]:
Processing package instance <MSFTscx> from </home/ops_monitoring/scxbundle.24766/scx-1.6.8-1.solaris.10.sparc.pkg>
Microsoft System Center 2012 Operations Manager <span class="k">for </span>UNIX/Linux agent<span class="o">(</span>sparc<span class="o">)</span> 1.6.8-1
http://www.microsoft.com
<span class="c">## Processing package information.</span>
<span class="c">## Processing system information.</span>
<span class="c">## Verifying package dependencies.</span>
<span class="c">## Verifying disk space requirements.</span>
<span class="c">## Checking for conflicts with packages already installed.</span>
<span class="c">## Checking for setuid/setgid programs.</span>
This package contains scripts which will be executed with super-user
permission during the process of installing this package.
Do you want to <span class="k">continue </span>with the installation of <MSFTscx> <span class="o">[</span>y,n,?] y
Installing Microsoft System Center 2012 Operations Manager <span class="k">for </span>UNIX/Linux agent as <MSFTscx>
<span class="c">## Executing preinstall script.</span>
Waiting <span class="k">for </span>service stop: svc:/application/management/omid ...
<span class="c">## Installing part 1 of 1.</span>
/etc/opt/microsoft/scx/pf_file.sh
/etc/opt/omi/conf/omiregister/root-scx/SCXProvider-omi.reg
/etc/opt/omi/conf/omiregister/root-scx/SCXProvider-req.reg
/etc/opt/omi/conf/omiregister/root-scx/SCXProvider-root.reg
/opt/microsoft/scx/bin/omi_preexec
/opt/microsoft/scx/bin/scxlogfilereader
/opt/microsoft/scx/bin/setup.sh
/opt/microsoft/scx/bin/tools/.scxadmin
/opt/microsoft/scx/bin/tools/.scxsslconfig
/opt/microsoft/scx/bin/tools/scxadmin
/opt/microsoft/scx/bin/tools/scxsslconfig
/opt/microsoft/scx/bin/tools/setup.sh
/opt/microsoft/scx/bin/uninstall
/opt/microsoft/scx/lib/libSCXCoreProviderModule.so
/opt/omi/lib/libSCXCoreProviderModule.so <symbolic <span class="nb">link</span><span class="o">></span>
<span class="o">[</span> verifying class <none> <span class="o">]</span>
/etc/opt/microsoft/scx/conf/installinfo.txt
/etc/opt/microsoft/scx/conf/scxconfig.conf
/etc/opt/microsoft/scx/conf/scxlog.conf
/etc/opt/microsoft/scx/conf/scxrunas.conf
<span class="o">[</span> verifying class <config> <span class="o">]</span>
<span class="c">## Executing postinstall script.</span>
/var/sadm/pkg/MSFTscx/install/postinstall: <span class="nv">ENV</span><span class="o">=</span>/usr/sislocal/profile: is not an identifier
pkgadd: ERROR: postinstall script did not <span class="nb">complete </span>successfully
Installation of <MSFTscx> failed.
</code></pre></div></div>
<p>The piece of the message above that stood out to me was this line:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/var/sadm/pkg/MSFTscx/install/postinstall: <span class="nv">ENV</span><span class="o">=</span>/usr/sislocal/profile: is not an identifier
</code></pre></div></div>
<p>I asked the customer to take a look at their Environmental Variables in <code class="language-plaintext highlighter-rouge">/etc/profile</code> and verify if there are any custom lines in there. We noticed there were custom lines, <strong>we removed these lines and attempted the installation again, it succeeded!</strong></p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/error-postinstall-linux-unix-agent/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 10, 2022
https://blakedrumm.com/blog/error-postinstall-linux-unix-agent/
https://blakedrumm.com/blog/error-postinstall-linux-unix-agent/Set and Check User Rights Assignment via PowerShell/assets/img/posts/set-user-rights.png<p><sub>This post was last updated on November 5th, 2024</sub></p>
<p>I stumbled across this gem (<a href="https://github.com/weloytty/QuirkyPSFunctions/blob/master/Source/Users/Grant-LogOnAsService.ps1">weloytty/Grant-LogonAsService.ps1</a>) that allows you to grant Logon as a Service Right for a User. I modified the script you can now run the Powershell script against multiple machines, users, and user rights.</p>
<h2 id="set-user-rights">Set User Rights</h2>
<h3 id="arrow_down-how-to-get-it">:arrow_down: How to get it</h3>
<p><a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/General%20Functions/Set-UserRights.ps1">Set-UserRights.ps1</a> :arrow_left: <strong>Direct Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Set-UserRights.ps1">Personal File Server - Set-UserRights.ps1</a> :arrow_left: <strong>Alternative Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Set-UserRights.txt">Personal File Server - Set-UserRights.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></p>
<p>All of the User Rights that can be set:</p>
<table class="table table-hover table-text d-block overflow-auto">
<thead>
<tr>
<th>Privilege</th>
<th>PrivilegeName</th>
</tr>
</thead>
<tbody>
<tr>
<td>SeAssignPrimaryTokenPrivilege</td>
<td>Replace a process level token</td>
</tr>
<tr>
<td>SeAuditPrivilege</td>
<td>Generate security audits</td>
</tr>
<tr>
<td>SeBackupPrivilege</td>
<td>Back up files and directories</td>
</tr>
<tr>
<td>SeBatchLogonRight</td>
<td>Log on as a batch job</td>
</tr>
<tr>
<td>SeChangeNotifyPrivilege</td>
<td>Bypass traverse checking</td>
</tr>
<tr>
<td>SeCreateGlobalPrivilege</td>
<td>Create global objects</td>
</tr>
<tr>
<td>SeCreatePagefilePrivilege</td>
<td>Create a pagefile</td>
</tr>
<tr>
<td>SeCreatePermanentPrivilege</td>
<td>Create permanent shared objects</td>
</tr>
<tr>
<td>SeCreateSymbolicLinkPrivilege</td>
<td>Create symbolic links</td>
</tr>
<tr>
<td>SeCreateTokenPrivilege</td>
<td>Create a token object</td>
</tr>
<tr>
<td>SeDebugPrivilege</td>
<td>Debug programs</td>
</tr>
<tr>
<td>SeDelegateSessionUserImpersonatePrivilege</td>
<td>Obtain an impersonation token for another user in the same session</td>
</tr>
<tr>
<td>SeDenyBatchLogonRight</td>
<td>Deny log on as a batch job</td>
</tr>
<tr>
<td>SeDenyInteractiveLogonRight</td>
<td>Deny log on locally</td>
</tr>
<tr>
<td>SeDenyNetworkLogonRight</td>
<td>Deny access to this computer from the network</td>
</tr>
<tr>
<td>SeDenyRemoteInteractiveLogonRight</td>
<td>Deny log on through Remote Desktop Services</td>
</tr>
<tr>
<td>SeDenyServiceLogonRight</td>
<td>Deny log on as a service</td>
</tr>
<tr>
<td>SeEnableDelegationPrivilege</td>
<td>Enable computer and user accounts to be trusted for delegation</td>
</tr>
<tr>
<td>SeImpersonatePrivilege</td>
<td>Impersonate a client after authentication</td>
</tr>
<tr>
<td>SeIncreaseBasePriorityPrivilege</td>
<td>Increase scheduling priority</td>
</tr>
<tr>
<td>SeIncreaseQuotaPrivilege</td>
<td>Adjust memory quotas for a process</td>
</tr>
<tr>
<td>SeIncreaseWorkingSetPrivilege</td>
<td>Increase a process working set</td>
</tr>
<tr>
<td>SeInteractiveLogonRight</td>
<td>Allow log on locally</td>
</tr>
<tr>
<td>SeLoadDriverPrivilege</td>
<td>Load and unload device drivers</td>
</tr>
<tr>
<td>SeLockMemoryPrivilege</td>
<td>Lock pages in memory</td>
</tr>
<tr>
<td>SeMachineAccountPrivilege</td>
<td>Add workstations to domain</td>
</tr>
<tr>
<td>SeManageVolumePrivilege</td>
<td>Perform volume maintenance tasks</td>
</tr>
<tr>
<td>SeNetworkLogonRight</td>
<td>Access this computer from the network</td>
</tr>
<tr>
<td>SeProfileSingleProcessPrivilege</td>
<td>Profile single process</td>
</tr>
<tr>
<td>SeRelabelPrivilege</td>
<td>Modify an object label</td>
</tr>
<tr>
<td>SeRemoteInteractiveLogonRight</td>
<td>Allow log on through Remote Desktop Services</td>
</tr>
<tr>
<td>SeRemoteShutdownPrivilege</td>
<td>Force shutdown from a remote system</td>
</tr>
<tr>
<td>SeRestorePrivilege</td>
<td>Restore files and directories</td>
</tr>
<tr>
<td>SeSecurityPrivilege</td>
<td>Manage auditing and security log</td>
</tr>
<tr>
<td>SeServiceLogonRight</td>
<td>Log on as a service</td>
</tr>
<tr>
<td>SeShutdownPrivilege</td>
<td>Shut down the system</td>
</tr>
<tr>
<td>SeSyncAgentPrivilege</td>
<td>Synchronize directory service data</td>
</tr>
<tr>
<td>SeSystemEnvironmentPrivilege</td>
<td>Modify firmware environment values</td>
</tr>
<tr>
<td>SeSystemProfilePrivilege</td>
<td>Profile system performance</td>
</tr>
<tr>
<td>SeSystemtimePrivilege</td>
<td>Change the system time</td>
</tr>
<tr>
<td>SeTakeOwnershipPrivilege</td>
<td>Take ownership of files or other objects</td>
</tr>
<tr>
<td>SeTcbPrivilege</td>
<td>Act as part of the operating system</td>
</tr>
<tr>
<td>SeTimeZonePrivilege</td>
<td>Change the time zone</td>
</tr>
<tr>
<td>SeTrustedCredManAccessPrivilege</td>
<td>Access Credential Manager as a trusted caller</td>
</tr>
<tr>
<td>SeUndockPrivilege</td>
<td>Remove computer from docking station</td>
</tr>
</tbody>
</table>
<p> </p>
<blockquote>
<h2 id="notebook-note">:notebook: Note</h2>
<p>You may edit line <a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/General%20Functions/Set-UserRights.ps1#L564">564</a> in the script to change what happens when the script is run without any arguments or parameters, this also allows you to change what happens when the script is run from the PowerShell ISE.</p>
</blockquote>
<p>Here are a few examples:</p>
<blockquote>
<h2 id="add-users">Add Users</h2>
<h3 id="single-users">Single Users</h3>
<h4 id="example-1">Example 1</h4>
<p>Add User Right “Allow log on locally” for current user:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-AddRight</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeInteractiveLogonRight</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-2">Example 2</h4>
<p>Add User Right “Log on as a service” for CONTOSO\User:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-AddRight</span><span class="w"> </span><span class="nt">-Username</span><span class="w"> </span><span class="nx">CONTOSO\User</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeServiceLogonRight</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-3">Example 3</h4>
<p>Add User Right “Log on as a batch job” for CONTOSO\User:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-AddRight</span><span class="w"> </span><span class="nt">-Username</span><span class="w"> </span><span class="nx">CONTOSO\User</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeBatchLogonRight</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-4">Example 4</h4>
<p>Add User Right “Log on as a batch job” for user SID S-1-5-11:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-AddRight</span><span class="w"> </span><span class="nt">-Username</span><span class="w"> </span><span class="nx">S-1-5-11</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeBatchLogonRight</span><span class="w">
</span></code></pre></div> </div>
<h3 id="add-multiple-users--rights--computers">Add Multiple Users / Rights / Computers</h3>
<h4 id="example-5">Example 5</h4>
<p>Add User Right “Log on as a service” and “Log on as a batch job” for CONTOSO\User1 and CONTOSO\User2 and run on, local machine and SQL.contoso.com:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-AddRight</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeServiceLogonRight</span><span class="p">,</span><span class="w"> </span><span class="nx">SeBatchLogonRight</span><span class="w"> </span><span class="nt">-ComputerName</span><span class="w"> </span><span class="s2">"</span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">COMPUTERNAME</span><span class="s2">"</span><span class="p">,</span><span class="w"> </span><span class="s2">"SQL.contoso.com"</span><span class="w"> </span><span class="nt">-UserName</span><span class="w"> </span><span class="s2">"CONTOSO\User1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"CONTOSO\User2"</span><span class="w">
</span></code></pre></div> </div>
</blockquote>
<p> </p>
<blockquote>
<h2 id="remove-users">Remove Users</h2>
<h3 id="single-users-1">Single Users</h3>
<h4 id="example-1-1">Example 1</h4>
<p>Remove User Right “Allow log on locally” for current user:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-RemoveRight</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeInteractiveLogonRight</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-2-1">Example 2</h4>
<p>Remove User Right “Log on as a service” for CONTOSO\User:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-RemoveRight</span><span class="w"> </span><span class="nt">-Username</span><span class="w"> </span><span class="nx">CONTOSO\User</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeServiceLogonRight</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-3-1">Example 3</h4>
<p>Remove User Right “Log on as a batch job” for CONTOSO\User:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-RemoveRight</span><span class="w"> </span><span class="nt">-Username</span><span class="w"> </span><span class="nx">CONTOSO\User</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeBatchLogonRight</span><span class="w">
</span></code></pre></div> </div>
<h4 id="example-4-1">Example 4</h4>
<p>Remove User Right “Log on as a batch job” for user SID S-1-5-11:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-RemoveRight</span><span class="w"> </span><span class="nt">-Username</span><span class="w"> </span><span class="nx">S-1-5-11</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeBatchLogonRight</span><span class="w">
</span></code></pre></div> </div>
<h3 id="remove-multiple-users--rights--computers">Remove Multiple Users / Rights / Computers</h3>
<h4 id="example-5-1">Example 5</h4>
<p>Remove User Right “Log on as a service” and “Log on as a batch job” for CONTOSO\User1 and CONTOSO\User2 and run on, local machine and SQL.contoso.com:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Set-UserRights.ps1</span><span class="w"> </span><span class="nt">-RemoveRight</span><span class="w"> </span><span class="nt">-UserRight</span><span class="w"> </span><span class="nx">SeServiceLogonRight</span><span class="p">,</span><span class="w"> </span><span class="nx">SeBatchLogonRight</span><span class="w"> </span><span class="nt">-ComputerName</span><span class="w"> </span><span class="s2">"</span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">COMPUTERNAME</span><span class="s2">"</span><span class="p">,</span><span class="w"> </span><span class="s2">"SQL.contoso.com"</span><span class="w"> </span><span class="nt">-UserName</span><span class="w"> </span><span class="s2">"CONTOSO\User1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"CONTOSO\User2"</span><span class="w">
</span></code></pre></div> </div>
</blockquote>
<hr />
<h2 id="check-user-rights">Check User Rights</h2>
<h3 id="arrow_down-how-to-get-it-1">:arrow_down: How to get it</h3>
<p><a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/General%20Functions/Get-UserRights.ps1">Get-UserRights.ps1</a> :arrow_left: <strong>Direct Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Get-UserRights.ps1">Personal File Server - Get-UserRights.ps1</a> :arrow_left: <strong>Alternative Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Get-UserRights.txt">Personal File Server - Get-UserRights.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></p>
<p>In order to check the Local User Rights, you will need to run the above (Get-UserRights), you may copy and paste the above script in your PowerShell ISE and press play.</p>
<p><img src="/assets/img/posts/get-user-right.png" alt="UserAccountsRights" class="img-fluid" /></p>
<blockquote>
<h2 id="note">Note</h2>
<p>You may edit line <a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/General%20Functions/Get-UserRights.ps1#L493">493</a> in the script to change what happens when the script is run without any arguments or parameters, this also allows you to change what happens when the script is run from the PowerShell ISE.</p>
</blockquote>
<p>Here are a few examples:</p>
<h3 id="local-computer">Local Computer</h3>
<p>Get Local User Account Rights and output to text in console:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w">
</span><span class="c"># or</span><span class="w">
</span><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w"> </span><span class="nt">-UserName</span><span class="w"> </span><span class="nx">DOMAIN\Username</span><span class="w">
</span></code></pre></div></div>
<h3 id="remote-computer">Remote Computer</h3>
<p>Get Remote SQL Server User Account Rights:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w"> </span><span class="nt">-ComputerName</span><span class="w"> </span><span class="nx">SQL.contoso.com</span><span class="w">
</span></code></pre></div></div>
<p>Get Local Machine and SQL Server User Account Rights:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w"> </span><span class="nt">-ComputerName</span><span class="w"> </span><span class="s2">"</span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">COMPUTERNAME</span><span class="s2">"</span><span class="p">,</span><span class="w"> </span><span class="s2">"SQL.contoso.com"</span><span class="w">
</span></code></pre></div></div>
<h3 id="output-types">Output Types</h3>
<p>Output Local User Rights on Local Machine as CSV in ‘C:\Temp’:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w"> </span><span class="nt">-FileOutputPath</span><span class="w"> </span><span class="nx">C:\Temp</span><span class="w"> </span><span class="nt">-FileOutputType</span><span class="w"> </span><span class="nx">CSV</span><span class="w">
</span></code></pre></div></div>
<p>Output to Text in ‘C:\Temp’:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w"> </span><span class="nt">-FileOutputPath</span><span class="w"> </span><span class="nx">C:\Temp</span><span class="w"> </span><span class="nt">-FileOutputType</span><span class="w"> </span><span class="nx">Text</span><span class="w">
</span><span class="c"># or</span><span class="w">
</span><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w"> </span><span class="nt">-FileOutputPath</span><span class="w"> </span><span class="nx">C:\Temp</span><span class="w">
</span></code></pre></div></div>
<p>PassThru object to allow manipulation / filtering:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w"> </span><span class="nt">-ComputerName</span><span class="w"> </span><span class="nx">SQL.contoso.com</span><span class="w"> </span><span class="nt">-UserName</span><span class="w"> </span><span class="nx">DOMAIN\SQLUser</span><span class="w"> </span><span class="nt">-PassThru</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Privilege</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="s1">'SeInteractiveLogonRight'</span><span class="p">}</span><span class="w">
</span><span class="c"># or</span><span class="w">
</span><span class="o">.</span><span class="n">\Get-UserRights.ps1</span><span class="w"> </span><span class="nt">-PassThru</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Privilege</span><span class="w"> </span><span class="o">-match</span><span class="w"> </span><span class="s1">'SeServiceLogonRight'</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Leave some feedback if this helped you! :v:</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/set-and-check-user-rights-assignment/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
January 5, 2022
https://blakedrumm.com/blog/set-and-check-user-rights-assignment/
https://blakedrumm.com/blog/set-and-check-user-rights-assignment/Create your own offline Certificate Request for SCOM Off-Domain Server/assets/img/posts/local-machine-certificate.png<p>In the below example we are assuming your machine is named <strong>IIS-2019</strong>.</p>
<p>Create a new file on your machine and name it:</p>
<blockquote>
<p>IIS-2019-CertReq.inf</p>
</blockquote>
<p>Edit the file to include something similar to the following (<strong>NOTE: Be aware Operations Manager only uses the first CN name in the Subject</strong>):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[NewRequest]
Subject="CN=IIS-2019.contoso.com,OU=Servers,O=Support Team,L=Charlotte,S=North Carolina,C=US"
Exportable=TRUE ; Private key is exportable - Required for Server Authentication
KeyLength=2048
KeySpec=1 ; Key Exchange – Required for encryption
KeyUsage=0xf0 ; Digital Signature, Key Encipherment
MachineKeySet=TRUE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
KeyAlgorithm = RSA
; Optionally include the Certificate Template
; [RequestAttributes]
; CertificateTemplate="SystemCenterOperationsManager"
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.1 ; Server Authentication
OID=1.3.6.1.5.5.7.3.2 ; Client Authentication
</code></pre></div></div>
<p>Open an Administrator Command Prompt and navigate to where you saved the above file. <br />
Run the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Certreq -New -f IIS-2019-CertReq.inf IIS-2019-CertRequest.req
</code></pre></div></div>
<blockquote>
<h3 id="notebook-note">:notebook: Note</h3>
<p>The server where you run the above <code class="language-plaintext highlighter-rouge">Certreq</code> command will be where the Certificate Private Key will be stored.</p>
</blockquote>
<p>Upload the above (IIS-2019-CertRequest.req) file to your Certificate Authority. <br />
… <br />
Once you receive back your signed certificate, import the Certificate into the Local Computer Personal Certificate Store:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certlm.msc
</code></pre></div></div>
<ul>
<li>Run this Powershell script to check the certificate you imported: <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Test-SCOMCertificate.ps1">https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Test-SCOMCertificate.ps1</a> <br />
<br />
Run it like this:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.\Test-SCOMCertificate.ps1 -All
</code></pre></div> </div>
<p>You can also copy/paste the script to an Powershell ISE (Running as Administrator), you just need to edit line <a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Test-SCOMCertificate.ps1#L770">770</a> to include the arguments you want to run.</p>
</li>
</ul>
<hr />
<p>On a side note. If you run the SCOM Certificate Checker script above and it shows an output that looks like this: <br />
<img src="/assets/img/posts/scom-cert-checker-missingkey.png" alt="Certificate Checker Script Missing Private Key" class="img-fluid" /></p>
<p>You may also notice that the Private Key for the Certificate is missing: <br />
<img src="/assets/img/posts/certificate-private-key-notpresent.png" alt="Certificate Private Key Missing" class="img-fluid" /></p>
<p>It is possible you may need to run the following command in an Administrator Command Prompt to restore the Keyspec and Private Key (replace the numbers & letters after <strong>my</strong> with the serial number of your Certificate):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certutil -repairstore my 1f00000008c694dac94bcfdc4a000000000008
</code></pre></div></div>
<p><img src="/assets/img/posts/certutil-output.png" alt="certutil Repair Store - Command Output" class="img-fluid" /></p>
<p>After you run the <code class="language-plaintext highlighter-rouge">certutil</code> command above, you will notice the Certificate is now showing a Private Key (notice the key icon): <br />
<img src="/assets/img/posts/certificate-private-key-present.png" alt="Certificate Private Key Present" class="img-fluid" /></p>
<p>You should now see this when you run the SCOM Certificate Checker Powershell Script: <br />
<img src="/assets/img/posts/scom-cert-checker-successful.png" alt="Certificate Checker Script Successful" class="img-fluid" /></p>
<p>Now you just need to import the Certificate with MOMCertImport (located on the SCOM Installation Media): <br />
<img src="/assets/img/posts/momcertimport-file.png" alt="MOMCertImport Location" class="img-fluid" /></p>
<p>Right Click and Run the Program as Administrator, select the certificate you imported: <br />
<img src="/assets/img/posts/momcertimport-certificate.png" alt="Confirm Certificate in MOMCertImport" class="img-fluid" /></p>
<p>Lastly, you will need to restart the Microsoft Monitoring Agent (HealthService). You can do this via Powershell with this command:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Restart-Service</span><span class="w"> </span><span class="nx">HealthService</span><span class="w">
</span></code></pre></div></div>
<p>After restarting the Microsoft Monitoring Agent (HealthService). You will wait until you see the following Event ID in the Operations Manager Event Log (20053) confirming that the certificate has been loaded:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Log Name: Operations Manager
Source: OpsMgr Connector
Date: 2/28/2022 10:35:36 AM
Event ID: 20053
Task Category: None
Level: Information
Keywords: Classic
User: N/A
Computer: MS02-2019.contoso.com
Description:
The OpsMgr Connector has loaded the specified authentication certificate successfully.
</code></pre></div></div>
<blockquote>
<p><strong>Don’t forget the Management Server</strong> <br />
The Management Server also needs to have a certificate requested for itself, and imported into the Personal Store in the Local Machine Certificates. You also need to run MOMCertImport.exe on the Management Server for the Management Server certificate. Otherwise the communication between the Management Server and the Agent or Gateway Server will not work via certificates.</p>
</blockquote>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/request-offline-certificate-for-off-domain-server/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
December 29, 2021
https://blakedrumm.com/blog/request-offline-certificate-for-off-domain-server/
https://blakedrumm.com/blog/request-offline-certificate-for-off-domain-server/Resolve Operations Manager Event ID 33333/assets/img/posts/event-33333.png<h2 id="book-introduction">:book: Introduction</h2>
<p>I had a case recently where my customer was having issues with the following Event ID 33333 on all the Management Servers in the Management Group.</p>
<p>This is the Exact Event Information:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Log Name: Operations Manager
Source: DataAccessLayer
Date: 7/7/2021 2:19:52 PM
Event ID: 33333
Task Category: None
Level: Warning
Keywords: Classic
User: N/A
Computer: ManagementServer1.contoso.com
Description:
Data Access Layer rejected retry on SqlError:
Request: p_StateChangeEventProcess -- (BaseManagedEntityId=2ee6ce9a-6ec1-4a16-335b-700136600z60), (EventOriginId=b48055d3-18f2-40f7-a0e7-a0f8bd1b44a3), (MonitorId=f1baeb56-8cce-f8c7-79ae-d69796c9d926), (NewHealthState=3), (OldHealthState=1), (TimeGenerated=7/7/2021 6:19:43 PM), (Context=), (RETURN_VALUE=0)
Class: 14
Number: 2627
Message: Violation of PRIMARY KEY constraint 'PK_StateChangeEvent'. Cannot insert duplicate key in object 'dbo.StateChangeEvent'. The duplicate key value is (b48055d3-18f2-40f7-a0e7-a0f8bd1b44a3).
</code></pre></div></div>
<h2 id="page_with_curl-how-to-fix">:page_with_curl: How to fix</h2>
<p>This Powershell Script will allow you to detect for Event ID 33333 being generated and get a count of unique Servers referenced across your OperationsManager Event Log:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$events</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">Get-EventLog</span><span class="w"> </span><span class="nt">-LogName</span><span class="w"> </span><span class="s1">'Operations Manager'</span><span class="w"> </span><span class="nt">-Source</span><span class="w"> </span><span class="s1">'DataAccessLayer'</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">SilentlyContinue</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">EventID</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="mi">33333</span><span class="w"> </span><span class="p">})</span><span class="w">
</span><span class="c"># If Event 33333 found in the OperationsManager Event Log, do the below</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">((</span><span class="nv">$events</span><span class="o">.</span><span class="nf">Message</span><span class="w"> </span><span class="o">-like</span><span class="w"> </span><span class="s2">"*Violation of PRIMARY KEY constraint 'PK_StateChangeEvent'. Cannot insert duplicate key in object 'dbo.StateChangeEvent'. The duplicate key value is*"</span><span class="p">)</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="p">(</span><span class="nv">$events</span><span class="o">.</span><span class="nf">Message</span><span class="w"> </span><span class="o">-like</span><span class="w"> </span><span class="s2">"*f1baeb56-8cce-f8c7-79ae-d69796c9d926*"</span><span class="p">))</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nv">$message</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$events</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">%</span><span class="p">{</span><span class="w"> </span><span class="p">(</span><span class="bp">$_</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nt">-Property</span><span class="w"> </span><span class="nx">Message</span><span class="w"> </span><span class="nt">-ExpandProperty</span><span class="w"> </span><span class="nx">Message</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="nv">$matches</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$message</span><span class="w"> </span><span class="o">-split</span><span class="w"> </span><span class="s2">","</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">select-string</span><span class="w"> </span><span class="s2">"MonitorId=(.*)"</span><span class="w">
</span><span class="nv">$match</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$matches</span><span class="o">.</span><span class="nf">matches</span><span class="o">.</span><span class="n">groups</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="nf">value</span><span class="o">.</span><span class="nf">TrimEnd</span><span class="p">(</span><span class="s2">")"</span><span class="p">)</span><span class="w">
</span><span class="nv">$i</span><span class="o">++</span><span class="w">
</span><span class="nv">$i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$i</span><span class="w">
</span><span class="s2">"Found </span><span class="si">$(</span><span class="nv">$message</span><span class="o">.</span><span class="nf">count</span><span class="si">)</span><span class="s2"> issues with the Event ID 33333 (Monitor Id: </span><span class="nv">$match</span><span class="s2">), see the following article:</span><span class="se">`n</span><span class="s2"> https://kevinholman.com/2017/05/29/stop-healthservice-restarts-in-scom-2016/"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Run the above script on each of your Management Servers in your Management Group.</p>
<p>I found that this correlates to this article written by Kevin Holman:
<a href="https://kevinholman.com/2017/05/29/stop-healthservice-restarts-in-scom-2016/">https://kevinholman.com/2017/05/29/stop-healthservice-restarts-in-scom-2016/</a></p>
<p>Following the steps in the article above, will resolve the issues you are having with Event ID: <strong>33333</strong> <code class="language-plaintext highlighter-rouge">Violation of PRIMARY KEY constraint 'PK_StateChangeEvent'. Cannot insert duplicate key in object 'dbo.StateChangeEvent'.</code> .</p>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/resolve-33333-events/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
August 16, 2021
https://blakedrumm.com/blog/resolve-33333-events/
https://blakedrumm.com/blog/resolve-33333-events/SCOM Clear Cache Script/assets/img/posts/clear-scomcache.png<p><sub>Article last updated on April 12th, 2023</sub></p>
<h1 id="arrow_down-how-to-get-it">:arrow_down: How to get it</h1>
<p><a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/blob/master/Powershell/Clear-SCOMCache.ps1">Clear-SCOMCache.ps1</a> :arrow_left: <strong>Direct Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Clear-SCOMCache.ps1">Personal File Server - Clear-SCOMCache.ps1</a> :arrow_left: <strong>Alternative Download Link</strong> <br />
<em>or</em> <br />
<a href="https://files.blakedrumm.com/Clear-SCOMCache.txt">Personal File Server - Clear-SCOMCache.txt</a> :arrow_left: <strong>Text Format Alternative Download Link</strong></p>
<p>The script without any modifications or parameters clears the Operations Manager cache only on the local server, nothing else.</p>
<h2 id="classical_building-argument-list">:classical_building: Argument List</h2>
<table class="table table-hover table-text d-block overflow-auto">
<thead>
<tr>
<th>Parameter</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>-All</td>
<td>Optionally clear all caches that SCOM could potentially use that doesnt require a reboot. Flushing DNS, Purging Kerberos Tickets, Resetting NetBIOS over TCPIP Statistics. (Combine with -Reboot for a full clear cache)</td>
</tr>
<tr>
<td>-Reboot</td>
<td>Optionally reset winsock catalog, stop the SCOM Services, clear SCOM Cache, then reboot the server. This will always perform on the local server last.</td>
</tr>
<tr>
<td>-Servers</td>
<td>Optionally each Server you want to clear SCOM Cache on. Can be an Agent, Management Server, or SCOM Gateway. This will always perform on the local server last.</td>
</tr>
<tr>
<td>-Shutdown</td>
<td>Optionally shutdown the server after clearing the SCOM cache. This will always perform on the local server last.</td>
</tr>
<tr>
<td>-Sleep</td>
<td>Time in seconds to sleep between each server.</td>
</tr>
</tbody>
</table>
<h2 id="question-examples">:question: Examples</h2>
<h3 id="clear-all-gray-scom-agents">Clear all Gray SCOM Agents</h3>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#Get the SystemCenter Agent Class</span><span class="w">
</span><span class="nv">$agent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMClass</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">where-object</span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">name</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="s2">"microsoft.systemcenter.agent"</span><span class="p">}</span><span class="w">
</span><span class="c">#Get the grey agents</span><span class="w">
</span><span class="nv">$objects</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-SCOMMonitoringObject</span><span class="w"> </span><span class="nt">-class</span><span class="p">:</span><span class="nv">$agent</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">where</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">IsAvailable</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="bp">$false</span><span class="p">}</span><span class="w">
</span><span class="o">.</span><span class="n">\Clear-SCOMCache.ps1</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nv">$objects</span><span class="w">
</span></code></pre></div></div>
<h3 id="clear-scom-cache-on-every-management-server-in-management-group">Clear SCOM cache on every Management Server in Management Group</h3>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Get-SCOMManagementServer</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">.</span><span class="n">\Clear-SCOMCache.ps1</span><span class="w">
</span></code></pre></div></div>
<h3 id="clear-scom-cache-on-every-agent-in-the-management-group">Clear SCOM cache on every Agent in the Management Group</h3>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Get-SCOMAgent</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">.</span><span class="n">\Clear-SCOMCache.ps1</span><span class="w">
</span></code></pre></div></div>
<h3 id="clear-scom-cache-and-reboot-the-servers-specified">Clear SCOM cache and reboot the Servers specified</h3>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Clear-SCOMCache.ps1</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">AgentServer.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">ManagementServer.contoso.com</span><span class="w"> </span><span class="nt">-Reboot</span><span class="w">
</span></code></pre></div></div>
<h3 id="clear-scom-cache-and-shutdown-the-servers-specified">Clear SCOM cache and shutdown the Servers specified</h3>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Clear-SCOMCache.ps1</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">AgentServer.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">ManagementServer.contoso.com</span><span class="w"> </span><span class="nt">-Shutdown</span><span class="w">
</span></code></pre></div></div>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/clear-scomcache/" alt="Page Views" /></p>
<!--
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
July 22, 2021
https://blakedrumm.com/blog/clear-scomcache/
https://blakedrumm.com/blog/clear-scomcache/System Center Operations Manager - Data Collector/assets/img/posts/scom-data-collector.png<h2 id="book-introduction">:book: Introduction</h2>
<p>This tool was designed to assist with troubleshooting complex System Center Operations Manager issues.</p>
<h2 id="arrow_down_small-quick-download-link">:arrow_down_small: Quick Download Link</h2>
<p><a href="https://aka.ms/SCOM-DataCollector">https://aka.ms/SCOM-DataCollector</a></p>
<p><a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/releases/latest" class="img-shields-io"><img src="https://img.shields.io/github/v/release/blakedrumm/SCOM-Scripts-and-SQL" alt="Latest Version" /></a> <br />
<a href="https://aka.ms/SCOM-DataCollector" class="img-shields-io"><img src="https://img.shields.io/github/downloads/blakedrumm/SCOM-Scripts-and-SQL/latest/SCOM-DataCollector.zip?style=for-the-badge&color=brightgreen" alt="Download Count Latest" /></a> <br />
<a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/releases" class="img-shields-io"><img src="https://img.shields.io/github/downloads/blakedrumm/SCOM-Scripts-and-SQL/total.svg?style=for-the-badge&color=brightgreen" alt="Download Count Releases" /></a></p>
<h2 id="page_facing_up-personal-webpage">:page_facing_up: Personal Webpage</h2>
<h4 id="data-collector">Data Collector</h4>
<p><a href="https://files.blakedrumm.com/SCOM-DataCollector.zip">https://files.blakedrumm.com/SCOM-DataCollector.zip</a></p>
<h4 id="report-builder">Report Builder</h4>
<p><a href="https://files.blakedrumm.com/ReportBuilder.zip">https://files.blakedrumm.com/ReportBuilder.zip</a></p>
<h2 id="link-github-link">:link: Github Link</h2>
<h4 id="data-collector-1">Data Collector</h4>
<p><a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/releases/latest/download/SCOM-DataCollector.zip">https://github.com/blakedrumm/SCOM-Scripts-and-SQL/releases/latest/download/SCOM-DataCollector.zip</a></p>
<h4 id="report-builder-1">Report Builder</h4>
<p><a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/releases/latest/download/ReportBuilder.zip">https://github.com/blakedrumm/SCOM-Scripts-and-SQL/releases/latest/download/ReportBuilder.zip</a></p>
<h2 id="red_circle-requirements">:red_circle: Requirements</h2>
<ul>
<li>System Center Operations Manager - Management Server</li>
<li>Administrator Privileges</li>
<li>Powershell 4</li>
</ul>
<h2 id="page_with_curl-instructions">:page_with_curl: Instructions</h2>
<p><a href="https://aka.ms/SCOM-DataCollector">Download the zip file</a> and extract zip file to a directory (ex. C:\Data Collector). You have 2 options for running this script.</p>
<ol>
<li>Right Click the SCOM Data Collector script and select Run with Powershell.</li>
<li>Open an Powershell shell <strong>as Adminstrator</strong> and change to the directory the SCOM Data Collector Powershell Script is located, such as:
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cd</span><span class="w"> </span><span class="nx">C:\Data</span><span class="w"> </span><span class="nx">Collector</span><span class="w">
</span><span class="o">.</span><span class="n">\DataCollector-v4.0.0.ps1</span><span class="w">
</span></code></pre></div> </div>
</li>
</ol>
<blockquote>
<h3 id="o-optional">:o: Optional</h3>
<p>You have the ability to run this script as any user you would like when you start the script without any switches. The default is the System Center Data Access Service account.</p>
</blockquote>
<p>Run this script on a Operations Manager Management Server to gather their SQL server names and DB names from the local registry. Otherwise user will need to manually input names. It will attempt to query the SQL Server Instance remotely, and will create CSV output files in the Output folder located in the SCOM Data Collector script directory.The SCOM Data Collector has the ability to query multiple databases in the SCOM SQL Instance (<em>master, OperationsManager, OperationsManagerDW</em>), having a high level of rights to SQL is preferred for a full gather.</p>
<p>After the script has completed you will see that the Output folder that is temporary created during script execution is removed. The Data Collector will automatically create a zip file in the same directory as the SCOM Data Collector Powershell Script named something similar to this: <br />
<code class="language-plaintext highlighter-rouge">SDC_Results_04_04_1975.zip</code></p>
<p>This script has the ability to gather the following information:</p>
<ul>
<li>Data from Management Server(s), Operations Manager SQL Server(s). You can also gather from Servers(s) specified with <code class="language-plaintext highlighter-rouge">-Servers</code>.</li>
<li>Event Logs – Application, System, OperationsManager</li>
<li>SCOM Version Installed</li>
<li>Update Rollup Information for SCOM Upgrades</li>
<li>SQL Queries that collect information about many aspects of your environment (too many queries to go into detail here, here are some of the queries it uses: <a href="https://github.com/blakedrumm/SCOM-Scripts-and-SQL/tree/master/SQL%20Queries">https://github.com/blakedrumm/SCOM-Scripts-and-SQL/tree/master/SQL%20Queries</a>)</li>
<li>Windows Updates installed on Management Servers / SQL Server</li>
<li>Service Principal Name (SPN) Information for SCOM Management Servers</li>
<li>Local Administrators Group on each Management Server and any other servers you specify</li>
<li>Local User Account Rights on each Management Server and any other servers you specify</li>
<li>Database Information / DB Version</li>
<li>SCOM RunAs Account Information</li>
<li>Check TLS 1.2 Readiness</li>
<li>TLS Settings on each Management Server and SQL Server</li>
<li>MSInfo32</li>
<li>Sealed / Unsealed MPs</li>
<li>Clock Synchronization</li>
<li>Latency Check (Ping Test)</li>
<li>Rules / Monitors in your SCOM Environment</li>
<li>Get Run As Accounts from SCOM Management Group</li>
<li>Test SCOM Ports</li>
<li>Best Practice Analyzer to verify you are following SCOM Best Practices <em>(only a few items being checked currently)</em></li>
<li>Gathers Group Policy settings on each Management Server and SQL Server</li>
<li>Gathers installed Software on each Management Server</li>
<li>Management Group Overall Health and verify Configuration matches across Management Servers in Management Group</li>
<li>Check SCOM Certificates for Validity / Usability</li>
<li>SCOM Install / Update Logs</li>
<li>IP Address of each Management Server</li>
<li>Gather SCOM Configuration from registry and configuration file</li>
<li><strong><em>this list is not complete…</em></strong></li>
</ul>
<hr />
<h2 id="question-examples">:question: Examples</h2>
<blockquote>
<h3 id="o-optional-1">:o: Optional</h3>
<p>If you know you have (read) Query rights against the DB(s) and Administrator permissions on the Management Servers, run any Switch (-Command) with -AssumeYes (-Yes). Otherwise you will need to provide an account that has permissions at runtime.</p>
</blockquote>
<h3 id="available-switches">Available Switches</h3>
<p>Every Switch Available:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-All</span><span class="w"> </span><span class="nt">-ManagementServers</span><span class="w"> </span><span class="s2">"<array>"</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="s2">"<array>"</span><span class="w"> </span><span class="nt">-AdditionalEventLogs</span><span class="w"> </span><span class="s2">"<array>"</span><span class="w"> </span><span class="nt">-GetRulesAndMonitors</span><span class="w"> </span><span class="nt">-GetRunAsAccounts</span><span class="w"> </span><span class="nt">-CheckTLS</span><span class="w"> </span><span class="nt">-CheckCertificates</span><span class="w"> </span><span class="nt">-GetEventLogs</span><span class="w"> </span><span class="nt">-ExportMPs</span><span class="w"> </span><span class="nt">-GPResult</span><span class="w"> </span><span class="nt">-SQLLogs</span><span class="w"> </span><span class="nt">-CheckPorts</span><span class="w"> </span><span class="nt">-GetLocalSecurity</span><span class="w"> </span><span class="nt">-GetInstalledSoftware</span><span class="w"> </span><span class="nt">-GetSPN</span><span class="w"> </span><span class="nt">-AssumeYes</span><span class="w"> </span><span class="nt">-GetConfiguration</span><span class="w"> </span><span class="nt">-CheckGroupPolicy</span><span class="w"> </span><span class="nt">-GetInstallLogs</span><span class="w"> </span><span class="nt">-SkipSQLQueries</span><span class="w"> </span><span class="nt">-SQLOnly</span><span class="w"> </span><span class="nt">-SQLOnlyOpsDB</span><span class="w"> </span><span class="nt">-SQLOnlyDW</span><span class="w"> </span><span class="nt">-BuildPipeline</span><span class="w"> </span><span class="nt">-CaseNumber</span><span class="w"> </span><span class="s2">"<string>"</span><span class="w"> </span><span class="nt">-ExportSCXCertificates</span><span class="w"> </span><span class="nt">-ExportMSCertificates</span><span class="w"> </span><span class="nt">-GenerateHTML</span><span class="w"> </span><span class="nt">-GetNotificationSubscriptions</span><span class="w"> </span><span class="nt">-GetUserRoles</span><span class="w"> </span><span class="nt">-LeastAmount</span><span class="w"> </span><span class="nt">-MSInfo32</span><span class="w"> </span><span class="nt">-NoSQLPermission</span><span class="w"> </span><span class="nt">-PingAll</span><span class="w"> </span><span class="nt">-SCXAgents</span><span class="w"> </span><span class="s2">"<array>"</span><span class="w"> </span><span class="nt">-SCXUsername</span><span class="w"> </span><span class="s2">"<string>"</span><span class="w"> </span><span class="nt">-SCXMaintenanceUsername</span><span class="w"> </span><span class="s2">"<string>"</span><span class="w"> </span><span class="nt">-SCXMonitoringUsername</span><span class="w"> </span><span class="s2">"<string>"</span><span class="w"> </span><span class="nt">-SkipBestPracticeAnalyzer</span><span class="w"> </span><span class="nt">-SkipConnectivityTests</span><span class="w"> </span><span class="nt">-SkipGeneralInformation</span><span class="w"> </span><span class="nt">-SQLLogs</span><span class="w">
</span></code></pre></div></div>
<h3 id="all-switches">All Switches</h3>
<p>This will allow you to run every switch available currently:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-All</span><span class="w">
</span><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-All</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">Agent1</span><span class="w">
</span><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-All</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">Agent1</span><span class="p">,</span><span class="w"> </span><span class="nx">Agent2</span><span class="p">,</span><span class="w"> </span><span class="nx">Agent3</span><span class="w">
</span><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-All</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">Agent1</span><span class="w"> </span><span class="nt">-ManagementServer</span><span class="w"> </span><span class="nx">MS01-2019.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">MS02-2019.contoso.com</span><span class="w">
</span><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-All</span><span class="w"> </span><span class="nt">-Yes</span><span class="w">
</span></code></pre></div></div>
<h3 id="built-in-menu">Built in menu</h3>
<p>To see the built in menu, run the script with no arguments or switches:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w">
</span></code></pre></div></div>
<p>You can also right click the <code class="language-plaintext highlighter-rouge">.ps1</code> file and Run with Powershell.</p>
<h3 id="certificates">Certificates</h3>
<p>To Check the Certificate(s) Installed on the Management Server(s) in the Management Group, and an Server:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-CheckCertificates</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">AppServer1.contoso.com</span><span class="w">
</span></code></pre></div></div>
<p>To Check the Certificate(s) Installed on the Management Server(s) in the Management Group:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-CheckCertificates</span><span class="w">
</span></code></pre></div></div>
<h3 id="gather-only-sql-queries">Gather only SQL Queries</h3>
<p>To gather only the SQL Queries run the following:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-SQLOnly</span><span class="w">
</span></code></pre></div></div>
<p>If you know the account running the Data Collector has permissions against the SCOM Databases, run this:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-SQLOnly</span><span class="w"> </span><span class="nt">-Yes</span><span class="w">
</span></code></pre></div></div>
<h3 id="event-logs">Event Logs</h3>
<p>To gather Event Logs from 3 Agents and the Management Server(s) in the Current Management Group:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-GetEventLogs</span><span class="w"> </span><span class="nt">-Servers</span><span class="w"> </span><span class="nx">Agent1.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">Agent2.contoso.com</span><span class="p">,</span><span class="w"> </span><span class="nx">Agent3.contoso.com</span><span class="w">
</span></code></pre></div></div>
<p>To just gather the Event Logs from the Management Server(s) in the Management Group:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-GetEventLogs</span><span class="w">
</span></code></pre></div></div>
<h3 id="management-packs">Management Packs</h3>
<p>To Export Installed Management Packs:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-ExportMPs</span><span class="w">
</span></code></pre></div></div>
<h3 id="runas-accounts">RunAs Accounts</h3>
<p>To Export RunAs Accounts from the Management Server:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-GetRunAsAccounts</span><span class="w">
</span></code></pre></div></div>
<h3 id="check-tls-12-readiness">Check TLS 1.2 Readiness</h3>
<p>To Run the TLS 1.2 Hardening Readiness Checks on every Management Server and SQL SCOM DB Server(s) in the Management Group:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\DataCollector.ps1</span><span class="w"> </span><span class="nt">-CheckTLS</span><span class="w">
</span></code></pre></div></div>
<p><img src="https://counter.blakedrumm.com/count/tag.svg?url=blakedrumm.com/blog/scom-data-collector/" alt="Page Views" /></p>
<!--
## Welcome to GitHub Pages
You can use the [editor on GitHub](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files.
Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files.
### Markdown
Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for
```markdown
Syntax highlighted code block
# Header 1
## Header 2
### Header 3
- Bulleted
- List
1. Numbered
2. List
**Bold** and _Italic_ and `Code` text
[Link](url) and 
```
For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
### Jekyll Themes
Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/blakedrumm/SCOM-Scripts-and-SQL/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file.
### Support or Contact
Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out.
Tip:
To add auto-size pictures:
{:class="img-fluid"}
-->
July 6, 2021
https://blakedrumm.com/blog/scom-data-collector/
https://blakedrumm.com/blog/scom-data-collector/