{"id":7533,"date":"2026-08-12T13:23:59","date_gmt":"2026-08-12T18:23:59","guid":{"rendered":"https:\/\/andreas-wolter.com\/?p=7533"},"modified":"2026-08-12T13:44:22","modified_gmt":"2026-08-12T18:44:22","slug":"2608_get-sqlsafe_communityedition_sqlserver_security_asssessment_at_scale","status":"publish","type":"post","link":"https:\/\/andreas-wolter.com\/en\/2608_get-sqlsafe_communityedition_sqlserver_security_asssessment_at_scale\/","title":{"rendered":"Running Get-SqlSafe at Scale Across a SQL Server Estate"},"content":{"rendered":"\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-m0cxh8ps-60cef0cfb08afc3fb2b1d4879de18a57\">\n#top .av-special-heading.av-m0cxh8ps-60cef0cfb08afc3fb2b1d4879de18a57{\npadding-bottom:10px;\n}\nbody .av-special-heading.av-m0cxh8ps-60cef0cfb08afc3fb2b1d4879de18a57 .av-special-heading-tag .heading-char{\nfont-size:25px;\n}\n.av-special-heading.av-m0cxh8ps-60cef0cfb08afc3fb2b1d4879de18a57 .av-subheading{\nfont-size:15px;\n}\n<\/style>\n<div  class='av-special-heading av-m0cxh8ps-60cef0cfb08afc3fb2b1d4879de18a57 av-special-heading-h3 blockquote modern-quote  avia-builder-el-0  el_before_av_textblock  avia-builder-el-first '><h3 class='av-special-heading-tag'  itemprop=\"headline\"  >Running Get-SqlSafe at Scale Across a SQL Server Estate<\/h3><div class=\"special-heading-border\"><div class=\"special-heading-inner-border\"><\/div><\/div><\/div>\r\n\r\n<section  class='av_textblock_section av-m0cxgkjy-c935304b4106b45214698f40e83a9894 '   itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/BlogPosting\" itemprop=\"blogPost\" ><div class='avia_textblock'  itemprop=\"text\" ><p>Get-SqlSafe is a free SQL Server security assessment that checks for common configuration, access-control, authentication, auditing and generates a detailed HTML report.<\/p>\n<p>It has been publicly available for a couple of months and has already received several valuable additions based on user feedback, including console-only mode, Amazon RDS for SQL Server support, and per-database reports.<\/p>\n<p>It has been encouraging to see Get-SqlSafe being used in real environments, including some very large ones.<\/p>\n<p>In this post, I will show how to run the assessment against dozens or even hundreds of SQL Server instances using only a small additional PowerShell wrapper.<\/p>\n<h2>What Get-SqlSafe provides<\/h2>\n<p>Get-SqlSafe Community Edition is available from <a href=\"https:\/\/sarpedonqualitylab.us\/resources\/\" target=\"_blank\" rel=\"noopener\">Sarpedon Quality Lab<\/a>.<\/p>\n<p>By default, the script opens a graphical logon prompt, which is convenient when assessing a single server. After the assessment finishes, it automatically opens the generated report in your browser. For automation, it also supports a console-only mode, making it suitable for running against a list of SQL Server instances.<\/p>\n<p style=\"padding-left: 40px;\">.\\Get-SqlSafe.ps1 `<br \/>\n-ConsoleOnly `<br \/>\n-SqlInstance &#8216;MYSERVER01&#8217; `<br \/>\n-Auth Windows `<br \/>\n-NoAutoOpenReport<\/p>\n<p>Be sure to include -NoAutoOpenReport; otherwise, every completed assessment will open another browser window.<\/p>\n<h2>Before you run it at scale<\/h2>\n<p>Start with two or three known instances before expanding to a larger list. Confirm that authentication, permissions, connectivity, output naming, and report generation behave as expected in your environment.<\/p>\n<ul>\n<li>Run the assessment only against systems you are authorized to access.<\/li>\n<li>Do not embed credentials in the server list or sample wrapper.<\/li>\n<li>Treat generated reports as sensitive information because they can contain server names, database names, account names, and details about potential security weaknesses.<\/li>\n<li>Expect unavailable servers, authentication failures, and connection timeouts in any sufficiently large estate.<\/li>\n<\/ul>\n<blockquote><p><strong>About the code excerpts: <\/strong>The snippets in this article illustrate individual stages of the approach. They are intentionally not presented as standalone, copy-and-run scripts. The accompanying sample script provides the surrounding variables and additional handling.<\/p><\/blockquote>\n<h2>Start with a simple server list<\/h2>\n<p>For a small number of SQL Server instances, the simplest approach is to run the script sequentially over a text file containing one server or instance name per line. Blank lines and lines beginning with # can be ignored, which makes it easy to annotate the list.<\/p>\n<h3>Excerpt: read and normalize the server list<\/h3>\n<p style=\"padding-left: 40px;\">$servers = Get-Content -LiteralPath $serverListPath |<br \/>\nForEach-Object { $_.Trim() } |<br \/>\nWhere-Object { $_ -ne &#8221; -and -not $_.StartsWith(&#8216;#&#8217;) } |<br \/>\nSelect-Object -Unique<\/p>\n<p>Trimming the entries and removing duplicates prevents simple formatting problems in the input file from turning into unnecessary assessment attempts.<\/p>\n<h2>Run Get-SqlSafe for each instance<\/h2>\n<p>Once the server list is available as a PowerShell array, each entry can be passed to Get-SqlSafe. The following excerpt shows the basic sequence.<\/p>\n<h3>Excerpt: invoke Get-SqlSafe and record basic status<\/h3>\n<p style=\"padding-left: 40px;\">foreach ($server in $servers) {<br \/>\ntry {<br \/>\n&#038; $getSqlSafePath `<br \/>\n-ConsoleOnly `<br \/>\n-SqlInstance $server `<br \/>\n-Auth Windows `<br \/>\n-NoAutoOpenReport<\/p>\n<p style=\"padding-left: 40px;\">$completed++<br \/>\nWrite-Host &#8220;Completed: $server&#8221; -ForegroundColor Green<br \/>\n}<br \/>\ncatch {<br \/>\n$failed++<br \/>\nWrite-Host &#8220;Failed: $server&#8221; -ForegroundColor Red<br \/>\nWrite-Host $_.Exception.Message -ForegroundColor Red<br \/>\n}<br \/>\n}<\/p>\n<p>This is deliberately basic failure handling. In a production wrapper, you may also want to capture timestamps, exit status, output paths, timeouts, and enough information to retry individual instances.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-7538 alignnone\" src=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2026\/08\/202608_Get-SqlSafe-MultiServerRunConsoleOutput-1.png\" alt=\"\" width=\"900\" height=\"430\" srcset=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2026\/08\/202608_Get-SqlSafe-MultiServerRunConsoleOutput-1.png 900w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2026\/08\/202608_Get-SqlSafe-MultiServerRunConsoleOutput-1-300x143.png 300w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2026\/08\/202608_Get-SqlSafe-MultiServerRunConsoleOutput-1-768x367.png 768w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2026\/08\/202608_Get-SqlSafe-MultiServerRunConsoleOutput-1-705x337.png 705w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p>Example screenshot of running Get-SqlSafe against 90 SQL Servers, including 11 not reachable in under a minute.<\/p>\n<h2>If you need to step up: parallel execution<\/h2>\n<p>Sequential execution is easy to understand and troubleshoot, and probably sufficient for many environments. For a larger estate, however, one slow or unreachable instance can delay everything that follows it.<\/p>\n<p>If sequential execution is too slow, you can start separate PowerShell processes in parallel by using <em>Start-Process<\/em>. This prevents one slow connection from blocking the entire list, but it also makes accurate completion tracking and failure handling more important.<\/p>\n<p>Avoid starting one process for every server at once. A small concurrency limit is usually sufficient. In one environment, I processed more than 100 SQL Server instances in under 2 minutes with no more than five assessments running in parallel. Your results will depend on network latency, authentication, server responsiveness, and the system running the wrapper.<\/p>\n<blockquote><p><strong>Note<\/strong><br \/>\nReliable parallel orchestration requires more than starting processes.<br \/>\nThis requires concurrency limits, timeout handling, result tracking, retry handling, and an unambiguous association between each instance and its output.<\/p><\/blockquote>\n<h2>Results<\/h2>\n<p>After the run, you will have a single \u201cResults\u201d-folder containing one HTML report for every successfully assessed instance.<\/p>\n<p>Now you have a repeatable snapshot of the instances you supplied, collected in a consistent format and produced without deploying an agent or database component.<\/p>\n<p>You should also retain the list of unsuccessful attempts. A missing report can indicate an obsolete server entry, a connectivity problem, or insufficient permissions.<\/p>\n<h2>Next: summarize the estate<\/h2>\n<p>Opening dozens or hundreds of reports individually is not an efficient way to answer estate-level questions. In my next article, I will show how to extract selected values from the generated reports and turn them into a consolidated SQL Server estate summary.<\/p>\n<h2>Summary<\/h2>\n<p>Running Get-SqlSafe across an estate does not require a complex platform. Start with console mode, a clean server list, sequential execution, and careful failure tracking. Add controlled parallelism only after the basic workflow is reliable.<\/p>\n<p>The accompanying sample is a blueprint rather than production orchestration. Add the safeguards appropriate for your environment and test it on a few instances before scaling out.<\/p>\n<p>If you have not downloaded Get-SqlSafe yet, you can find it on <a href=\"https:\/\/sarpedonqualitylab.us\/resources\/\" target=\"_blank\" rel=\"noopener\">the Get-SqlSafe resources page<\/a>.<\/p>\n<p>A working sample of the multi-server runner can be downloaded here: <a href=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2026\/08\/Get-SqlSafe-ServerList-Runner-1.zip\">Get-SqlSafe-ServerList-Runner-1.zip\u00a0<\/a><\/p>\n<p>Andreas<\/p>\n<\/div><\/section>\r\n\r\n<div  class='flex_column av-27ilfv-30c3733b2a94e65a34b4942e6b6a5f6f av_one_full  avia-builder-el-2  el_after_av_textblock  el_before_av_social_share  first flex_column_div  column-top-margin'     ><section  class='av_textblock_section av-mo242alu-8257e57f95cd0d93808b09100c4a8236 '   itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/BlogPosting\" itemprop=\"blogPost\" ><div class='avia_textblock'  itemprop=\"text\" ><p><strong data-start=\"1285\" data-end=\"1320\">Need to go beyond the baseline?<\/strong><br data-start=\"1320\" data-end=\"1323\" \/>Get-SqlSafe Community Edition is designed as a first look. For organizations that need deeper assurance, Sarpedon Quality Lab offers professional SQL Server Security Assessments covering advanced permissions analysis, configuration review, auditing, escalation paths, backup and OS-level security, and environment-specific remediation guidance.<\/p>\n<\/div><\/section>\n<div  class='avia-button-wrap av-mo243ot6-ea0b57e46898d9b891741b0c23880f73-wrap avia-button-center  avia-builder-el-4  el_after_av_textblock  el_before_av_hr '>\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-mo243ot6-ea0b57e46898d9b891741b0c23880f73\">\n#top #wrap_all .avia-button.av-mo243ot6-ea0b57e46898d9b891741b0c23880f73{\nfont-size:14px;\nbackground-color:#75a823;\nborder-color:#75a823;\ncolor:#ffffff;\nbox-shadow: 0 0 5px 5px ;\ntransition:all 0.4s ease-in-out;\n}\n<\/style>\n<a href=\"https:\/\/sarpedonqualitylab.us\/sql-server-security-assessment\/\" class=\"avia-button av-mo243ot6-ea0b57e46898d9b891741b0c23880f73 avia-icon_select-yes-left-icon avia-size-medium avia-position-center\" target=\"_blank\" rel=\"noopener\"><span class='avia_button_icon avia_button_icon_left' aria-hidden='true' data-av_icon='\ue832' data-av_iconfont='entypo-fontello'><\/span><span class='avia_iconbox_title' >Learn more about the full SQL Server Security Assessment<\/span><\/a><\/div>\n<div  class='hr av-9inuj-ef570c4ea0fba0353373c5000396a879 hr-default  avia-builder-el-5  el_after_av_button  avia-builder-el-last '><span class='hr-inner '><span class=\"hr-inner-style\"><\/span><\/span><\/div><\/div>\r\n\r\n<div  class='av-social-sharing-box av-5n5vpa-78ffdd9d224b4a246af65bdc00dce900 av-social-sharing-box-default  avia-builder-el-6  el_after_av_one_full  el_before_av_hr  av-social-sharing-box-fullwidth'><div class=\"av-share-box\"><h5 class='av-share-link-description av-no-toc '>Share article<\/h5><ul class=\"av-share-box-list noLightbox\"><li class='av-share-link av-social-link-facebook' ><a target=\"_blank\" aria-label=\"Share on Facebook\" href=\"https:\/\/www.facebook.com\/sharer.php?u=https:\/\/andreas-wolter.com\/en\/2608_get-sqlsafe_communityedition_sqlserver_security_asssessment_at_scale\/&amp;t=Running%20Get-SqlSafe%20at%20Scale%20Across%20a%20SQL%20Server%20Estate\" aria-hidden=\"false\" data-av_icon=\"\ue8f3\" data-av_iconfont=\"entypo-fontello\" title=\"\" data-avia-related-tooltip=\"Share on Facebook\" rel=\"noopener\"><span class='avia_hidden_link_text'>Share on Facebook<\/span><\/a><\/li><li class='av-share-link av-social-link-twitter' ><a target=\"_blank\" aria-label=\"Share on Twitter\" href=\"https:\/\/twitter.com\/share?text=Running%20Get-SqlSafe%20at%20Scale%20Across%20a%20SQL%20Server%20Estate&amp;url=https:\/\/andreas-wolter.com\/en\/?p=7533\" aria-hidden=\"false\" data-av_icon=\"\ue8f1\" data-av_iconfont=\"entypo-fontello\" title=\"\" data-avia-related-tooltip=\"Share on Twitter\" rel=\"noopener\"><span class='avia_hidden_link_text'>Share on Twitter<\/span><\/a><\/li><li class='av-share-link av-social-link-linkedin' ><a target=\"_blank\" aria-label=\"Share on LinkedIn\" href=\"https:\/\/linkedin.com\/shareArticle?mini=true&amp;title=Running%20Get-SqlSafe%20at%20Scale%20Across%20a%20SQL%20Server%20Estate&amp;url=https:\/\/andreas-wolter.com\/en\/2608_get-sqlsafe_communityedition_sqlserver_security_asssessment_at_scale\/\" aria-hidden=\"false\" data-av_icon=\"\ue8fc\" data-av_iconfont=\"entypo-fontello\" title=\"\" data-avia-related-tooltip=\"Share on LinkedIn\" rel=\"noopener\"><span class='avia_hidden_link_text'>Share on LinkedIn<\/span><\/a><\/li><\/ul><\/div><\/div>\r\n\r\n\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-4ofg9q-c2108540b480aba02923089240a3a176\">\n#top .hr.hr-invisible.av-4ofg9q-c2108540b480aba02923089240a3a176{\nheight:50px;\n}\n<\/style>\n<div  class='hr av-4ofg9q-c2108540b480aba02923089240a3a176 hr-invisible  avia-builder-el-7  el_after_av_social_share  el_before_av_comments_list '><span class='hr-inner '><span class=\"hr-inner-style\"><\/span><\/span><\/div>\r\n\r\n<div  class='av-buildercomment av-284ftq-f5a1564cd6b8ffad6ce835e2d40de4b7  av-blog-meta-author-disabled av-blog-meta-html-info-disabled'><\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":4,"featured_media":7538,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[57,121],"tags":[386,206],"class_list":["post-7533","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-security-en","category-scripts-en","tag-get-sqlsafe","tag-sql-security"],"_links":{"self":[{"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/posts\/7533","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/comments?post=7533"}],"version-history":[{"count":3,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/posts\/7533\/revisions"}],"predecessor-version":[{"id":7541,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/posts\/7533\/revisions\/7541"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/media\/7538"}],"wp:attachment":[{"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/media?parent=7533"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/categories?post=7533"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/tags?post=7533"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}