{"id":32477,"date":"2024-04-17T11:15:13","date_gmt":"2024-04-17T09:15:13","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=32477"},"modified":"2024-08-19T10:56:17","modified_gmt":"2024-08-19T08:56:17","slug":"build-sql-server-audit-reports-with-powershell","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/","title":{"rendered":"Build SQL Server audit reports with Powershell"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"h-introduction\">Introduction<\/h2>\n\n\n\n<p>When you are tasked with conducting an audit at a client&#8217;s site or on the environment you manage, you might find it necessary to automate the audit process in order to save time. However, it can be challenging to extract information from either the PowerShell console or a text file.<\/p>\n\n\n\n<p>Here, the idea would be to propose a solution that could generate audit reports to quickly identify how the audited environment is configured. We will attempt to propose a solution that will automate the generation of audit reports.<\/p>\n\n\n\n<p>In broad terms, here are what we will implement:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Define the environment we wish to audit. We centralize the configuration of our environments and all the parameters we will use.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Define the checks or tests we would like to perform.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Execute these checks. In our case, we will mostly use dbatools to perform the checks. However, it&#8217;s possible that you may not be able to use dbatools in your environment for security reasons, for example. In that case, you could replace calls to dbatools with calls to PowerShell functions.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Produce an audit report.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-technologies\">Technologies<\/h2>\n\n\n\n<p>Here are the technologies we will use in our project :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>SQL Server<\/li>\n\n\n\n<li>Powershell<\/li>\n\n\n\n<li>Windows Server<\/li>\n\n\n\n<li>JSON<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-dependencies\">Dependencies<\/h2>\n\n\n\n<p>In our example, we use the dbatools module in oder to get some information related to the environment(s) we audit.<\/p>\n\n\n\n<p>Reference : <a href=\"https:\/\/dbatools.io\/\">https:\/\/dbatools.io\/<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-global-architecture\">Global architecture<\/h2>\n\n\n\n<p><strong>Here is how our solution will work :<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We store the configuration of our environment in a JSON file. This avoids storing certain parameters in the PowerShell code.<\/li>\n\n\n\n<li>We import our configuration (our JSON file). We centralize in one file all the checks, tests to be performed. The configuration stored in the JSON file is passed to the tests.<\/li>\n\n\n\n<li>We execute all the tests to be performed, then we generate an HTML file on which we apply a CSS stylesheet.<\/li>\n\n\n\n<li>We can then send this information by email (for example).<\/li>\n<\/ul>\n\n\n\n<p><strong>Here are some details about the structure of our project :<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes has-small-font-size\"><table><thead><tr><th><strong>Folder<\/strong><\/th><th><strong>Type<\/strong><\/th><th>File<\/th><th><strong>Description<\/strong><\/th><th><strong>Details<\/strong><\/th><\/tr><\/thead><tbody><tr><td>dbi-audit<\/td><td>PS1 file<\/td><td>dbi-audit-config.json<\/td><td>Contains some pieces of information related to the environment you would like to audit.<\/td><td>The file is called by the dbi-audit-checks.ps1. We import that file and parse it. E.g. if you need to add new servers to audit you can edit that file and run a new audit.<\/td><\/tr><tr><td>dbi-audit<\/td><td>PS1 file<\/td><td>dbi-audit-checks.ps1<\/td><td>Store the checks to perform on the environment(s).<\/td><td>That file acts as a &#8220;library&#8221;, it contains all the checks to perform. It centralizes all the functions.<\/td><\/tr><tr><td>dbi-audit<\/td><td>PS1 file<\/td><td>dbi-audit-run.ps1<\/td><td>Run the checks to perform Transform the output in an html file.<\/td><td>It&#8217;s the most import file : &nbsp;<br>It runs the checks to perform. &nbsp;<br>It builds the html report and apply a stylesheet &nbsp;<br>It can also send by email the related report<\/td><\/tr><tr><td>dbi-audit<\/td><td>CSS<\/td><td>dbi-audit-stylesheet.css<\/td><td>Contains the stylesheet to apply to the HTML report.<\/td><td>It&#8217;s where we define what our HTML report will look like.<\/td><\/tr><tr><td>html_output<\/td><td>Folder<\/td><td>&#8211;<\/td><td>Will contain the report audit produced.<\/td><td>It stores HTML reports.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>What does it look like ?<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"607\" height=\"161\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png\" alt=\"\" class=\"wp-image-33016\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png 607w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-300x80.png 300w\" sizes=\"auto, (max-width: 607px) 100vw, 607px\" \/><\/figure>\n\n\n\n<p><strong>How does it work ?<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"440\" height=\"661\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/workflow_a.jpg\" alt=\"\" class=\"wp-image-33017\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/workflow_a.jpg 440w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/workflow_a-200x300.jpg 200w\" sizes=\"auto, (max-width: 440px) 100vw, 440px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-implementation\">Implementation<\/h2>\n\n\n\n<p>Code &#8211; A basic implementation :<\/p>\n\n\n\n<p>dbi-audit-config.json :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#091;\n\t{\n\t\t\"Name\": \"app.computername\",\n\t\t\"Value\": &#091;\n\t\t\t\t\t  \"WS-2022-A\",\n                      \"ad\"\n\t\t\t\t  ],\n\t\t\"Description\": \"List of Windows Servers that Windows-based tests will run against\"\n\t},\n\t{\n\t\t\"Name\": \"app.sqlinstance\",\n\t\t\"Value\": &#091;\n\t\t\t\t\t  \"WS-2022-A\\\\INSTANCEA,1433\"\n\t\t\t\t  ],\n\t\t\"Description\": \"List of SQL Server instances that SQL-based tests will run against\"\n\t},\n\t{\n\t\t\"Name\": \"dbi-app.checkcomputersinformation.enabled\",\n\t\t\"Value\": \"True\",\n\t\t\"Description\": \"Get some information on OS level\"\n\t},\n\t{\n\t\t\"Name\": \"dbi-app.checkoperatingsystem.enabled\",\n\t\t\"Value\": \"True\",\n\t\t\"Description\": \"Perform some OS checks\"\n\t},\n\t{\n\t\t\"Name\": \"dbi-app.checksqlsystemconfiguration.enabled\",\n\t\t\"Value\": \"True\",\n\t\t\"Description\": \"Check some SQL Server system settings\"\n\t}\n]<\/code><\/pre>\n\n\n\n<p>dbi-audit-controls-library.ps1 :<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>#We import our configuration\n$AuditConfig = &#091;PSCustomObject](Get-Content .\\dbi-audit-config.json | Out-String | ConvertFrom-Json)\n\n#We retrieve the values contained in our json file. Each value is stored in a variable\n$Computers = $AuditConfig | Where-Object { $_.Name -eq 'dbi-app.computername' } | Select-Object Value\n$SQLInstances = $AuditConfig | Where-Object { $_.Name -eq 'dbi-app.sqlinstance' } | Select-Object Value\n$UnitFileSize = ($AuditConfig | Where-Object { $_.Name -eq 'app.unitfilesize' } | Select-Object Value).Value\n\n#Our configuration file allow to enable or disable some checks. We also retrieve those values.\n$EnableCheckComputersInformation = ($AuditConfig | Where-Object { $_.Name -eq 'dbi-app.checkcomputersinformation.enabled' } | Select-Object Value).Value\n$EnableCheckOperatingSystem = ($AuditConfig | Where-Object { $_.Name -eq 'dbi-app.checkoperatingsystem.enabled' } | Select-Object Value).Value\n$EnableCheckSQLSystemConfiguration = ($AuditConfig | Where-Object { $_.Name -eq 'dbi-app.checksqlsystemconfiguration.enabled' } | Select-Object Value).Value\n\n#Used to invoke command queries\n$ComputersList = @()\n$ComputersList += $Computers | Foreach-Object {\n   $_.Value \n}\n\n\nfunction Get-ComputersInformation()\n{\n    if ($EnableCheckComputersInformation -eq $True)\n    { \n        $ComputersInformationList = @()\n        $ComputersInformationList += $Computers | Foreach-Object { \n                                                    Get-DbaComputerSystem -ComputerName $_.Value | \n                                                        Select-Object ComputerName, Domain, NumberLogicalProcessors, \n                                                        NumberProcessors, TotalPhysicalMemory\n        }\n    }\n        \n    return $ComputersInformationList\n}\n\n\nfunction Get-OperatingSystem()\n{\n    if ($EnableCheckOperatingSystem -eq $True)\n    {    \n        $OperatingSystemList = @()\n        $OperatingSystemList += $Computers | Foreach-Object {\n                                                Get-DbaOperatingSystem -ComputerName $_.Value | \n                                                    Select-Object ComputerName, Architecture, OSVersion, ActivePowerPlan\n        }\n    }\n\n    return $OperatingSystemList\n}\n\n\nfunction Get-OSDiskSpace()\n{\n    if ($EnableCheckOSDiskSpace -eq $True)\n    {   \n        $OSDiskSpaceList = @()\n        $OSDiskSpaceList += $Computers | Foreach-Object {\n                                            Get-DbaDiskSpace -ComputerName $_.Value -Unit $UnitFileSize | \n                                                Select-Object ComputerName, Name, Label, Capacity, Free, PercentFree, BlockSize, FileSystem\n        }\n    }\n    \n    return $OSDiskSpaceList\n}\n\n\nfunction Get-SQLServerServiceState()\n{\n    if ($EnableCheckSQLServerServiceState -eq $True)\n    {\n        $SQLServerServiceStateList = @()\n        $SQLServerServiceStateList += $Computers | Foreach-Object {\n                                            Get-DbaService -ComputerName $_.Value | \n                                                Select-Object ComputerName, ServiceName, ServiceType, DisplayName, StartName, State, StartMode\n        }\n    }\n\n    return $SQLServerServiceStateList\n}\n<\/code><\/pre>\n\n\n\n<p>dbi-audit-main.ps1 :<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>. .\\dbi-audit-controls-library.ps1\n\n$HTMLHeader = '&lt;!DOCTYPE html&gt;&lt;head&gt;&lt;meta charset=\"utf-8\"\/&gt;&lt;link href=\"..\\dbi-audit-style.css\" rel=\"stylesheet\"&gt;&lt;\/head&gt;&lt;body&gt;&lt;div id=\"sidebar\"&gt;&lt;\/div&gt;'\n$HTMLFooter = \"&lt;\/body&gt;&lt;\/html&gt;\"\n\n$HeaderMapping = @{\n    ComputersInformation = \"Computers Information\"\n    OperatingSystem = \"Operation System Information\"\n    OSDiskSpace = \"Disk Space Information\"\n    SQLServerServiceState = \"SQL Server Services State\"\n}\n\n$Checks = &#091;ordered] @{}\n$Checks&#091;'ComputersInformation'] = Get-ComputersInformation\n$Checks&#091;'OperatingSystem'] = Get-OperatingSystem\n$Checks&#091;'OSDiskSpace'] = Get-OSDiskSpace\n$Checks&#091;'SQLServerServiceState'] = Get-SQLServerServiceState\n\n$Output = ''\n\n$Checks.Keys | ForEach-Object {\n    \n    $TitleSection = $HeaderMapping&#091;$_]\n    $Output += $Checks&#091;$_] | ConvertTo-HTML -Pre \"&lt;div class=`\"$_`\"&gt;\" -Post \"&lt;\/div&gt;\" -Property * -Fragment\n    $Output = $Output -replace \"(?s)&lt;colgroup&gt;.*?&lt;\/colgroup&gt;\", \"&lt;h2&gt;$TitleSection&lt;\/h2&gt;\"  \n    $Output = $Output -Replace '&lt;td&gt;Stopped','&lt;td class=\"control_failed\"&gt;Stopped'\n    $Output = $Output -Replace '&lt;td&gt;Running','&lt;td class=\"control_passed\"&gt;Running'\n    $Output = $Output -Replace '&lt;td&gt;Balanced','&lt;td class=\"control_failed\"&gt;Balanced'\n    $Output = $Output -Replace '&lt;td&gt;High performance','&lt;td class=\"control_passed\"&gt;High performance'\n}\n\n$HTML = $HTMLHeader + $Output + $HTMLFooter\n$HTML | Out-File \".\\html_output\\dbi-audit.html\" -Encoding utf8<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>dbi-audit-style.css :<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>th,\ntd {\n  border: 1px solid rgb(160 160 160);\n  padding: 8px 10px;\n}\n\nth&#091;scope='col'] {\n  background-color: #505050;\n  color: #fff;\n}\n\nth&#091;scope='row'] {\n  background-color: #d6ecd4;\n}\n\ntd {\n  text-align: center;\n}\n\ntr:nth-of-type(even) {\n  background-color: #eee;\n}\n\ntable {\n  border-collapse: collapse;\n  border: 2px solid rgb(140 140 140);\n  font-family: sans-serif;\n  font-size: 0.8rem;\n  letter-spacing: 1px;\n  -moz-box-shadow: 0 0 3px #888;\n  -webkit-box-shadow: 0 0 5px#888;\n  box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;\n}\n\ntr .control_failed {\n\tcolor: #F7F7F7;\n\tbackground-color: #BE4025;\n}\n\ntr .control_passed {\n\tcolor: #F7F7F7;\n\tbackground-color: #16BA00;\n}\n\ncaption {\n  caption-side: bottom;\n  padding: 10px;\n}\n\nhtml {\n    padding:0;\n    margin:0;\n}\n\nbody {\n\tbackground-color:#fbfbfb;\n    margin:0;\n    padding: 0;\n}\n\nh2 {\n\tfont-family: \"Gill Sans\", sans-serif;\n    text-shadow: 2px 2px 2px #c9c9c9;\t\n}\n\n#sidebar {\n    float:left;\n    background-color:#ffa733;\n    width:4%;\n    margin-right:20px; \n    height:100vh;\n    box-shadow: 5px 10px #154c79;\n}\n\n#sidebar .dbi_audit {\n    display: inline-block;\n    transform: rotate(-90deg);\n    transform-origin: top left;\n}<\/code><\/pre>\n\n\n\n<p>How does it run ?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.\\dbi-audit-main.ps1<\/code><\/pre>\n\n\n\n<p>Output (what does it really look like ?) :<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"650\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-1-1024x650.png\" alt=\"\" class=\"wp-image-33020\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-1-1024x650.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-1-300x190.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-1-768x487.png 768w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-1.png 1149w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-nice-to-have\">Nice to have<\/h2>\n\n\n\n<p><strong>Let&#8217;s say I would like to add new checks. How would I proceed ?<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"570\" height=\"90\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-3.png\" alt=\"\" class=\"wp-image-33022\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-3.png 570w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-3-300x47.png 300w\" sizes=\"auto, (max-width: 570px) 100vw, 570px\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Edit the dbi-audit-config.json and add your check<\/li>\n\n\n\n<li>Edit the dbi-audit-checks.ps1<\/li>\n\n\n\n<li>Retrieve the information related to your check<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>$EnableCheckSQLDatabaseQueryStore = ($AuditConfig | Where-Object { $_.Name -eq 'app.checksqldatabasequerystore.enabled' } | Select-Object Value).Value<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Add another function<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>function Get-SQLDatabaseQueryStore()\n{\n    if ($EnableCheckSQLDatabaseQueryStore -eq $True)\n    {\n        $SQLDatabaseQueryStoreList = @()\n        $SQLDatabaseQueryStoreList += $SQLInstances | Foreach-Object {\n                                                        Test-DbaDbQueryStore -SqlInstance $_.Value | \n                                                            Where-Object { $_.Name -eq 'ActualState' -and $_.Database -ne 'master' -and $_.Database -ne 'msdb' -and $_.Database -ne 'model' -and $_.Database -ne 'tempdb' } | \n                                                                Select-Object ComputerName, SQLInstance, Database, Value\n        }\n    }\n\n    return $SQLDatabaseQueryStoreList\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Call it in the dbi-audit-main.ps1 script<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>$HeaderMapping = @{\n    ComputersInformation = \"Computers Information\"\n    OperatingSystem = \"Operation System Information\"\n    OSDiskSpace = \"Disk Space Information\"\n    SQLServerServiceState = \"SQL Server Services State\"\n    SQLDatabaseQueryStore = \"Query Store\"\n}\n\n$Checks = &#091;ordered] @{}\n$Checks&#091;'ComputersInformation'] = Get-ComputersInformation\n$Checks&#091;'OperatingSystem'] = Get-OperatingSystem\n$Checks&#091;'OSDiskSpace'] = Get-OSDiskSpace\n$Checks&#091;'SQLServerServiceState'] = Get-SQLServerServiceState\n$Checks&#091;'SQLDatabaseQueryStore'] = Get-SQLDatabaseQueryStore<\/code><\/pre>\n\n\n\n<p><strong>End result :<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"780\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-4-1024x780.png\" alt=\"\" class=\"wp-image-33025\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-4-1024x780.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-4-300x229.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-4-768x585.png 768w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image-4.png 1155w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>What about sending the report through email ?<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We could add a function that send an email with an attachment.\n<ul class=\"wp-block-list\">\n<li>Edit the dbi-audit-controls-library file\n<ul class=\"wp-block-list\">\n<li>Add a function Send-EmailWithAuditReport<\/li>\n\n\n\n<li>Add this piece of code to the function :<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>Send-MailMessage -SmtpServer mysmtpserver -From 'Sender' -To 'Recipient' -Subject 'Audit report' -Body 'Audit report' -Port 25 -Attachments $Attachments<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Edit the dbi-audit-main.ps1<\/li>\n\n\n\n<li>Add a call to the Send-EmailWithAuditReport function <code>Send-EmailWithAuditReport -Attachments $Attachments<\/code><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-conclusion\">Conclusion<\/h2>\n\n\n\n<p>The main idea of this solution is to be able to use the same functions while applying a different rendering. To achieve this, you would need to change the CSS file.<\/p>\n\n\n\n<p>This would allow having the same code to perform the following tasks:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Audit<\/li>\n\n\n\n<li>Health check<\/li>\n\n\n\n<li>&#8230;<\/li>\n<\/ul>\n\n\n\n<p>Thank you, Amine Haloui.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction When you are tasked with conducting an audit at a client&#8217;s site or on the environment you manage, you might find it necessary to automate the audit process in order to save time. However, it can be challenging to extract information from either the PowerShell console or a text file. Here, the idea would [&hellip;]<\/p>\n","protected":false},"author":147,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[99],"tags":[1888,3338,3337,51],"type_dbi":[],"class_list":["post-32477","post","type-post","status-publish","format-standard","hentry","category-sql-server","tag-dbatools","tag-html","tag-reporting","tag-sql-server"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Build SQL Server audit reports with Powershell - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build SQL Server audit reports with Powershell\" \/>\n<meta property=\"og:description\" content=\"Introduction When you are tasked with conducting an audit at a client&#8217;s site or on the environment you manage, you might find it necessary to automate the audit process in order to save time. However, it can be challenging to extract information from either the PowerShell console or a text file. Here, the idea would [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-04-17T09:15:13+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-08-19T08:56:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png\" \/>\n<meta name=\"author\" content=\"Amine Haloui\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Amine Haloui\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/\"},\"author\":{\"name\":\"Amine Haloui\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/221331d69d49c63fca67069b49b813fe\"},\"headline\":\"Build SQL Server audit reports with Powershell\",\"datePublished\":\"2024-04-17T09:15:13+00:00\",\"dateModified\":\"2024-08-19T08:56:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/\"},\"wordCount\":695,\"commentCount\":1,\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png\",\"keywords\":[\"dbatools\",\"HTML\",\"Reporting\",\"SQL Server\"],\"articleSection\":[\"SQL Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/\",\"name\":\"Build SQL Server audit reports with Powershell - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png\",\"datePublished\":\"2024-04-17T09:15:13+00:00\",\"dateModified\":\"2024-08-19T08:56:17+00:00\",\"author\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/221331d69d49c63fca67069b49b813fe\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#primaryimage\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png\",\"contentUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png\",\"width\":607,\"height\":161},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/www.dbi-services.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Build SQL Server audit reports with Powershell\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/221331d69d49c63fca67069b49b813fe\",\"name\":\"Amine Haloui\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/64707272207cd8d2667aefcb212f3ff5d19a15813da5aad6553f109d1f1afec1?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/64707272207cd8d2667aefcb212f3ff5d19a15813da5aad6553f109d1f1afec1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/64707272207cd8d2667aefcb212f3ff5d19a15813da5aad6553f109d1f1afec1?s=96&d=mm&r=g\",\"caption\":\"Amine Haloui\"},\"url\":\"https:\/\/www.dbi-services.com\/blog\/author\/aminehaloui\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Build SQL Server audit reports with Powershell - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/","og_locale":"en_US","og_type":"article","og_title":"Build SQL Server audit reports with Powershell","og_description":"Introduction When you are tasked with conducting an audit at a client&#8217;s site or on the environment you manage, you might find it necessary to automate the audit process in order to save time. However, it can be challenging to extract information from either the PowerShell console or a text file. Here, the idea would [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/","og_site_name":"dbi Blog","article_published_time":"2024-04-17T09:15:13+00:00","article_modified_time":"2024-08-19T08:56:17+00:00","og_image":[{"url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png","type":"","width":"","height":""}],"author":"Amine Haloui","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Amine Haloui","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/"},"author":{"name":"Amine Haloui","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/221331d69d49c63fca67069b49b813fe"},"headline":"Build SQL Server audit reports with Powershell","datePublished":"2024-04-17T09:15:13+00:00","dateModified":"2024-08-19T08:56:17+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/"},"wordCount":695,"commentCount":1,"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png","keywords":["dbatools","HTML","Reporting","SQL Server"],"articleSection":["SQL Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/","url":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/","name":"Build SQL Server audit reports with Powershell - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#primaryimage"},"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png","datePublished":"2024-04-17T09:15:13+00:00","dateModified":"2024-08-19T08:56:17+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/221331d69d49c63fca67069b49b813fe"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#primaryimage","url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png","contentUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/05\/image.png","width":607,"height":161},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/build-sql-server-audit-reports-with-powershell\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Build SQL Server audit reports with Powershell"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/221331d69d49c63fca67069b49b813fe","name":"Amine Haloui","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/64707272207cd8d2667aefcb212f3ff5d19a15813da5aad6553f109d1f1afec1?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/64707272207cd8d2667aefcb212f3ff5d19a15813da5aad6553f109d1f1afec1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/64707272207cd8d2667aefcb212f3ff5d19a15813da5aad6553f109d1f1afec1?s=96&d=mm&r=g","caption":"Amine Haloui"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/aminehaloui\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/32477","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/147"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=32477"}],"version-history":[{"count":55,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/32477\/revisions"}],"predecessor-version":[{"id":34553,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/32477\/revisions\/34553"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=32477"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=32477"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=32477"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=32477"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}