├── src ├── Common │ ├── Roles.csv │ ├── config.ini │ ├── PowerStigScan.Computer.ps1 │ ├── helpers.ps1 │ ├── DSCCall.ps1 │ ├── PowerStigScan.Results.ps1 │ ├── PowerStigScan.Scap.ps1 │ ├── PowerStigScan.Config.ps1 │ └── PowerStigScan.Main.ps1 ├── PowerStigScan.psm1 ├── PowerStigScan.psd1 └── SQL │ ├── 499.sql │ ├── DBdeployer.ps1 │ ├── 502.sql │ └── 500.sql ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── LICENSE └── README.md /src/Common/Roles.csv: -------------------------------------------------------------------------------- 1 | DotNetFramework 2 | FireFox 3 | IISServer 4 | IISSite 5 | InternetExplorer 6 | Excel2013 7 | Outlook2013 8 | PowerPoint2013 9 | Word2013 10 | OracleJRE 11 | SqlServer-2012-Database 12 | SqlServer-2012-Instance 13 | SqlServer-2016-Instance 14 | WindowsClient 15 | WindowsDefender 16 | WindowsDNSServer 17 | WindowsFirewall 18 | WindowsServer-DC 19 | WindowsServer-MS -------------------------------------------------------------------------------- /src/Common/config.ini: -------------------------------------------------------------------------------- 1 | ; All Entries are space sensitive. Future versions will fix input validation. 2 | ; Concurrent scan option is only used here if you are running a standalone function 3 | ; else it falls back to SQL configuration 4 | 5 | [general] 6 | CKLOutPath=C:\Temp\PowerStig\CKL\ 7 | LogPath=C:\Temp\PowerStig\ 8 | ConcurrentScans=5 9 | 10 | [SCAP] 11 | ScapInstallDir=C:\Program Files\SCAP Compliance Checker 5.1\ 12 | ScapProfile=MAC-3_Sensitive 13 | 14 | [database] 15 | SQLInstanceName=ServerName\InstanceName 16 | DatabaseName=PowerStig -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/PowerStigScan.psm1: -------------------------------------------------------------------------------- 1 | Import-Module PowerStig -RequiredVersion 3.2.0 2 | 3 | . $PsScriptRoot\Common\helpers.ps1 4 | . $PsScriptRoot\Common\PowerStigScan.Computer.ps1 5 | . $PsScriptRoot\Common\PowerStigScan.Config.ps1 6 | . $PsScriptRoot\Common\PowerStigScan.Results.ps1 7 | . $PsScriptRoot\Common\PowerStigScan.Scap.ps1 8 | . $PsScriptRoot\Common\PowerStigScan.Main.ps1 9 | 10 | Export-ModuleMember -Function @('Invoke-PowerStigScan','Add-PowerStigComputer','Get-PowerStigSqlConfig','Set-PowerStigSqlConfig', 11 | 'Get-PowerStigConfig','Get-PowerStigComputer','Set-PowerStigComputer','Set-PowerStigConfig', 12 | 'Remove-PowerStigComputer','Get-PowerStigOrgSettings','Start-PowerStigDSCScan','Install-PowerStigSQLDatabase') -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Matt Preston 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerStigScan 2 | 3 | ### Release History 4 | 1.0.0.0 - Released February 8, 2019 5 | 1.0.0.2 - Released Feburary 25, 2019 6 | 1.1.0.0 - Released March 1, 2019 7 | 2.0.0.0 - Released June 17, 2019 8 | 2.0.1.0 - Released July 8, 2019 9 | 10 | ## What's New! 11 | ## Support for PowerStig 3.2.0 12 | 13 | ### SCAP Integration 14 | With 2.0.0.0 we have introduced integration with the DISA SCAP Compliance Checker (SCC) tool. This is not a requirement to 15 | run but it will allow you to use SCAP as an authoritative source for rules that it does cover. SCC does not have a lot of 16 | overlap with this module, mostly on the OS checklists, but it is seen as an authoritative source in many DoD organizations. 17 | If, between SCAP and PowerStigScan, there is a conflict between the two sources, the SCAP result will take precedence and will 18 | be annotated on the checklist. 19 | 20 | ### Database Requirement Changes 21 | Similarly, for those that are unable to use a SQL database in their environment, the requirement for a database has been 22 | lowered. You would still see many benefits in using a database such as reporting and archiving of results but now you can 23 | have basic functionality for CKL generation regardless of a database being present. 24 | 25 | ### Organizational Settings Support 26 | We now support custom org settings with PowerStigScan in a more consistent manner. First and foremost, you can store the org 27 | settings in the database for dynamic creation when a scan is triggered. Also, you can store your Org Settings XMLs in the 28 | .\PSOrgSettings\ path of your configured log path (default is C:\Temp\PowerStig). 29 | 30 | 31 | ## How It Works 32 | PowerStigScan is used to automate STIG auditing and checklist generation through the use of the PowerSTIG module. 33 | PowerStig uses DSC to configure an environment to be compliant with DISA STIGs using an automated process to convert 34 | the xccdf to a parsable xml file that is consumed by the module to generate the composite DSC resources. 35 | 36 | PowerStigScan uses that engine with the declarative nature of DSC to test your environment against the compiled MOFs. 37 | This module is made to be used with the companion Database, whose build script is in the SQL folder. The database 38 | holds historical findings that can be used to compile the DISA CKL (Checklist) files that are consumable by 39 | the DISA STIGViewer tool. 40 | 41 | ## How to Install 42 | 43 | ### Database Install 44 | Minimum Requirement - SQL Server Express 2016 45 | 46 | Using the PowerSTIG_DBobjectDeploy_#.sql script in the ..\SQL folder, modify the following lines: 47 | 48 | - :setvar MAIL_PROFILE "MailProfile" 49 | - :setvar MAIL_RECIPIENTS "user@mail.mil" 50 | - :setvar CMS_SERVER "STIG" 51 | - :setvar CMS_DATABASE "PowerStigScan1234" 52 | - :setvar CKL_OUTPUT "C:\Temp\PowerStig\CKL\" 53 | - :setvar CKL_ARCHIVE "C:\Temp\PowerStig\CKL\Archive\" 54 | - :setvar ORG_SETTING_XML "C:\Program Files\WindowsPowerShell\Modules\PowerSTIG\3.1.0\StigData\Processed" 55 | - :setvar CREATE_JOB "Y" 56 | 57 | The Server and Database should be the database location that you intend to install the database into. The MAIL_PROFILE is used to email reports from the database. CREATE_JOB will create a SQL agent job that can be used to automate scans on a 58 | predetermined basis. The CKL_OUTPUT and CKL_ARCHIVE are used during the batch scanning function and are paths relative to the 59 | server or computer that is scanning (i.e. if there is a SQL01 and MS01, the database is on SQL01 and you are scanning from 60 | MS01, the path C:\TEMP will be determined by the scanning server, in this case C:\TEMP on MS01). 61 | 62 | ### Module Install 63 | Using your preferred method to install this module you still need to configure a few settings to get started. First, using 64 | Get-PowerStigConfig, you can view the settings that are located in the config.ini that is located in the .\common directory 65 | of the module.These settings allow for simple and repeatable results in your environment. The primary settings to be 66 | concerned with will be the SQL server and database that you will be connecting to. You can use Set-PowerStigConfig to modify 67 | these settings. 68 | 69 | ### Adding Target Computers 70 | In order to use the SQL Batch functionality, the target servers must exist in the SQL database prior to attempting to running Invoke-PowerStigScan with the -SqlBatch switch. You can add servers to the database with the Add-PowerStigComputer cmdlet with the -ServerName parameter. 71 | 72 | ### BugFixes 73 | ### 2.0.1.0 74 | Added detection for PowerShell 5.1 75 | Fixed issues preventing .Net SCAP scan from proceding 76 | Added support to automatically set Non-Applicable rules for 2016 STIG to NA 77 | 78 | ## Supported STIGs 79 | 80 | ### PowerStig and SCAP comparisons 81 | #### (Can run in PowerStig only or PowerStig + SCAP modes) 82 | Windows Server 2016 Member Server - 1.7 83 | Windows Server 2016 Domain Controller -1.7 84 | Windows Server 2012R2 Member Server - 2.15 85 | Windows Server 2012R2 Domain Controller - 2.16 86 | Windows 10 Client - 1.16 87 | Internet Explorer 11 - 1.16 88 | Windows Firewall - 1.7 89 | Windows Defender - 1.4 90 | Mozilla Firefox - 4.25 91 | 92 | ### PowerStig Only 93 | Excel 2013 - 1.7 94 | PowerPoint 2013 - 1.6 95 | Word 2013 - 1.6 96 | Outlook 2013 - 1.13 97 | Windows Server 2012R2 DNS Server - 1.11 98 | 99 | ### SCAP Only (Versions listed are for manual checklists) 100 | Adobe Acrobat Reader DC Classic - 1.4 101 | Adobe Acrobat Reader DC Continuous - 1.5 102 | Google Chrome - 1.15 103 | .Net Framework - 1.7 104 | 105 | ## Known Issues 106 | IIS, JRE, and SQL scans are not complete. We need to determine the information dynamically as storing static information will 107 | be too burdensome for most administrators. -------------------------------------------------------------------------------- /src/Common/PowerStigScan.Computer.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Functions: 3 | Public: 4 | CM01 - Add-PowerStigComputer 5 | CM02 - Get-PowerStigComputer 6 | CM03 - Set-PowerStigComputer 7 | CM04 - Remove-PowerStigComputer 8 | #> 9 | 10 | #region Private 11 | 12 | #endregion Private 13 | 14 | #region Public 15 | 16 | #CM01 17 | <# 18 | .SYNOPSIS 19 | Adds a new computer target to the PowerStig database 20 | 21 | .DESCRIPTION 22 | Adds a new computer target to the PowerStig database to be scanned with the -SQLBatch switch on Invoke-PowerStigScan 23 | 24 | .PARAMETER ServerName 25 | Name of server to add 26 | 27 | .PARAMETER SqlInstance 28 | SQL instance name that hosts the PowerStig database. If empty, this will use the settings in the ModuleBase\Common\config.ini file. 29 | 30 | .PARAMETER DatabaseName 31 | Name of the database that hosts the PowerStig tables. If empty, this will use the settings in the ModuleBase\Common\config.ini file. 32 | 33 | .EXAMPLE 34 | Add-PowerStigComputer -ServerName DC2012Test -SqlInstance SQLTest -DatabaseName Master 35 | Add-PowerStigComputer -ServerName PowerStigTest 36 | 37 | #> 38 | function Add-PowerStigComputer 39 | { 40 | [CmdletBinding()] 41 | Param( 42 | [Parameter(Mandatory=$true)] 43 | [ValidateNotNullorEmpty()] 44 | [String]$ServerName, 45 | 46 | [switch]$DebugScript, 47 | 48 | [Parameter(Mandatory=$false)] 49 | [String]$SqlInstance, 50 | 51 | [Parameter(Mandatory=$false)] 52 | [String]$DatabaseName 53 | ) 54 | 55 | $workingPath = Split-Path $PsCommandPath 56 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 57 | 58 | if($null -eq $sqlInstance -or $sqlInstance -eq '') 59 | { 60 | $sqlInstance = $iniVar.SqlInstanceName 61 | } 62 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 63 | { 64 | $DatabaseName = $iniVar.DatabaseName 65 | } 66 | 67 | 68 | 69 | $Query = "PowerSTIG.sproc_AddTargetComputer @TargetComputerName = `"$ServerName`"" 70 | 71 | if($DebugScript) 72 | { 73 | Write-Host $query 74 | } 75 | $Results = Invoke-PowerStigSqlCommand -Query $Query -SqlInstance $SqlInstance -DatabaseName $DatabaseName 76 | return $Results 77 | 78 | } 79 | 80 | #CM02 81 | function Get-PowerStigComputer 82 | { 83 | [CmdletBinding()] 84 | param( 85 | [Parameter()] 86 | [switch]$DebugScript, 87 | 88 | [Parameter()] 89 | [String]$SqlInstance, 90 | 91 | [Parameter()] 92 | [String]$DatabaseName 93 | 94 | ) 95 | 96 | $workingPath = Split-Path $PsCommandPath 97 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 98 | 99 | if($null -eq $SqlInstance -or $SqlInstance -eq '') 100 | { 101 | $SqlInstance = $iniVar.SqlInstanceName 102 | } 103 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 104 | { 105 | $DatabaseName = $iniVar.DatabaseName 106 | } 107 | 108 | 109 | $GetAllServers = "EXEC PowerSTIG.sproc_GetActiveServers" 110 | if($DebugScript) 111 | { 112 | Write-Host $GetAllServers 113 | } 114 | $RunGetAllServers = (Invoke-PowerStigSqlCommand -SqlInstance $SqlInstance -DatabaseName $DatabaseName -Query $GetAllServers) 115 | 116 | Return $RunGetAllServers 117 | } 118 | 119 | #CM03 120 | function Set-PowerStigComputer 121 | { 122 | [cmdletBinding()] 123 | param( 124 | [Parameter(Mandatory=$true)] 125 | [String]$ServerName, 126 | 127 | [Parameter(Mandatory=$true)] 128 | [ValidateSet('2012R2','2016','10')] 129 | [String]$osVersion, 130 | 131 | [switch]$DebugScript, 132 | 133 | [Parameter()] 134 | [String]$SqlInstance, 135 | 136 | [Parameter()] 137 | [String]$DatabaseName 138 | ) 139 | 140 | $workingPath = Split-Path $PsCommandPath 141 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 142 | 143 | if($null -eq $SqlInstance -or $SqlInstance -eq '') 144 | { 145 | $SqlInstance = $iniVar.SqlInstanceName 146 | } 147 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 148 | { 149 | $DatabaseName = $iniVar.DatabaseName 150 | } 151 | 152 | 153 | $UpdateComputer = "EXEC PowerSTIG.sproc_UpdateTargetOS @TargetComputer=`"$ServerName`", @OSname=`"$osVersion`"" 154 | Invoke-PowerStigSqlCommand -SqlInstance $SqlInstance -DatabaseName $DatabaseName -Query $UpdateComputer 155 | 156 | } 157 | 158 | #CM04 159 | function Remove-PowerStigComputer 160 | { 161 | [cmdletBinding()] 162 | param( 163 | [Parameter(Mandatory=$true)] 164 | [String]$ServerName, 165 | 166 | [Parameter()] 167 | [Switch]$Force, 168 | 169 | [switch]$DebugScript, 170 | 171 | [Parameter()] 172 | [String]$SqlInstance, 173 | 174 | [Parameter()] 175 | [String]$DatabaseName 176 | ) 177 | 178 | $workingPath = Split-Path $PsCommandPath 179 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 180 | 181 | if($null -eq $SqlInstance -or $SqlInstance -eq '') 182 | { 183 | $SqlInstance = $iniVar.SqlInstanceName 184 | } 185 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 186 | { 187 | $DatabaseName = $iniVar.DatabaseName 188 | } 189 | 190 | if(!($Force)) 191 | { 192 | 193 | $readIn = Read-Host "This will remove $ServerName and all data related to the computer from the database. Continue?(Y/N)" 194 | do{ 195 | if($readIn -eq "N") 196 | { 197 | Write-Host "Cancelling" 198 | Return 199 | } 200 | elseif($readIn -eq "Y") 201 | { 202 | $proceed = $true 203 | } 204 | else 205 | { 206 | $readIn = Read-Host "Invalid response. Do you want to remove $ServerName? (Y/N)" 207 | } 208 | }While($proceed -eq $false) 209 | } 210 | 211 | 212 | $deleteComputer = "EXEC PowerSTIG.sproc_DeleteTargetComputerAndData @TargetComputer = `'$ServerName`'" 213 | if($DebugScript) 214 | { 215 | Write-Host $deleteComputer 216 | } 217 | Invoke-PowerStigSqlCommand -SqlInstance $SqlInstance -DatabaseName $DatabaseName -Query $deleteComputer 218 | 219 | } 220 | 221 | 222 | #endregion Public -------------------------------------------------------------------------------- /src/Common/helpers.ps1: -------------------------------------------------------------------------------- 1 | # ================================================================================================================= 2 | # Purpose: 3 | # Revisions: 4 | # 06282018 - Matt Preston, Microsoft - Release 1 5 | # ================================================================================================================= 6 | # ----------------------------------------------------------------------------- 7 | # 8 | # Copyright (C) 2018 Microsoft Corporation 9 | # 10 | # Disclaimer: 11 | # This is SAMPLE code that is NOT production ready. It is the sole intention of this code to provide a proof of concept as a 12 | # learning tool for Microsoft Customers. Microsoft does not provide warranty for or guarantee any portion of this code 13 | # and is NOT responsible for any affects it may have on any system it is executed on or environment it resides within. 14 | # Please use this code at your own discretion! 15 | # Additional legalese: 16 | # This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment. 17 | # THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 18 | # INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 19 | # We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute 20 | # the object code form of the Sample Code, provided that You agree: 21 | # (i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code is embedded; 22 | # (ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded; and 23 | # (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits, including attorneys' fees, 24 | # that arise or result from the use or distribution of the Sample Code. 25 | # ----------------------------------------------------------------------------- 26 | 27 | <# 28 | Functions: 29 | Private: 30 | H01 - Convert-PowerStigRoleToSql 31 | H02 - Import-PowerStigConfig 32 | H03 - Invoke-PowerStigSqlCommand 33 | #> 34 | #H01 35 | function Convert-PowerStigRoleToSql 36 | { 37 | [cmdletBinding()] 38 | param( 39 | [Parameter(Mandatory=$true)] 40 | [String]$Role 41 | ) 42 | 43 | 44 | switch($Role) 45 | { 46 | "DotNetFramework" {Return $Role} 47 | "FireFox" {Return $Role} 48 | "IISServer" {Return $Role} 49 | "IISSite" {Return $Role} 50 | "InternetExplorer" {Return $Role} 51 | "Excel2013" {Return $Role} 52 | "Outlook2013" {Return $Role} 53 | "PowerPoint2013" {Return $Role} 54 | "Word2013" {Return $Role} 55 | "OracleJRE" {Return $Role} 56 | "SqlServer-2012-Database" {Return "SqlServer2012Database"} 57 | "SqlServer-2012-Instance" {Return "SqlServer2012Instance"} 58 | "SqlServer-2016-Instance" {Return "SqlServer2016Instance"} 59 | "WindowsClient" {Return $Role} 60 | "WindowsDefender" {Return $Role} 61 | "WindowsDNSServer" {Return $Role} 62 | "WindowsFirewall" {Return $Role} 63 | "WindowsServer-DC" {Return "WindowsServerDC"} 64 | "WindowsServer-MS" {Return "WindowsServerMS"} 65 | "GoogleChrome" {Return $Role} 66 | "AdobeAcrobatReaderDCCont" {Return $Role} 67 | "AdobeAcrobatReaderDCClassic" {Return $Role} 68 | } 69 | 70 | } 71 | 72 | 73 | #H02 74 | <# 75 | .SYNOPSIS 76 | Retrieves configuration data from a standard .ini file and returns it as a hashtable 77 | 78 | .DESCRIPTION 79 | Will cycle through each line of a standard .ini and store each configuration pair as a value/key pair in a hashtable 80 | 81 | .PARAMETER configFilePath 82 | Path to the .ini file to be put to a variable 83 | 84 | .EXAMPLE 85 | Import-PowerStigConfig -configFilePath C:\users\test.user\documents\config.ini 86 | #> 87 | function Import-PowerStigConfig 88 | { 89 | [CmdletBinding()] 90 | Param( 91 | [Parameter(Mandatory=$true)] 92 | [ValidateNotNullorEmpty()] 93 | [String]$configFilePath 94 | ) 95 | 96 | $configDataText = Get-Content $configFilePath 97 | $variables = @{} 98 | 99 | # Cycle through each part of the config.ini file 100 | foreach($c in $configDataText) 101 | { 102 | # Split String at the "=", Left is config name, right is config setting, ignore lines with "[" and ";" 103 | $splitVar = [regex]::split($c,'=') 104 | if(($splitVar[0].CompareTo("") -ne 0) -and ($splitVar[0].StartsWith("[") -ne $True) -and ($splitVar[0].StartsWith(";") -ne $True)) 105 | { 106 | $variables.Add($splitVar[0].trim(), $splitVar[1].trim()) | out-null 107 | } # End if 108 | } # End foreach 109 | 110 | # Return hashtable of config data 111 | Return $variables 112 | } # End Import-PowerStigConfig 113 | 114 | #H03 115 | function Invoke-PowerStigSqlCommand 116 | { 117 | [cmdletBinding()] 118 | param( 119 | [Parameter(Mandatory=$true)] 120 | [ValidateNotNullorEmpty()] 121 | [String]$Query, 122 | 123 | [Parameter(Mandatory=$false)] 124 | [String]$SqlInstance, 125 | 126 | [Parameter(Mandatory=$false)] 127 | [String]$DatabaseName 128 | ) 129 | 130 | $workingPath = Split-Path $PsCommandPath 131 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 132 | 133 | if($SqlInstance -eq $null -or $SqlInstance -eq '') 134 | { 135 | $SqlInstance = $iniVar.SqlInstanceName 136 | } 137 | if($DatabaseName -eq $null -or $DatabaseName -eq '') 138 | { 139 | $DatabaseName = $iniVar.DatabaseName 140 | } 141 | 142 | $SqlConnection = New-Object System.Data.SqlClient.SqlConnection 143 | $SqlConnection.ConnectionString = "Server=$SqlInstance;Database=$DatabaseName;Integrated Security=True" 144 | $SqlCmd = New-Object System.Data.SqlClient.SqlCommand 145 | $SqlCmd.CommandText = $Query 146 | $SqlCmd.Connection = $SqlConnection 147 | $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter 148 | $SqlAdapter.SelectCommand = $SqlCmd 149 | $DataSet = New-Object System.Data.DataSet 150 | $SqlAdapter.Fill($DataSet) | Out-Null 151 | $SqlConnection.Close() 152 | 153 | return $DataSet.Tables[0] 154 | } -------------------------------------------------------------------------------- /src/PowerStigScan.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PowerStigScan' 3 | # 4 | # Generated by: Matt Preston 5 | # 6 | # Generated on: 8/7/2018 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'PowerStigScan.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '2.0.1.0' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '453265f6-5529-4e29-9918-7aca081ca986' 22 | 23 | # Author of this module 24 | Author = 'Matt Preston' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'Microsoft' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) 2018 Matt Preston. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'Module to Audit systems using the PowerStig engine. 34 | PowerStigScan Repo: https://github.com/mapresto/PowerStigScan. 35 | PowerStig Repo: https://github.com/Microsoft/PowerStig' 36 | 37 | # Minimum version of the Windows PowerShell engine required by this module 38 | PowerShellVersion = '5.1' 39 | 40 | # Name of the Windows PowerShell host required by this module 41 | # PowerShellHostName = '' 42 | 43 | # Minimum version of the Windows PowerShell host required by this module 44 | # PowerShellHostVersion = '' 45 | 46 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 47 | # DotNetFrameworkVersion = '' 48 | 49 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 50 | # CLRVersion = '' 51 | 52 | # Processor architecture (None, X86, Amd64) required by this module 53 | # ProcessorArchitecture = '' 54 | 55 | # Modules that must be imported into the global environment prior to importing this module 56 | RequiredModules = @( 57 | @{ModuleName = 'AuditPolicyDsc'; ModuleVersion = '1.2.0.0'}, 58 | @{ModuleName = 'AccessControlDsc'; ModuleVersion = '1.4.0.0'}, 59 | @{ModuleName = 'ComputerManagementDsc'; ModuleVersion = '6.2.0.0'} 60 | @{ModuleName = 'FileContentDsc'; ModuleVersion = '1.1.0.108'}, 61 | @{ModuleName = 'PolicyFileEditor'; ModuleVersion = '3.0.1'}, 62 | @{ModuleName = 'PSDscResources'; ModuleVersion = '2.10.0.0'} 63 | @{ModuleName = 'SecurityPolicyDsc'; ModuleVersion = '2.4.0.0'}, 64 | @{ModuleName = 'SqlServerDsc'; ModuleVersion = '12.1.0.0'}, 65 | @{ModuleName = 'WindowsDefenderDsc'; ModuleVersion = '1.0.0.0'}, 66 | @{ModuleName = 'xDnsServer'; ModuleVersion = '1.11.0.0'}, 67 | @{ModuleName = 'xWebAdministration'; ModuleVersion = '2.5.0.0'}, 68 | @{ModuleName = 'PowerStig'; ModuleVersion = '3.2.0'} 69 | 70 | ) 71 | 72 | # Assemblies that must be loaded prior to importing this module 73 | # RequiredAssemblies = @() 74 | 75 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 76 | # ScriptsToProcess = @() 77 | 78 | # Type files (.ps1xml) to be loaded when importing this module 79 | # TypesToProcess = @() 80 | 81 | # Format files (.ps1xml) to be loaded when importing this module 82 | # FormatsToProcess = @() 83 | 84 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 85 | # NestedModules = @() 86 | 87 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 88 | FunctionsToExport = @( 89 | 'Invoke-PowerStigScan', 90 | 'Add-PowerStigComputer', 91 | 'Get-PowerStigComputer', 92 | 'Remove-PowerStigComputer', 93 | 'Get-PowerStigSqlConfig', 94 | 'Set-PowerStigSqlConfig', 95 | 'Get-PowerStigConfig', 96 | 'Set-PowerStigConfig', 97 | 'Get-PowerStigOrgSettings', 98 | 'Start-PowerStigDSCScan', 99 | 'Install-PowerStigSQLDatabase' 100 | ) 101 | 102 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 103 | CmdletsToExport = @() 104 | 105 | # Variables to export from this module 106 | VariablesToExport = @() 107 | 108 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 109 | AliasesToExport = '*' 110 | 111 | # DSC resources to export from this module 112 | # DscResourcesToExport = @() 113 | 114 | # List of all modules packaged with this module 115 | # ModuleList = @() 116 | 117 | # List of all files packaged with this module 118 | # FileList = @() 119 | 120 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 121 | PrivateData = @{ 122 | 123 | PSData = @{ 124 | 125 | # Tags applied to this module. These help with module discovery in online galleries. 126 | # Tags = @() 127 | 128 | # A URL to the license for this module. 129 | # LicenseUri = '' 130 | 131 | # A URL to the main website for this project. 132 | # ProjectUri = '' 133 | 134 | # A URL to an icon representing this module. 135 | # IconUri = '' 136 | 137 | # ReleaseNotes of this module 138 | ReleaseNotes = 'Added support for PowerSTIG 3.2.0 139 | Consolidated file management for key files used 140 | Consolidated scanning functions to a single function 141 | Added additional, optional integration with SCAP 142 | Removed dependency on SQL for bulk scan and CKL generation 143 | Added switches to make SQL and SCAP optional components 144 | Added Install-PowerStigSQLDatabase to ease the creation of SQL objects 145 | Added detection for PowerShell 5.1 146 | Fixed issues preventing .Net SCAP scan from proceding 147 | Added support to automatically set Non-Applicable rules for 2016 STIG to NA' 148 | 149 | } # End of PSData hashtable 150 | 151 | } # End of PrivateData hashtable 152 | 153 | # HelpInfo URI of this module 154 | # HelpInfoURI = '' 155 | 156 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 157 | # DefaultCommandPrefix = '' 158 | 159 | } -------------------------------------------------------------------------------- /src/SQL/499.sql: -------------------------------------------------------------------------------- 1 | -- =============================================================================================== 2 | -- =============================================================================================== 3 | -- Purpose: Deployment script for PowerSTIG database objects 4 | -- Revisions: 5 | -- =============================================================================================== 6 | -- =============================================================================================== 7 | /* 8 | Copyright (C) 2019 Microsoft Corporation 9 | Disclaimer: 10 | This is SAMPLE code that is NOT production ready. It is the sole intention of this code to provide a proof of concept as a 11 | learning tool for Microsoft Customers. Microsoft does not provide warranty for or guarantee any portion of this code 12 | and is NOT responsible for any affects it may have on any system it is executed on or environment it resides within. 13 | Please use this code at your own discretion! 14 | Additional legalize: 15 | This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment. 16 | THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 17 | INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 18 | We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute 19 | the object code form of the Sample Code, provided that You agree: 20 | (i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code is embedded; 21 | (ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded; and 22 | (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits, including attorneys� fees, 23 | that arise or result from the use or distribution of the Sample Code. 24 | */ 25 | -- =============================================================================================== 26 | -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 27 | -- =============================================================================================== 28 | SET NOCOUNT ON 29 | DECLARE @StepName varchar(256) 30 | DECLARE @StepMessage varchar(768) 31 | DECLARE @ErrorMessage varchar(2000) 32 | DECLARE @ErrorSeverity tinyint 33 | DECLARE @ErrorState tinyint 34 | DECLARE @StepAction varchar(25) 35 | DECLARE @UpdateVersion smallint 36 | DECLARE @CurrentVersion smallint 37 | SET @UpdateVersion = 499 38 | -- =============================================================================================== 39 | -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 40 | -- =============================================================================================== 41 | -- 42 | IF OBJECT_ID('PowerSTIG.DBversion') IS NOT NULL 43 | BEGIN 44 | IF EXISTS (SELECT VersionID FROM PowerSTIG.DBversion WHERE UpdateVersion = @UpdateVersion AND isActive = 1) 45 | BEGIN 46 | SET @StepMessage = 'Update version ['+CAST(@UpdateVersion as varchar(5))+'] already applied. This is an informational message only.' 47 | SET @StepAction = 'DEPLOY' 48 | PRINT @StepMessage 49 | -- 50 | EXEC PowerSTIG.sproc_InsertScanLog 51 | @LogEntryTitle = @StepName 52 | ,@LogMessage = @StepMessage 53 | ,@ActionTaken = @StepAction 54 | -- 55 | -- Bail out of this script. Already applied. 56 | SELECT 8675309 AS UpdateApplied; 57 | THROW 8675309, 'Database update previously applied. This is an informational message only.', 1 58 | END 59 | END 60 | -- =============================================================================================== 61 | PRINT '///////////////////////////////////////////////////////' 62 | PRINT 'PowerStigScan database object deployment start - '+CONVERT(VARCHAR,GETDATE(), 21) 63 | PRINT '\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' 64 | -- =============================================================================================== 65 | DROP TABLE IF EXISTS __PowerStigDBdeployVersion 66 | -- 67 | CREATE TABLE __PowerStigDBdeployVersion (UpdateVersion smallint,CurrentVersion smallint) 68 | -- 69 | INSERT INTO __PowerStigDBdeployVersion (UpdateVersion,CurrentVersion) VALUES (@UpdateVersion,NULL) 70 | -- =============================================================================================== 71 | -- Create schema 72 | -- =============================================================================================== 73 | -- 74 | PRINT 'Begin create schema' 75 | -- 76 | IF NOT EXISTS (SELECT name FROM sys.schemas WHERE name = 'PowerSTIG') 77 | EXEC('CREATE SCHEMA [PowerSTIG] AUTHORIZATION [dbo]'); 78 | -- 79 | PRINT 'End create schema' 80 | GO 81 | -- =============================================================================================== 82 | -- Create logging and versioning tables 83 | -- =============================================================================================== 84 | IF OBJECT_ID('PowerSTIG.DBversion') IS NULL 85 | -- 86 | CREATE TABLE PowerSTIG.DBversion ( 87 | VersionID smallint IDENTITY(1,1) NOT NULL PRIMARY KEY, 88 | UpdateVersion smallint NOT NULL DEFAULT(0), 89 | VersionTS datetime NOT NULL DEFAULT(GETDATE()), 90 | isActive INT NOT NULL, 91 | VersionNotes varchar(MAX) NULL) 92 | -- 93 | IF OBJECT_ID('PowerSTIG.ScanLog') IS NULL 94 | -- 95 | CREATE TABLE PowerSTIG.ScanLog ( 96 | LogTS datetime NOT NULL DEFAULT(GETDATE()), 97 | LogEntryTitle varchar(128) NULL, 98 | LogMessage varchar(2000) NULL, 99 | ActionTaken varchar(25) NULL CONSTRAINT check_ActionTaken CHECK (ActionTaken IN ('INSERT','UPDATE','DELETE','DEPLOY','ERROR','START','FINISH')), 100 | LoggedUser varchar(50) NULL DEFAULT(SUSER_NAME())) 101 | -- 102 | GO 103 | CREATE OR ALTER PROCEDURE PowerSTIG.sproc_InsertScanLog 104 | @LogEntryTitle varchar(128)=NULL, 105 | @LogMessage varchar(1000)=NULL, 106 | @ActionTaken varchar(25)=NULL 107 | AS 108 | SET NOCOUNT ON 109 | --------------------------------------------------------------------------------- 110 | -- The sample scripts are not supported under any Microsoft standard support 111 | -- program or service. The sample scripts are provided AS IS without warranty 112 | -- of any kind. Microsoft further disclaims all implied warranties including, 113 | -- without limitation, any implied warranties of merchantability or of fitness for 114 | -- a particular purpose. The entire risk arising out of the use or performance of 115 | -- the sample scripts and documentation remains with you. In no event shall 116 | -- Microsoft, its authors, or anyone else involved in the creation, production, or 117 | -- delivery of the scripts be liable for any damages whatsoever (including, 118 | -- without limitation, damages for loss of business profits, business interruption, 119 | -- loss of business information, or other pecuniary loss) arising out of the use 120 | -- of or inability to use the sample scripts or documentation, even if Microsoft 121 | -- has been advised of the possibility of such damages 122 | --------------------------------------------------------------------------------- 123 | -- =============================================================================================== 124 | -- Purpose: 125 | -- Revisions: 126 | -- 07162018 - Kevin Barlett, Microsoft - Initial creation. 127 | -- =============================================================================================== 128 | -- 129 | DECLARE @ErrorMessage varchar(2000) 130 | DECLARE @ErrorSeverity tinyint 131 | DECLARE @ErrorState tinyint 132 | DECLARE @LoggedUser varchar(50) 133 | DECLARE @LogTS datetime 134 | SET @LoggedUser = (SELECT SUSER_NAME() AS LoggedUser) 135 | SET @LogTS = (SELECT GETDATE() AS LogTS) 136 | -- 137 | BEGIN TRY 138 | INSERT INTO 139 | PowerSTIG.ScanLog (LogTS,LogEntryTitle,LogMessage,ActionTaken,LoggedUser) 140 | VALUES 141 | ( 142 | @LogTS, 143 | @LogEntryTitle, 144 | @LogMessage, 145 | @ActionTaken, 146 | @LoggedUser 147 | ) 148 | END TRY 149 | BEGIN CATCH 150 | SET @ErrorMessage = ERROR_MESSAGE() 151 | SET @ErrorSeverity = ERROR_SEVERITY() 152 | SET @ErrorState = ERROR_STATE() 153 | RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState) 154 | END CATCH 155 | GO 156 | -- =============================================================================================== 157 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 158 | -- Logging 159 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 160 | -- =============================================================================================== 161 | DECLARE @StepName varchar(256) 162 | DECLARE @StepMessage varchar(768) 163 | DECLARE @ErrorMessage varchar(2000) 164 | DECLARE @ErrorSeverity tinyint 165 | DECLARE @ErrorState tinyint 166 | DECLARE @StepAction varchar(25) 167 | DECLARE @UpdateVersion SMALLINT 168 | DECLARE @CurrentVersion smallint 169 | SET @UpdateVersion = (SELECT TOP 1 UpdateVersion FROM __PowerStigDBdeployVersion) 170 | --SET @CurrentVersion = (SELECT TOP 1 CurrentVersion FROM __PowerStigDBdeployVersion) 171 | SET @StepMessage = 'Update version ['+CAST(@UpdateVersion as varchar(5))+'] successfully applied. This is an informational message only.' 172 | SET @StepAction = 'DEPLOY' 173 | --PRINT @StepMessage 174 | -- 175 | EXEC PowerSTIG.sproc_InsertScanLog 176 | @LogEntryTitle = @StepName 177 | ,@LogMessage = @StepMessage 178 | ,@ActionTaken = @StepAction 179 | -- 180 | INSERT INTO 181 | PowerSTIG.DBversion (UpdateVersion,VersionTS,isActive,VersionNotes) 182 | VALUES 183 | (@UpdateVersion,GETDATE(),1,NULL) 184 | 185 | -- =============================================================================================== 186 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 187 | -- =============================================================================================== 188 | DROP TABLE IF EXISTS __PowerStigDBdeployVersion 189 | -- =============================================================================================== 190 | PRINT '///////////////////////////////////////////////////////' 191 | PRINT 'PowerStigScan database object deployment complete - '+CONVERT(VARCHAR,GETDATE(), 21) 192 | PRINT '\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' 193 | -- =============================================================================================== -------------------------------------------------------------------------------- /src/Common/DSCCall.ps1: -------------------------------------------------------------------------------- 1 | # Consolidated resource for MOF generation 2 | # IISObject must include WebsiteName + WebAppPool - Get-Website -> foreach($i in $sites) {(inv-cmd -comp $serv -scr {get-website $i}).applicationpool} 3 | # SQLObject must include SqlVersion, SqlRole, ServerInstance, Database 4 | 5 | param( 6 | 7 | [Parameter(Mandatory=$true,Position=0)] 8 | [String] 9 | $ComputerName, 10 | 11 | [Parameter(Mandatory=$false)] 12 | [ValidateSet("2012R2","2016",'10')] 13 | [String] 14 | $OsVersion, 15 | 16 | [Parameter(Mandatory=$true)] 17 | [ValidateNotNullorEmpty()] 18 | [String] 19 | $OrgSettingsFilePath, 20 | 21 | [Parameter(Mandatory=$false)] 22 | [String[]] 23 | $SkipRules, 24 | 25 | [Parameter(Mandatory=$true)] 26 | [ValidateNotNullorEmpty()] 27 | [String] 28 | $LogPath 29 | 30 | ) 31 | 32 | DynamicParam { 33 | $ParameterName = 'Role' 34 | $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary 35 | $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] 36 | $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute 37 | $ParameterAttribute.Mandatory = $true 38 | $AttributeCollection.Add($ParameterAttribute) 39 | $roleSet = @(Import-CSV "$(Split-Path $PsCommandPath)\Roles.csv" -Header Role | Select-Object -ExpandProperty Role) 40 | $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($roleSet) 41 | $AttributeCollection.Add($ValidateSetAttribute) 42 | $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string[]], $AttributeCollection) 43 | $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) 44 | return $RuntimeParameterDictionary 45 | } 46 | 47 | 48 | Begin 49 | { 50 | #Bound the dynamic parameter to a new Variable 51 | $Role = $PSBoundParameters[$ParameterName] 52 | } 53 | 54 | process 55 | { 56 | 57 | if($null -ne $LogPath -and $LogPath -ne "") 58 | { 59 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Starting mof generation for $ComputerName" 60 | } 61 | 62 | Configuration PowerSTIG 63 | { 64 | Import-DscResource -ModuleName PowerStig -ModuleVersion 3.2.0 65 | 66 | Node $ComputerName 67 | { 68 | # Org Settings will always be passed. Log file will be used. 69 | # Question will be if skip rule will be 70 | # if Skip rule is not empty/null do 1 else do 2 71 | Switch($Role){ 72 | "WindowsServer-DC" { 73 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding DomainController Configuration" 74 | WindowsServer DomainController 75 | { 76 | OsVersion = $OsVersion 77 | OsRole = 'DC' 78 | StigVersion = (Get-PowerStigXMLVersion -Role "WindowsServer-DC" -OSVersion $osVersion) 79 | OrgSettings = $OrgSettingsFilePath 80 | } 81 | 82 | } 83 | "WindowsDNSServer" { 84 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding DNS Configuration" 85 | WindowsDnsServer DNS 86 | { 87 | OsVersion = $OsVersion 88 | StigVersion = (Get-PowerStigXMLVersion -Role "WindowsDNSServer" -OSVersion $osVersion) 89 | OrgSettings = $OrgSettingsFilePath 90 | } 91 | } 92 | "WindowsServer-MS" { 93 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding MemberServer Configuration" 94 | WindowsServer MemberServer 95 | { 96 | OsVersion = $OsVersion 97 | OsRole = 'MS' 98 | StigVersion = (Get-PowerStigXMLVersion -Role "WindowsServer-MS" -OSVersion $osVersion) 99 | OrgSettings = $OrgSettingsFilePath 100 | } 101 | } 102 | "InternetExplorer" { 103 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding InternetExplorer Configuration" 104 | InternetExplorer IE 105 | { 106 | BrowserVersion = '11' 107 | StigVersion = (Get-PowerStigXMLVersion -Role "InternetExplorer") 108 | OrgSettings = $OrgSettingsFilePath 109 | } 110 | } 111 | "WindowsFirewall" { 112 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding FireWall Configuration" 113 | WindowsFirewall Firewall 114 | { 115 | StigVersion = (Get-PowerStigXMLVersion -Role "WindowsFirewall") 116 | OrgSettings = $OrgSettingsFilePath 117 | } 118 | } 119 | "WindowsClient" { 120 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding Windows10 Configuration" 121 | WindowsClient Client 122 | { 123 | OsVersion = '10' 124 | StigVersion = (Get-PowerStigXMLVersion -Role "WindowsClient" -OSVersion "10") 125 | OrgSettings = $OrgSettingsFilePath 126 | } 127 | } 128 | "OracleJRE" { 129 | #continue until this is finalized - must find config and properties path 130 | Return 131 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding OracleJRE Configuration" 132 | OracleJRE JRE 133 | { 134 | ConfigPath = $ConfigPath 135 | PropertiesPath = $PropertiesPath 136 | StigVersion = (Get-PowerStigXMLVersion -Role "OracleJRE") 137 | OrgSettings = $OrgSettingsFilePath 138 | } 139 | } 140 | "IISServer" { 141 | #continue until this is finalized - must find app pool website relationships 142 | Return 143 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding IIS Configuration" 144 | IisServer IIS-Server-$ComputerName 145 | { 146 | StigVersion = (Get-PowerStigXMLVersion -Role "IISServer") 147 | OrgSettings = $OrgSettingsFilePath 148 | } 149 | IisSite IIS-Site-$WebsiteName 150 | { 151 | WebsiteName = $WebsiteName 152 | WebAppPool = $WebAppPool 153 | StigVersion = (Get-PowerStigXMLVersion -Role "IISSite") 154 | OrgSettings = $OrgSettingsFilePath 155 | } 156 | } 157 | "SqlServer-2012-Database" { 158 | #continue until finalized, must find instance and database relationships 159 | Return 160 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding SQL Configuration" 161 | SqlServer Sql-$Database 162 | { 163 | SqlVersion = $SqlVersion 164 | SqlRole = $SqlRole 165 | ServerInstance = $SqlInstance 166 | Database = $Database 167 | StigVersion = (Get-PowerStigXMLVersion -Role "SqlServer-2012-Database") 168 | OrgSettings = $OrgSettingsFilePath 169 | } 170 | } 171 | "Outlook2013" { 172 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding Outlook2013 Configuration" 173 | Office Outlook 174 | { 175 | OfficeApp = "Outlook2013" 176 | StigVersion = (Get-PowerStigXMLVersion -Role "Outlook2013") 177 | OrgSettings = $OrgSettingsFilePath 178 | } 179 | } 180 | "PowerPoint2013"{ 181 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding PowerPoint2013 Configuration" 182 | Office PowerPoint 183 | { 184 | OfficeApp = "PowerPoint2013" 185 | StigVersion = (Get-PowerStigXMLVersion -Role "PowerPoint2013") 186 | OrgSettings = $OrgSettingsFilePath 187 | } 188 | } 189 | "Excel2013" { 190 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding Excel2013 Configuration" 191 | Office Excel 192 | { 193 | OfficeApp = "Excel2013" 194 | StigVersion = (Get-PowerStigXMLVersion -Role "Excel2013") 195 | OrgSettings = $OrgSettingsFilePath 196 | } 197 | } 198 | "Word2013" { 199 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding Word2013 Configuration" 200 | Office Word 201 | { 202 | OfficeApp = "Word2013" 203 | StigVersion = (Get-PowerStigXMLVersion -Role "Word2013") 204 | OrgSettings = $OrgSettingsFilePath 205 | } 206 | } 207 | "FireFox" { 208 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding FireFox Configuration" 209 | 210 | try 211 | { 212 | $installDirectory = (Get-PowerStigFireFoxDirectory -ServerName $ComputerName) 213 | } 214 | catch 215 | { 216 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$ComputerName][FireFoxDSC][ERROR]:$_" 217 | Return 218 | } 219 | 220 | if($null -eq $installDirectory -or $installDirectory -eq "") 221 | { 222 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$ComputerName][FireFoxDSC][ERROR]:Could not find FireFox install directory." 223 | Return 224 | } 225 | 226 | FireFox Firefox 227 | { 228 | StigVersion = (Get-PowerStigXMLVersion -Role "FireFox") 229 | InstallDirectory = $installDirectory 230 | OrgSettings = $OrgSettingsFilePath 231 | } 232 | } 233 | "DotNetFramework" { 234 | Add-Content -Path $LogPath -Value "$(Get-Time):[$ComputerName][Info]: Adding DotNet Configuration" 235 | DotNetFramework DotNet 236 | { 237 | FrameworkVersion = 'DotNet4' 238 | StigVersion = (Get-PowerStigXMLVersion -Role "DotNetFramework") 239 | OrgSettings = $OrgSettingsFilePath 240 | } 241 | } 242 | } 243 | 244 | } 245 | } 246 | 247 | PowerSTIG 248 | } -------------------------------------------------------------------------------- /src/SQL/DBdeployer.ps1: -------------------------------------------------------------------------------- 1 | # ================================================================================================================= 2 | # Purpose: 3 | # Revisions: 4 | # 05242019 - Kevin Barlett, Microsoft - Initial creation. 5 | # 6 | # ================================================================================================================= 7 | # ----------------------------------------------------------------------------- 8 | # 9 | # Copyright (C) 2019 Microsoft Corporation 10 | # 11 | # Disclaimer: 12 | # This is SAMPLE code that is NOT production ready. It is the sole intention of this code to provide a proof of concept as a 13 | # learning tool for Microsoft Customers. Microsoft does not provide warranty for or guarantee any portion of this code 14 | # and is NOT responsible for any affects it may have on any system it is executed on or environment it resides within. 15 | # Please use this code at your own discretion! 16 | # Additional legalese: 17 | # This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment. 18 | # THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 19 | # INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 20 | # We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute 21 | # the object code form of the Sample Code, provided that You agree: 22 | # (i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code is embedded; 23 | # (ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded; and 24 | # (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits, including attorneys' fees, 25 | # that arise or result from the use or distribution of the Sample Code. 26 | # ----------------------------------------------------------------------------- 27 | param( 28 | [CmdletBinding()] 29 | [Parameter(ParameterSetName='Set1',Position=0,Mandatory=$true)][String]$DBserverName, 30 | [parameter(ParameterSetName='Set1',Position=1,Mandatory=$true)][String]$DatabaseName 31 | # [parameter(ParameterSetName='Set2',Position=2,Mandatory=$true)][String[]]$serverList 32 | ) 33 | $Timestamp = (get-date).ToString("MMddyyyyHHmmss") 34 | $CurTime = get-date 35 | $LogFile = ".\DBdeployLog_$Timestamp.txt" 36 | #======================================================================== 37 | # Create logging function 38 | #======================================================================== 39 | function log($string, $color) 40 | { 41 | if ($null -eq $color) {$color = "white"} 42 | #write-host $string -foregroundcolor $color 43 | $string | out-file -Filepath $logfile -append 44 | } 45 | $HeaderMessage = " 46 | /////////////////////////////////////////////////////////////////////////////// 47 | \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 48 | PowerSTIGscan Database Installer - v0.1 49 | $CurTime 50 | /////////////////////////////////////////////////////////////////////////////// 51 | \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 52 | " #-foregroundcolor "Red" 53 | Write-Host $HeaderMessage -ForegroundColor Green 54 | Log $HeaderMessage 55 | #$UserContext = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name 56 | #$ServerName = $(Get-Content env:computername) 57 | #======================================================================== 58 | #Scrub inputs 59 | #======================================================================== 60 | $DBServerName = $DBServerName.trim() 61 | # 62 | $DatabaseName = $DatabaseName.trim() 63 | #======================================================================== 64 | #Perform test connection 65 | #======================================================================== 66 | If (Test-Connection $DBServerName -count 1 -quiet) 67 | { 68 | $CurTime = get-date 69 | [console]::ForegroundColor = "Green" 70 | $LogMessage = "---> Servername $DBServerName appears to be valid. Continuing. . ." 71 | Write-Host $LogMessage 72 | [console]::ResetColor() 73 | # 74 | log [$CurTime]$LogMessage 75 | } 76 | Else 77 | { 78 | $CurTime = get-date 79 | [console]::ForegroundColor = "Red" 80 | $LogMessage = "---> Servername $DBServerName appears to be invalid or the server is unavailable. Please validate the specified SQL Server name. Exiting." 81 | Write-Host $LogMessage 82 | [console]::ResetColor() 83 | # 84 | log [$CurTime]$LogMessage 85 | EXIT 86 | } 87 | #======================================================================== 88 | #Validate database existence 89 | #======================================================================== 90 | $CurTime = get-date 91 | [console]::ForegroundColor = "Green" 92 | $LogMessage = "---> Checking for the existence of database [$DatabaseName]" 93 | Write-Host $LogMessage 94 | [console]::ResetColor() 95 | # 96 | log [$CurTime]$LogMessage 97 | 98 | $DBexistsQuery = "SELECT 1 AS DatabaseExists FROM sys.databases 99 | where [name] = '$DatabaseName' and [state] = 0 and is_read_only = 0" 100 | $SqlConnection = New-Object System.Data.SqlClient.SqlConnection 101 | $SqlConnection.ConnectionString = "Server=$DBServerName;Database=master;Integrated Security=True" 102 | $SqlCmd = New-Object System.Data.SqlClient.SqlCommand 103 | $SqlCmd.CommandText = $DBexistsQuery 104 | $SqlCmd.Connection = $SqlConnection 105 | $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter 106 | $SqlAdapter.SelectCommand = $SqlCmd 107 | $DataSet = New-Object System.Data.DataSet 108 | [void]$SqlAdapter.Fill($DataSet) 109 | $SqlConnection.Close() 110 | 111 | $DBexists = $DataSet.Tables[0] | Select-Object DatabaseExists -ExpandProperty DatabaseExists 112 | 113 | 114 | if ($DBexists -ne 1) 115 | { 116 | $CurTime = get-date 117 | [console]::ForegroundColor = "Yellow" 118 | $LogMessage = "---> Specified database [$DatabaseName] was not found. Creating database [$DatabaseName] now." 119 | Write-Host $LogMessage 120 | [console]::ResetColor() 121 | # 122 | log [$CurTime]$LogMessage 123 | 124 | try 125 | { 126 | $CreateDatabaseQuery = " 127 | DECLARE @DatabaseName varchar(256) 128 | SET @DatabaseName = '$DatabaseName' 129 | DECLARE @DefaultDataLoc varchar(256) 130 | DECLARE @DefaultLogLoc varchar(256) 131 | DECLARE @SQLCMD varchar(MAX) 132 | SELECT 133 | @DefaultDataLoc = CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS varchar(256)), 134 | @DefaultLogLoc = CAST(SERVERPROPERTY('InstanceDefaultLogPath') AS varchar(256)) 135 | 136 | -- 137 | SET @SQLCMD = 'CREATE DATABASE ['+@DatabaseName+'] ON PRIMARY (NAME = '''+@DatabaseName+'_data'', FILENAME = '''+@DefaultDataLoc+''+@DatabaseName+'_data.mdf'' , SIZE = 128MB , MAXSIZE = UNLIMITED, FILEGROWTH = 128MB) LOG ON (NAME = '''+@DatabaseName+'_log'', FILENAME = '''+@DefaultLogLoc+''+@DatabaseName+'_log.ldf'' , SIZE = 128MB , MAXSIZE = 2048GB , FILEGROWTH =128MB)' 138 | --PRINT @SQLCMD 139 | EXEC(@SQLCMD) 140 | -- 141 | SET @SQLCMD = 'ALTER DATABASE ['+@DatabaseName+'] SET RECOVERY SIMPLE' 142 | --PRINT @SQLCMD 143 | EXEC(@SQLCMD) 144 | -- 145 | SET @SQLCMD = 'ALTER DATABASE ['+@DatabaseName+'] SET PAGE_VERIFY CHECKSUM' 146 | --PRINT @SQLCMD 147 | EXEC(@SQLCMD) 148 | " 149 | $SqlConnection = New-Object System.Data.SqlClient.SqlConnection 150 | $SqlConnection.ConnectionString = "Server=$DBServerName;Database=master;Integrated Security=True" 151 | $SqlCmd = New-Object System.Data.SqlClient.SqlCommand 152 | $SqlCmd.CommandText = $CreateDatabaseQuery 153 | $SqlCmd.Connection = $SqlConnection 154 | $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter 155 | $SqlAdapter.SelectCommand = $SqlCmd 156 | $DataSet = New-Object System.Data.DataSet 157 | [void]$SqlAdapter.Fill($DataSet) 158 | $SqlConnection.Close() 159 | 160 | $CurTime = get-date 161 | [console]::ForegroundColor = "Green" 162 | $LogMessage = "---> Database [$DatabaseName] created successfully." 163 | Write-Host $LogMessage 164 | [console]::ResetColor() 165 | # 166 | log [$CurTime]$LogMessage 167 | } 168 | catch 169 | { 170 | 171 | $CurTime = get-date 172 | [console]::ForegroundColor = "Red" 173 | $LogMessage = "---> An error was encountered while creating database [$DatabaseName]. Please investigate." 174 | Write-Host $LogMessage 175 | [console]::ResetColor() 176 | # 177 | log [$CurTime]$LogMessage 178 | 179 | 180 | } 181 | } 182 | 183 | else 184 | { 185 | $CurTime = get-date 186 | [console]::ForegroundColor = "Green" 187 | $LogMessage = "---> The specified database [$DatabaseName] already exists. PowerSTIGscan deployment continuing." 188 | Write-Host $LogMessage 189 | [console]::ResetColor() 190 | # 191 | log [$CurTime]$LogMessage 192 | } 193 | 194 | 195 | #======================================================================== 196 | #Execute deployment scripts 197 | #======================================================================== 198 | $DeployScripts = Get-ChildItem "$(Split-Path $PsCommandPath)\" | Where-Object {$_.Extension -eq ".sql"} | Sort-Object Name 199 | 200 | foreach ($Script in $DeployScripts) 201 | { 202 | try { 203 | 204 | 205 | Write-Host "Executing Script: " $Script.Name -BackgroundColor DarkGreen -ForegroundColor White 206 | $script = $Script.FullName 207 | #write-host $script 208 | 209 | $DatabaseScript = Get-Content $Script | Out-String 210 | $ScriptBatches = $DatabaseScript -split "GO\r\n" 211 | foreach ($Batch in $ScriptBatches) 212 | { 213 | $SqlConnection = New-Object System.Data.SqlClient.SqlConnection 214 | $SqlConnection.ConnectionString = "Server=$DBServerName;Database=$DatabaseName;Integrated Security=True" 215 | $SqlCmd = New-Object System.Data.SqlClient.SqlCommand 216 | $SqlCmd.CommandText = $Batch; 217 | $SqlCmd.Connection = $SqlConnection 218 | $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter 219 | $SqlAdapter.SelectCommand = $SqlCmd 220 | $DataSet = New-Object System.Data.DataSet 221 | [void]$SqlAdapter.Fill($DataSet) 222 | #$SqlAdapter.Fill($DataSet) | Out-Null 223 | $SqlConnection.Close() 224 | 225 | } 226 | $CurTime = get-date 227 | [console]::ForegroundColor = "Green" 228 | $LogMessage = "---> Script [$script] executed successfully." 229 | #Write-Host $LogMessage 230 | [console]::ResetColor() 231 | # 232 | log [$CurTime]$LogMessage 233 | # 234 | Write-Host "Execution successful for script: " $Script.Name -BackgroundColor DarkGreen -ForegroundColor White 235 | } 236 | catch 237 | { 238 | $UpdateApplied = $DataSet.Tables[0] | Select-Object UpdateApplied -ExpandProperty UpdateApplied 239 | if ($UpdateApplied -eq 8675309){ 240 | 241 | $CurTime = get-date 242 | $LogMessage = "---> Database update previously applied. This is an informational message only." 243 | log [$CurTime]$LogMessage 244 | Write-Host $LogMessage -BackgroundColor Yellow -ForegroundColor Black 245 | } 246 | else 247 | { 248 | $CurTime = get-date 249 | [console]::ForegroundColor = "Green" 250 | $LogMessage = "---> Error encountered executing script [$script]. Please investigate." 251 | #Write-Host $LogMessage 252 | [console]::ResetColor() 253 | # 254 | log [$CurTime]$LogMessage 255 | #log [$CurTime]$PSItem 256 | log [$CurTime]$_ 257 | # 258 | Write-Host "Error encountered executing script: " $Script.Name -BackgroundColor Red -ForegroundColor White 259 | 260 | } 261 | } 262 | } -------------------------------------------------------------------------------- /src/Common/PowerStigScan.Results.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Functions: 3 | Private: 4 | R01 - Update-PowerStigCKL 5 | R02 - Set-PowerStigResultHashTable 6 | R03 - Get-PowerStigFindings 7 | R04 - Convert-PowerStigTest 8 | R05 - Import-PowerStigObject 9 | Public: 10 | R06 - New-PowerStigCKL 11 | #> 12 | 13 | #region Private 14 | 15 | #R01 16 | <# 17 | .SYNOPSIS 18 | Queries SQL for results based on date to generate .ckl file 19 | 20 | .DESCRIPTION 21 | Queries SQL for results based on date, if no date is given then the most recent results will be returned. 22 | This uses a blank .CKL file as a base to generate a new file. 23 | 24 | .PARAMETER Role 25 | Type of CKL file that is to be generated such as DC for Domain Controller 26 | 27 | .PARAMETER osVersion 28 | Current version of Operating System that is being used on the target server 29 | 30 | .PARAMETER TargetServerName 31 | Name of the Server that was previously tested 32 | 33 | .PARAMETER sqlInstance 34 | Database instance holding the powerstig database 35 | 36 | .PARAMETER OutPath 37 | Location that the ckl file will be saved. Directory will be created if needed. 38 | 39 | .EXAMPLE 40 | Update-PowerStigCkl -Role DC -osVersion 2012R2 -TargetServerName TestDC1 -sqlInstance SqlTest,49314 -outPath C:\ckl\thisckl.ckl 41 | 42 | .NOTES 43 | General notes 44 | #> 45 | function Update-PowerStigCkl 46 | { 47 | [CmdletBinding()] 48 | Param( 49 | [Parameter(Mandatory=$true)] 50 | [ValidateSet("2012R2","2016","10","All")] 51 | [String]$osVersion, 52 | 53 | [Parameter(Mandatory=$true)] 54 | [ValidateNotNullorEmpty()] 55 | [String]$ServerName, 56 | 57 | [Parameter(Mandatory=$true)] 58 | [ValidateNotNullorEmpty()] 59 | [String]$Role, 60 | 61 | [Parameter(Mandatory=$true)] 62 | [HashTable]$InputObject, 63 | 64 | [Parameter(Mandatory=$true)] 65 | [HashTable]$SourceHash, 66 | 67 | [Parameter(Mandatory=$false)] 68 | [ValidateNotNullorEmpty()] 69 | [String]$OutPath 70 | ) 71 | 72 | 73 | $workingPath = Split-Path $PsCommandPath 74 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 75 | 76 | if($null -eq $outPath -or $outPath -eq '') 77 | { 78 | $outPath = $iniVar.CKLOutPath 79 | } 80 | 81 | $Timestamp = (get-date).ToString("MMddyyyyHHmmss") 82 | if($Role -notlike "WindowsServer*") 83 | { 84 | $outFileName = $ServerName + "_" + $Role + "_" + $Timestamp + ".ckl" 85 | } 86 | elseif($Role -like "WindowsServer*") 87 | { 88 | $outFileName = $ServerName + "_" + $osVersion + "_" + $Role + "_" + $Timestamp + ".ckl" 89 | } 90 | 91 | # generate file name 92 | If($role -notlike "WindowsServer*" -and $role -notlike "*WindowsDNSServer*") 93 | { 94 | [String]$fileName = $Role + "Empty.ckl" 95 | } 96 | elseif($Role -eq "WindowsDNSServer") 97 | { 98 | [String]$fileName = $osVersion + $role + "Empty.ckl" 99 | } 100 | elseif($Role -like "WindowsServer*") 101 | { 102 | [String]$fileName = $osVersion + $role + "Empty.ckl" 103 | } 104 | 105 | 106 | # Pull CKL to variable 107 | [xml]$CKL = Get-Content -Path "$(Split-Path $psCommandPath)\CKL\$fileName" -Encoding UTF8 108 | # Without this line, Severity_override, severity_justification, comments, etc. will all format incorrectly. 109 | # And will not be able to sort by Category 110 | $CKL.PreserveWhitespace = $true 111 | 112 | # Strictly declare constants that are standard for CKL files 113 | $isNotAFinding = "NotAFinding" 114 | $isFinding = "Open" 115 | $isNull = "Not_Reviewed" 116 | 117 | 118 | ## Each Rule is covered at $ckl.CHECKLIST.STIGS.iSTIG 119 | ## VulnID is under STIGDATA[0].ATTRIBUTE_DATA 120 | ## Finding is under Status 121 | ## Search HashTable for VulnID 122 | foreach($i in $CKL.CHECKLIST.STIGS.iSTIG.Vuln) 123 | { 124 | #initiate variables for current rules being evaluated 125 | $boolNotAFinding = $null 126 | $currentRule = $i.STIG_DATA[0].ATTRIBUTE_DATA 127 | 128 | # $results.$currentRule will return either $true or $false if it exists as a result 129 | $boolNotAFinding = $InputObject.$currentRule 130 | 131 | # if it didn't find a rule, ensure that there is not an entry type like V-####.a 132 | # if there are, evaluate all rules with the same number with a letter suffix and determine if all true 133 | # if there is one false, rule evaluates as false 134 | if($null -eq $boolNotAFinding) 135 | { 136 | $testRule = $InputObject.keys | Where-Object {$_ -like "$currentRule.*"} 137 | if (-not($null -eq $testRule)) 138 | { 139 | $ruleResult = $true 140 | foreach($tRule in $testRule) 141 | { 142 | #if you evaluate one rule as false, output is a finding, break loop 143 | if($InputObject.$tRule -eq $false) 144 | { 145 | $ruleResult = $false 146 | continue 147 | } 148 | } 149 | $boolNotAFinding = $ruleResult 150 | } 151 | } 152 | # Set status field in xml 153 | if($boolNotAFinding -eq $true) 154 | { 155 | $i.STATUS = $isNotAFinding 156 | if($SourceHash."$currentRule" -eq "0") 157 | { 158 | $i.COMMENTS = "Result is from PowerStig" 159 | } 160 | elseif ($SourceHash."$CurrentRule" -eq "1") 161 | { 162 | $i.COMMENTS = "Result is from SCAP" 163 | } 164 | } 165 | elseif($boolNotAFinding -eq $false) 166 | { 167 | $i.STATUS = $isFinding 168 | if($SourceHash."$currentRule" -eq "0") 169 | { 170 | $i.COMMENTS = "Result is from PowerStig" 171 | } 172 | elseif ($SourceHash."$CurrentRule" -eq "1") 173 | { 174 | $i.COMMENTS = "Result is from SCAP" 175 | } 176 | } 177 | elseif($null -eq $boolNotAFinding -and $i.STATUS -ne "Not_Applicable") 178 | { 179 | $i.STATUS = $isNull 180 | } 181 | } 182 | 183 | if(-not(Test-Path -Path $outPath)) 184 | { 185 | New-Item -ItemType Directory -Path $outPath -Force | Out-Null 186 | } 187 | 188 | $CKL.save("$outPath\$outFileName") 189 | 190 | } 191 | 192 | #R02 193 | <# 194 | .SYNOPSIS 195 | Creates and returns a hashtable based on a input object generated from SQL results. 196 | 197 | .DESCRIPTION 198 | This function relies on database output being formated as Finding with type String and InDesiredState as type Boolean 199 | Finding should be in the format V-##### with either four or five numbers and possibly appended by a dot letter. 200 | Returns a hash table that can be easily searched for results 201 | 202 | .PARAMETER inputObject 203 | Object that includes database results, best used with the function Get-PowerStigFindings 204 | #> 205 | function Set-PowerStigResultHashTable 206 | { 207 | [CmdletBinding()] 208 | Param( 209 | [Parameter(Mandatory=$true)] 210 | [ValidateNotNullorEmpty()] 211 | [PSObject]$inputObject 212 | ) 213 | 214 | $hash=@{} 215 | 216 | foreach($i in $inputObject) 217 | { 218 | $hash.add($($i.Finding),$($i.InDesiredState)) 219 | } 220 | 221 | return $hash 222 | } 223 | 224 | Function Set-PowerStigResultHashTableFromObject 225 | { 226 | [CmdletBinding()] 227 | param( 228 | [Parameter(Mandatory=$true)] 229 | [ValidateNotNullorEmpty()] 230 | [PSObject]$InputObject 231 | ) 232 | 233 | $outHash = @{} 234 | $tempHash = @{} 235 | [Regex]$VIDRegex = "V-([1-9}])[0-9]{3}[0-9]?" 236 | 237 | foreach($i in $InputObject) 238 | { 239 | [bool]$tempBool = $i.DesiredState 240 | $tempHash.add($($i.VulnID),$tempBool) 241 | } 242 | 243 | foreach($i in $tempHash.keys) 244 | { 245 | $vID = $VIDRegex.Matches($i).value 246 | 247 | $testRule = $tempHash.keys | Where-Object {$_ -like "$vID.*"} 248 | if($testRule.count -ge 2 -and $outHash.Contains($vID)) 249 | { 250 | Continue 251 | } 252 | if (-not($null -eq $testRule)) 253 | { 254 | $ruleResult = $true 255 | foreach($tRule in $testRule) 256 | { 257 | #if you evaluate one rule as false, output is a finding, break loop 258 | if($tempHash.$tRule -eq $false) 259 | { 260 | $ruleResult = $false 261 | continue 262 | } 263 | } 264 | $outHash.add($vID,$ruleResult) 265 | } 266 | else 267 | { 268 | $outHash.add($i,$($tempHash.$i)) 269 | } 270 | } 271 | 272 | 273 | Return $outHash 274 | } 275 | 276 | #R03 277 | <# 278 | .SYNOPSIS 279 | Retrieves the most recent PowerStig findings from the database and returns the database results. 280 | 281 | .DESCRIPTION 282 | Calls the database to retrieve the PowerStig findings for the target server. Returns two columns; Finding and InDesiredState. 283 | Finding is a type String attribute. InDesiredState is a type Boolean attribute. 284 | Is paired with Set-PowerStigResultHashTable to create a searchable object to generate ckl files. 285 | 286 | .PARAMETER SqlInstance 287 | Target SQL instance that holds the PowerStig database. 288 | If empty, will use the settings configured in the config.ini file located in the modulepath\common filepath 289 | 290 | .PARAMETER DatabaseName 291 | Name of database on server that holds the PowerStig tables 292 | 293 | .PARAMETER ServerName 294 | Name of Server to retrieve results for. 295 | 296 | .EXAMPLE 297 | Get-PowerStigFindings -SqlInstance "SQL2012TEST,49314" -DatabaseName Master -ServerName dc2012test 298 | #> 299 | function Get-PowerStigFindings 300 | { 301 | #Returns Columns Finding, InDesiredState 302 | #Finding is in format V-## - Type String 303 | #InDesiredState is in format True or False - Type Boolean :) 304 | [CmdletBinding()] 305 | Param( 306 | [Parameter(Mandatory=$false)] 307 | [String]$SqlInstance, 308 | 309 | [Parameter(Mandatory=$false)] 310 | [String]$DatabaseName, 311 | 312 | [Parameter(Mandatory=$true)] 313 | [ValidateNotNullorEmpty()] 314 | [String]$ServerName, 315 | 316 | [Parameter(Mandatory=$true)] 317 | [ValidateNotNullorEmpty()] 318 | [String]$GUID 319 | ) 320 | 321 | $workingPath = Split-Path $PsCommandPath 322 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 323 | 324 | if($null -eq $SqlInstance -or $SqlInstance -eq '') 325 | { 326 | $SqlInstance = $iniVar.SqlInstanceName 327 | } 328 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 329 | { 330 | $DatabaseName = $iniVar.DatabaseName 331 | } 332 | 333 | $query = "PowerSTIG.sproc_GetComplianceStateByServer @TargetComputer = '$ServerName', @GUID = '$GUID'" 334 | $Results = Invoke-PowerStigSqlCommand -SqlInstance $SqlInstance -DatabaseName $DatabaseName -Query $query 335 | 336 | Return $Results 337 | } 338 | 339 | #R04 340 | function Convert-PowerStigTest 341 | { 342 | [CmdletBinding()] 343 | param( 344 | [Parameter(Mandatory=$true)] 345 | [PSObject]$TestResults 346 | ) 347 | [Regex]$VIDRegex = "V-([1-9}])[0-9]{3}[0-9]?\.?[a-z]?" 348 | $FullResults = $TestResults.ResourcesInDesiredState + $TestResults.ResourcesNotInDesiredState 349 | 350 | $OutputArr = @() 351 | 352 | $ScanDate = (Get-Date).ToString() 353 | 354 | foreach($i in $FullResults) 355 | { 356 | if($VIDRegex.match($i.InstanceName).success -eq $false) 357 | { 358 | Continue 359 | } 360 | $BoolState = $i.InDesiredState 361 | 362 | $strMod = $i.InstanceName 363 | $strMod = $strMod.Split("][") 364 | if($strMod[6] -eq "Skip") 365 | { Continue } 366 | Else 367 | { 368 | $VidOutPut = $VIDRegex.match($i.InstanceName).value 369 | 370 | $propHash = @{ 371 | VulnID = $VidOutPut 372 | DesiredState = $BoolState 373 | ScanDate = $ScanDate 374 | } 375 | 376 | $currentObj = New-Object PSObject -Property $propHash 377 | 378 | 379 | $outputArr += $currentObj 380 | } 381 | 382 | 383 | 384 | } 385 | 386 | Return $OutputArr 387 | 388 | 389 | } 390 | 391 | #R05 392 | function Import-PowerStigObject 393 | { 394 | [cmdletBinding()] 395 | param( 396 | [Parameter(Mandatory=$true)] 397 | [String]$ServerName, 398 | 399 | [Parameter(Mandatory=$true)] 400 | [PSObject[]]$inputObj, 401 | 402 | # Role is not strictly defined due to SCAP 403 | [Parameter(Mandatory=$true)] 404 | [String]$Role, 405 | 406 | [Parameter(Mandatory=$true)] 407 | [ValidateSet('SCAP','POWERSTIG')] 408 | [String]$ScanSource, 409 | 410 | [Parameter(Mandatory=$true)] 411 | [String]$ScanVersion 412 | ) 413 | 414 | $guid = New-Guid 415 | 416 | foreach($o in $inputObj) 417 | { 418 | $query = "EXEC PowerSTIG.sproc_InsertFindingImport @PSComputerName = `'$ServerName`', @VulnID = `'$($o.VulnID)`', @DesiredState = `'$($o.DesiredState)`', @ScanDate = `'$($o.ScanDate)`', @GUID = `'$($guid.guid)`', @StigType=`'$Role`', @ScanSource = `'$ScanSource`', @ScanVersion=`'$ScanVersion`'" 419 | Invoke-PowerStigSqlCommand -SqlInstance $SqlInstance -DatabaseName $DatabaseName -Query $query | Out-Null 420 | } 421 | 422 | #Process Finding 423 | $query = "EXEC PowerSTIG.sproc_ProcessFindings @GUID = `'$($guid.guid)`'" 424 | Invoke-PowerStigSqlCommand -SqlInstance $SqlInstance -DatabaseName $DatabaseName -Query $query | Out-Null 425 | 426 | return 427 | 428 | } 429 | 430 | #endregion Private 431 | 432 | #region Public 433 | #endregion Public -------------------------------------------------------------------------------- /src/SQL/502.sql: -------------------------------------------------------------------------------- 1 | -- =============================================================================================== 2 | -- =============================================================================================== 3 | -- Purpose: Deployment script for PowerSTIG database objects 4 | -- Revisions: 5 | -- =============================================================================================== 6 | -- =============================================================================================== 7 | /* 8 | Copyright (C) 2019 Microsoft Corporation 9 | Disclaimer: 10 | This is SAMPLE code that is NOT production ready. It is the sole intention of this code to provide a proof of concept as a 11 | learning tool for Microsoft Customers. Microsoft does not provide warranty for or guarantee any portion of this code 12 | and is NOT responsible for any affects it may have on any system it is executed on or environment it resides within. 13 | Please use this code at your own discretion! 14 | Additional legalize: 15 | This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment. 16 | THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 17 | INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 18 | We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute 19 | the object code form of the Sample Code, provided that You agree: 20 | (i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code is embedded; 21 | (ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded; and 22 | (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits, including attorneys� fees, 23 | that arise or result from the use or distribution of the Sample Code. 24 | */ 25 | 26 | -- =============================================================================================== 27 | -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 28 | -- =============================================================================================== 29 | DECLARE @StepName varchar(256) 30 | DECLARE @StepMessage varchar(768) 31 | DECLARE @ErrorMessage varchar(2000) 32 | DECLARE @ErrorSeverity tinyint 33 | DECLARE @ErrorState tinyint 34 | DECLARE @StepAction varchar(25) 35 | DECLARE @UpdateVersion smallint 36 | DECLARE @CurrentVersion smallint 37 | SET @UpdateVersion = 502 38 | -- =============================================================================================== 39 | -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 40 | -- =============================================================================================== 41 | IF OBJECT_ID('PowerSTIG.DBversion') IS NOT NULL 42 | BEGIN 43 | IF EXISTS (SELECT VersionID FROM PowerSTIG.DBversion WHERE UpdateVersion = @UpdateVersion AND isActive = 1) 44 | BEGIN 45 | SET @StepMessage = 'Update version ['+CAST(@UpdateVersion as varchar(5))+'] already applied. This is an informational message only.' 46 | SET @StepAction = 'DEPLOY' 47 | PRINT @StepMessage 48 | -- 49 | EXEC PowerSTIG.sproc_InsertScanLog 50 | @LogEntryTitle = @StepName 51 | ,@LogMessage = @StepMessage 52 | ,@ActionTaken = @StepAction 53 | -- 54 | -- Bail out of this script. Already applied. 55 | SELECT 8675309 AS UpdateApplied; 56 | THROW 8675309, 'Database update previously applied. This is an informational message only.', 1 57 | END 58 | END 59 | -- =============================================================================================== 60 | PRINT '///////////////////////////////////////////////////////' 61 | PRINT 'PowerStigScan database object deployment start - '+CONVERT(VARCHAR,GETDATE(), 21) 62 | PRINT '\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' 63 | -- =============================================================================================== 64 | DROP TABLE IF EXISTS __PowerStigDBdeployVersion 65 | -- 66 | CREATE TABLE __PowerStigDBdeployVersion (UpdateVersion smallint,CurrentVersion smallint) 67 | -- 68 | INSERT INTO __PowerStigDBdeployVersion (UpdateVersion,CurrentVersion) VALUES (@UpdateVersion,NULL) 69 | -- 70 | SET @StepMessage = 'Update version ['+CAST(@UpdateVersion as varchar(5))+'] not yet applied. Executing script now. This is an informational message only.' 71 | SET @StepAction = 'DEPLOY' 72 | PRINT @StepMessage 73 | -- 74 | EXEC PowerSTIG.sproc_InsertScanLog 75 | @LogEntryTitle = @StepName 76 | ,@LogMessage = @StepMessage 77 | ,@ActionTaken = @StepAction 78 | -- 79 | INSERT INTO PowerSTIG.DBversion (UpdateVersion,VersionTS,isActive,VersionNotes) 80 | VALUES 81 | (@UpdateVersion,GETDATE(),0,NULL) 82 | -- =============================================================================================== 83 | -- =============================================================================================== 84 | IF (OBJECT_ID('PowerSTIG.PK_Scans_ScanID', 'PK') IS NULL) 85 | ALTER TABLE PowerSTIG.Scans ADD CONSTRAINT PK_Scans_ScanID PRIMARY KEY CLUSTERED (ScanID) 86 | -- 87 | IF (OBJECT_ID('PowerSTIG.FK_FindingRepo_ScanID', 'F') IS NULL) 88 | ALTER TABLE [PowerSTIG].[FindingRepo] WITH NOCHECK ADD CONSTRAINT [FK_FindingRepo_ScanID] FOREIGN KEY([ScanID]) 89 | REFERENCES [PowerSTIG].[Scans] ([ScanID]) 90 | -- 91 | IF (OBJECT_ID('PowerSTIG.FK_Scans_ScanSourceID', 'F') IS NULL) 92 | ALTER TABLE [PowerSTIG].[Scans] WITH NOCHECK ADD CONSTRAINT [FK_Scans_ScanSourceID] FOREIGN KEY([ScanSourceID]) 93 | REFERENCES [PowerSTIG].[ScanSource] ([ScanSourceID]) 94 | -- 95 | IF (OBJECT_ID('PowerSTIG.FK_FindingRepo_ScanID', 'F') IS NULL) 96 | ALTER TABLE [PowerSTIG].[FindingRepo] WITH NOCHECK ADD CONSTRAINT [FK_FindingRepo_ScanID] FOREIGN KEY([ScanID]) 97 | REFERENCES [PowerSTIG].[Scans] ([ScanID]) 98 | -- 99 | GO 100 | -------------------------------------------------------- 101 | -- [PowerSTIG].[sproc_TrendTargetRoleSource] 102 | -------------------------------------------------------- 103 | CREATE OR ALTER PROCEDURE [PowerSTIG].[sproc_TrendTargetRoleSource] 104 | @TargetComputer varchar(256) 105 | 106 | AS 107 | SET NOCOUNT ON 108 | --------------------------------------------------------------------------------- 109 | -- The sample scripts are not supported under any Microsoft standard support 110 | -- program or service. The sample scripts are provided AS IS without warranty 111 | -- of any kind. Microsoft further disclaims all implied warranties including, 112 | -- without limitation, any implied warranties of merchantability or of fitness for 113 | -- a particular purpose. The entire risk arising out of the use or performance of 114 | -- the sample scripts and documentation remains with you. In no event shall 115 | -- Microsoft, its authors, or anyone else involved in the creation, production, or 116 | -- delivery of the scripts be liable for any damages whatsoever (including, 117 | -- without limitation, damages for loss of business profits, business interruption, 118 | -- loss of business information, or other pecuniary loss) arising out of the use 119 | -- of or inability to use the sample scripts or documentation, even if Microsoft 120 | -- has been advised of the possibility of such damages 121 | --------------------------------------------------------------------------------- 122 | -- =============================================================================================== 123 | -- PURPOSE: 124 | -- 125 | -- REVISIONS: 126 | -- 04222019 - Kevin Barlett, Microsoft - Initial creation. 127 | -- EXAMPLES: 128 | -- EXEC [PowerSTIG].[sproc_TrendTargetRoleSource] @TargetComputer = 'WIN10' 129 | -- =============================================================================================== 130 | -- 131 | DECLARE @TargetComputerID INT 132 | --declare @TargetComputer varchar(255) 133 | --set @TargetComputer = 'SQLtest006' 134 | SET @TargetComputerID = (SELECT TargetComputerID FROM PowerSTIG.ComplianceTargets WHERE TargetComputer = LTRIM(RTRIM(@TargetComputer))) 135 | -- 136 | 137 | -- ======================================================= 138 | -- Find the most recent scan for each target + compliance type combination 139 | -- ======================================================= 140 | 141 | DROP TABLE IF EXISTS #RecentScan 142 | -- 143 | 144 | SELECT * INTO #RecentScan FROM 145 | ( 146 | SELECT 147 | M.*, ROW_NUMBER() OVER (PARTITION BY TargetComputerID,ComplianceTypeID,ScanSourceID ORDER BY LastComplianceCheck DESC) RN 148 | FROM 149 | PowerSTIG.ComplianceSourceMap M 150 | WHERE 151 | M.TargetComputerID = @TargetComputerID 152 | 153 | ) T 154 | WHERE 155 | T.RN = 1 156 | 157 | -- ======================================================= 158 | -- Return results 159 | -- ======================================================= 160 | SELECT 161 | ComplianceType, 162 | COUNT(R.inDesiredState) AS NumberOfCompliantFindings, 163 | O.ScanSource, 164 | CONVERT(varchar,S.ScanDate,101) AS ScanDate 165 | --S.ScanDate 166 | FROM 167 | PowerSTIG.Scans S 168 | JOIN 169 | PowerSTIG.FindingRepo R 170 | ON 171 | S.ScanID = R.ScanID 172 | JOIN 173 | PowerSTIG.ComplianceTypes T 174 | ON 175 | T.ComplianceTypeID = R.ComplianceTypeID 176 | JOIN 177 | PowerSTIG.ScanSource O 178 | ON 179 | O.ScanSourceID = S.ScanSourceID 180 | 181 | WHERE 182 | R.InDesiredState = 1 183 | AND 184 | R.TargetComputerID = @TargetComputerID 185 | AND 186 | R.ScanID IN (SELECT ScanID FROM #RecentScan) 187 | GROUP BY 188 | T.ComplianceType,R.inDesiredState,O.ScanSource,ScanDate 189 | GO 190 | -------------------------------------------------------- 191 | -- CREATE OR ALTER PROCEDURE [PowerSTIG].[sproc_GetOrgSettingsByRole] 192 | -------------------------------------------------------- 193 | CREATE OR ALTER PROCEDURE [PowerSTIG].[sproc_GetOrgSettingsByRole] 194 | @ComplianceType varchar(256) 195 | AS 196 | SET NOCOUNT ON 197 | --------------------------------------------------------------------------------- 198 | -- The sample scripts are not supported under any Microsoft standard support 199 | -- program or service. The sample scripts are provided AS IS without warranty 200 | -- of any kind. Microsoft further disclaims all implied warranties including, 201 | -- without limitation, any implied warranties of merchantability or of fitness for 202 | -- a particular purpose. The entire risk arising out of the use or performance of 203 | -- the sample scripts and documentation remains with you. In no event shall 204 | -- Microsoft, its authors, or anyone else involved in the creation, production, or 205 | -- delivery of the scripts be liable for any damages whatsoever (including, 206 | -- without limitation, damages for loss of business profits, business interruption, 207 | -- loss of business information, or other pecuniary loss) arising out of the use 208 | -- of or inability to use the sample scripts or documentation, even if Microsoft 209 | -- has been advised of the possibility of such damages 210 | --------------------------------------------------------------------------------- 211 | -- =============================================================================================== 212 | -- PURPOSE: 213 | -- REVISIONS: 214 | -- 04222019 - Kevin Barlett, Microsoft - Initial creation. 215 | -- EXAMPLES: 216 | -- =============================================================================================== 217 | -- 218 | DECLARE @ComplianceTypeID INT 219 | --declare @ComplianceType varchar(256) 220 | --set @ComplianceType = 'WindowsServer-MS' 221 | SET @ComplianceTypeID = (SELECT ComplianceTypeID FROM PowerSTIG.ComplianceTypes WHERE ComplianceType = @ComplianceType) 222 | SELECT 223 | T.ComplianceType, 224 | R.Finding AS RuleID, 225 | P.RawString AS FindingText, 226 | R.OrgValue 227 | FROM 228 | PowerSTIG.OrgSettingsRepo R 229 | JOIN 230 | PowerSTIG.ComplianceTypesInfo I 231 | ON 232 | R.TypesInfoID = I.TypesInfoID 233 | JOIN 234 | PowerSTIG.ComplianceTypes T 235 | ON 236 | T.ComplianceTypeID = I.ComplianceTypeID 237 | LEFT OUTER JOIN 238 | PowerSTIG.Finding F 239 | ON 240 | F.Finding = R.Finding 241 | JOIN 242 | PowerSTIG.StigTextRepo P 243 | ON 244 | P.RuleID = F.Finding 245 | WHERE 246 | T.ComplianceTypeID = @ComplianceTypeID 247 | ORDER BY 248 | R.Finding 249 | GO 250 | -- =============================================================================================== 251 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 252 | -- Logging 253 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 254 | -- =============================================================================================== 255 | DECLARE @StepName varchar(256) 256 | DECLARE @StepMessage varchar(768) 257 | DECLARE @ErrorMessage varchar(2000) 258 | DECLARE @ErrorSeverity tinyint 259 | DECLARE @ErrorState tinyint 260 | DECLARE @StepAction varchar(25) 261 | DECLARE @UpdateVersion SMALLINT 262 | DECLARE @CurrentVersion smallint 263 | SET @UpdateVersion = (SELECT TOP 1 UpdateVersion FROM __PowerStigDBdeployVersion) 264 | SET @CurrentVersion = (SELECT TOP 1 CurrentVersion FROM __PowerStigDBdeployVersion) 265 | SET @StepMessage = 'Update version ['+CAST(@UpdateVersion as varchar(5))+'] successfully applied. This is an informational message only.' 266 | SET @StepAction = 'DEPLOY' 267 | PRINT @StepMessage 268 | -- 269 | EXEC PowerSTIG.sproc_InsertScanLog 270 | @LogEntryTitle = @StepName 271 | ,@LogMessage = @StepMessage 272 | ,@ActionTaken = @StepAction 273 | -- 274 | UPDATE 275 | PowerSTIG.DBversion 276 | SET 277 | isActive = 1 278 | WHERE 279 | UpdateVersion = @UpdateVersion 280 | 281 | -- =============================================================================================== 282 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 283 | -- =============================================================================================== 284 | DROP TABLE IF EXISTS __PowerStigDBdeployVersion 285 | -- =============================================================================================== 286 | PRINT '///////////////////////////////////////////////////////' 287 | PRINT 'PowerStigScan database object deployment complete - '+CONVERT(VARCHAR,GETDATE(), 21) 288 | PRINT '\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' 289 | -- =============================================================================================== 290 | -------------------------------------------------------------------------------- /src/Common/PowerStigScan.Scap.ps1: -------------------------------------------------------------------------------- 1 | function Get-PowerStigScapVersionMap 2 | { 3 | $verHash= @{ 4 | #PSTIGVer2.15 5 | "Windows_2012_MS"="2.15" 6 | #PSTIGVer=2.16 7 | "Windows_2012_DC"="2.16" 8 | #PSTIGVer=1.7 9 | "Windows_Server_2016"="1.8" 10 | #PSTIGVer=1.7 11 | "Windows_Firewall"="1.7" 12 | #PSTIGVer=1.4 13 | "Windows_Defender_Antivirus"="1.1" 14 | #PSTIGVer=1.16 - There was not a new Benchmark to match January 2019 STIG release, defaulted to previous Benchmark 15 | "Windows_10"="1.13" 16 | #PSTIGVer=1.16 17 | "IE_11"="1.12" 18 | #PSTIGVer=1.7 19 | "MS_Dot_Net_Framework"="1.6" 20 | #PSTIGVer=4.25 21 | "Mozilla_FireFox_Windows"="1.2" 22 | #Following does not have a corresponding PowerStig Equivilent 23 | #StigVer=1.4 24 | "Adobe_Acrobat_Reader_DC_Classic"="1.5" 25 | #StigVer=1.5 26 | "Adobe_Acrobat_Reader_DC_Continuous"="1.4" 27 | #StigVer=1.15 28 | "Google_Chrome_Current_Windows"="1.11" 29 | } 30 | 31 | Return $verHash 32 | 33 | } 34 | 35 | Function Get-ScapOnlyRoles 36 | { 37 | $sRoles = "Adobe_Acrobat_Reader_DC_Classic", 38 | "Adobe_Acrobat_Reader_DC_Continuous", 39 | "Google_Chrome_Current_Windows", 40 | "MS_Dot_Net_Framework" 41 | 42 | Return $sRoles 43 | } 44 | 45 | 46 | 47 | 48 | function Get-PowerStigScapResults 49 | { 50 | [cmdletBinding()] 51 | param( 52 | [Parameter(Mandatory=$true)] 53 | [String]$ScapResultsXccdf, 54 | 55 | [Parameter(Mandatory=$false)] 56 | [Switch]$OutHash 57 | ) 58 | 59 | [xml]$ScapXML = Get-Content -Path $ScapResultsXccdf 60 | $ScanDate = (Get-ChildItem $ScapResultsXccdf).LastWriteTime.ToString() 61 | 62 | #$ScapXML.Benchmark.TestResult.'rule-result' #ruleID 63 | 64 | $ResultHash = @{} 65 | $VIDHash = @{} 66 | [Regex]$VIDRegex = "V-([1-9}])[0-9]{3}[0-9]?" 67 | 68 | foreach($r in $($ScapXML.Benchmark.TestResult.'rule-result')) 69 | { 70 | $boolOut = $false 71 | if($r.result -eq 'pass') 72 | { 73 | $boolOut = $true 74 | } 75 | 76 | $ResultHash.Add($($r.idref),$boolOut) 77 | } 78 | 79 | #EXAMPLE: $ResultHash."$($ScapXML.Benchmark.Group[0].rule.id[0])" 80 | #V-ID: $testXML.Benchmark.Group[0].id[0] 81 | 82 | foreach($g in $($ScapXML.Benchmark.Group)) 83 | { 84 | if($ResultHash."$($g.rule.id[0])" -eq $true) 85 | { 86 | $gBoolOut = $true 87 | $vID = $VIDRegex.matches($($g.id[0])).Value 88 | $VIDHash.Add($vID,$gBoolOut) 89 | } 90 | elseif($ResultHash."$($g.rule.id[0])" -eq $false) 91 | { 92 | $gBoolOut = $false 93 | $vID = $VIDRegex.matches($($g.id[0])).Value 94 | $VIDHash.Add($vID,$gBoolOut) 95 | } 96 | } 97 | 98 | if($OutHash -eq $true) 99 | { 100 | Return $VIDHash 101 | } 102 | 103 | $outObj = @() 104 | 105 | foreach($i in $VIDHash.Keys) 106 | { 107 | $props = @{VulnID = $i; 108 | DesiredState = $VIDHash.$i; 109 | ScanDate = $ScanDate} 110 | $outObj += New-Object -TypeName PSObject -Property $props 111 | } 112 | 113 | Return $outObj 114 | } 115 | 116 | 117 | function Get-PowerStigScapVersion 118 | { 119 | [cmdletBinding()] 120 | param( 121 | [Parameter(Mandatory=$true)] 122 | [String]$ScapRole 123 | ) 124 | 125 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 126 | 127 | $ScapInstallDir = $iniVar.ScapInstallDir 128 | 129 | $ScapContent = Get-ChildItem "$ScapInstallDir\Resources\Content\SCAP12_Content" 130 | 131 | [Regex]$VersionMatch = "V[1-9]?[0-9]R[0-9][0-9]?" 132 | 133 | foreach($c in $ScapContent) 134 | { 135 | if($c.name -like "*$scapRole*") 136 | { 137 | 138 | $fileVersion = ($VersionMatch.matches($c.name)).value 139 | [int32]$tempMaj = $fileVersion.Split("R")[0].replace("V","") 140 | [int32]$tempMin = $fileVersion.Split("R")[1] 141 | [Version]$tempVer = "$tempMaj.$tempMin" 142 | 143 | if($null -eq $testVer) 144 | { 145 | $testVer = $tempVer 146 | } 147 | elseif($tempVer -gt $testVer) 148 | { 149 | $testVer = $tempVer 150 | } 151 | 152 | 153 | } 154 | } 155 | 156 | Return $testVer 157 | } 158 | 159 | function Get-PowerScapOutputPath 160 | { 161 | $workingPath = Split-Path $PsCommandPath 162 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 163 | $scapPath = $iniVar.ScapInstallDir 164 | 165 | $results = & "$scapPath\cscc.exe --getopt userDataDirectory -q" 166 | 167 | $directory = $results[$results.count - 1].replace("userDataDirectory = ","") 168 | 169 | return $directory 170 | } 171 | 172 | function Convert-PowerStigRoleToScap 173 | { 174 | [cmdletBinding()] 175 | param( 176 | [Parameter(Mandatory=$false)] 177 | [ValidateSet("2016","2012R2","10","All")] 178 | [String]$OsVersion 179 | ) 180 | DynamicParam { 181 | $ParameterName = 'Role' 182 | $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary 183 | $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] 184 | $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute 185 | $ParameterAttribute.Mandatory = $true 186 | $AttributeCollection.Add($ParameterAttribute) 187 | $roleSet = Import-CSV "$(Split-Path $PsCommandPath)\Roles.csv" -Header Role | Select-Object -ExpandProperty Role 188 | $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($roleSet) 189 | $AttributeCollection.Add($ValidateSetAttribute) 190 | $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) 191 | $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) 192 | return $RuntimeParameterDictionary 193 | } 194 | 195 | begin{ 196 | $Role = $PSBoundParameters[$ParameterName] 197 | } 198 | 199 | process{ 200 | switch($Role) 201 | { 202 | "DotNetFramework" {Return "MS_Dot_Net_Framework"} 203 | "FireFox" {Return "Mozilla_FireFox_Windows"} 204 | "IISServer" {Return $null} 205 | "IISSite" {Return $null} 206 | "InternetExplorer" {Return "IE_11"} 207 | "Excel2013" {Return $null} 208 | "Outlook2013" {Return $null} 209 | "PowerPoint2013" {Return $null} 210 | "Word2013" {Return $null} 211 | "OracleJRE" {Return $null} 212 | "SqlServer-2012-Database" {Return $null} 213 | "SqlServer-2012-Instance" {Return $null} 214 | "SqlServer-2016-Instance" {Return $null} 215 | "WindowsClient" {Return "Windows_10"} 216 | "WindowsDefender" {Return "Windows_Defender_Antivirus"} 217 | "WindowsDNSServer" {Return $null} 218 | "WindowsFirewall" {Return "Windows_Firewall"} 219 | "WindowsServer-DC" {if($OsVersion -eq "2016"){Return "Windows_Server_2016"} 220 | elseif($OsVersion -eq "2012R2"){Return "Windows_2012_DC"} } 221 | "WindowsServer-MS" {if($OsVersion -eq "2016"){Return "Windows_Server_2016"} 222 | elseif($OsVersion -eq "2012R2"){Return "Windows_2012_MS"} } 223 | } 224 | } 225 | } 226 | 227 | Function Convert-ScapRoleToPowerStig 228 | { 229 | [cmdletBinding()] 230 | param( 231 | [Parameter(Mandatory=$true)] 232 | [String]$Role, 233 | 234 | [Parameter(Mandatory=$false)] 235 | [Switch]$isDomainController 236 | ) 237 | 238 | 239 | 240 | switch -Wildcard ($Role) 241 | { 242 | "*Windows_Server_2016*" {if($isDomainController){Return "WindowsServer-DC"}else{Return "WindowsServer-MS"}} 243 | "*Windows_2012_MS*" {Return "WindowsServer-MS"} 244 | "*Windows_2012_DC*" {Return "WindowsServer-DC"} 245 | "*Windows_Firewall*" {Return "WindowsFirewall"} 246 | "*Windows_Defender_Antivirus*" {Return "WindowsDefender"} 247 | "*Windows_10*" {Return "WindowsClient"} 248 | "IE_11*" {Return "InternetExplorer"} 249 | "*MS_Dot_Net_Framework*" {Return "DotNetFramework"} 250 | "*Mozilla_FireFox_Windows*" {Return "FireFox"} 251 | } 252 | 253 | } 254 | 255 | Function Set-PowerStigScapBasicOptions 256 | { 257 | $workingPath = Split-Path $PsCommandPath 258 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 259 | $basePath = $iniVar.LogPath 260 | 261 | $ScapInstallDir = $iniVar.ScapInstallDir 262 | $outputPath = Join-Path -Path $basepath -ChildPath "SCC" 263 | 264 | $ScapOptions = @{ 265 | "scapScan" = "1" 266 | "ovalScan" = "0" 267 | "ocilScan" = "1" 268 | "allSettingsHTMLReport" = "1" 269 | "allSettingsTextReport" = "0" 270 | "nonComplianceHTMLReport" = "0" 271 | "nonComplianceTextReport" = "0" 272 | "allSettingsSummaryHTMLReport" = "0" 273 | "allSettingsSummaryTextReport" = "0" 274 | "nonComplianceSummaryHTMLReport" = "0" 275 | "nonComplianceSummaryTextReport" = "0" 276 | "keepXCCDFXML" = "1" 277 | "keepOVALXML" = "0" 278 | "keepOCILXML" = "0" 279 | "keepARFXML" = "0" 280 | "keepCPEXML" = "0" 281 | "userDataDirectory" = $outputPath 282 | "userDataDirectoryValue" = "4" 283 | "dirResultsLogsEnabled" = "1" 284 | "dirTargetNameEnabled" = "1" 285 | "dirXMLEnabled" = "1" 286 | "dirStreamNameEnabled" = "0" 287 | "dirContentTypeEnabled" = "0" 288 | "dirTimestampEnabled" = "0" 289 | "fileTargetNameEnabled" = "1" 290 | "fileSCCVersionEnabled" = "0" 291 | "fileContentVersionEnabled" = "1" 292 | "fileTimestampEnabled" = "0" 293 | } 294 | 295 | if(-not(Test-Path -Path $outPutPath)) 296 | { 297 | New-Item -Path $outPutPath -ItemType Directory -force | Out-Null 298 | } 299 | 300 | $strSetOpt = "" 301 | foreach($sOpt in $($ScapOptions.Keys)) 302 | { 303 | $strSetOpt += " --setOpt $sOpt $($ScapOptions.$sOpt)" 304 | } 305 | 306 | $exePath = Join-Path -Path $ScapInstallDir -ChildPath "cscc.exe" 307 | 308 | $cmdStart = "& `"" + $exePath + "`" " 309 | $configCommand = "$cmdStart$strSetOpt -q" 310 | Invoke-Expression $configCommand | Out-Null 311 | } 312 | 313 | function Set-PowerStigScapRoleXML 314 | { 315 | [cmdletBinding()] 316 | param( 317 | [Parameter(Mandatory=$true)] 318 | [ValidateSet('2012R2','2016','10')] 319 | [String]$OsVersion, 320 | 321 | [Parameter(Mandatory=$false)] 322 | [switch]$isDomainController, 323 | 324 | [Parameter(Mandatory=$false)] 325 | [switch]$RunAll 326 | ) 327 | 328 | 329 | $fileName = "$($OsVersion)_$(if($isDomainController){"DC"}else{"MS"})_options.xml" 330 | if($OsVersion -eq '10') 331 | { 332 | $fileName = "Client_options.xml" 333 | } 334 | $iniVar = Import-PowerStigConfig -configFilePath "$(Split-Path $PsCommandPath)\Config.ini" 335 | $scapInstallDir = $iniVar.ScapInstallDir 336 | $ScapProfile = $iniVar.ScapProfile 337 | $logPath = $iniVar.LogPath 338 | $outpath = Join-Path -Path $logPath -ChildPath "SCAP\" 339 | 340 | [xml]$configXML = Get-Content $ScapInstallDir\options.xml 341 | $configXML.PreserveWhitespace = $true 342 | $psRoles = Import-CSV "$(Split-Path $PsCommandPath)\Roles.csv" -Header Role | Select-Object -ExpandProperty Role 343 | 344 | $xmlRoles = @() 345 | 346 | # Determine which roles exist in Scap 347 | foreach($r in $psRoles) 348 | { 349 | if($r -like "WindowsServer-DC" -and $isDomainController -eq $false) 350 | { 351 | continue 352 | } 353 | elseif($r -like "WindowsServer-MS" -and $isDomainController -eq $true) 354 | { 355 | continue 356 | } 357 | elseif($r -like "*WindowsServer*") 358 | { 359 | $testRole = Convert-PowerStigRoleToScap -Role $r -OsVersion $OsVersion 360 | if($null -ne $testRole) 361 | { 362 | $xmlRoles += $testRole 363 | } 364 | } 365 | else 366 | { 367 | $testRole = Convert-PowerStigRoleToScap -Role $r 368 | if($null -ne $testRole) 369 | { 370 | $xmlRoles += $testRole 371 | } 372 | } 373 | 374 | } 375 | 376 | $workingVersions = Get-PowerStigScapVersionMap 377 | 378 | foreach($i in $($configXML.options.contents.content)) 379 | { 380 | 381 | $i.enabled = "0" 382 | if($i.benchmarkID -like "*USGCB*"){Continue} 383 | 384 | [Version]$iVer = $i.version 385 | 386 | if($RunAll -eq $true) 387 | { 388 | if($i.benchmarkID -like "*Windows_2012*" -or $i.benchmarkID -like "*Windows_10*" -or $i.benchmarkID -like "*Windows_Server*") 389 | { 390 | foreach($r in $xmlRoles) 391 | { 392 | if($i.benchmarkID -like "*$r*" -and $iVer -eq $workingVersions."$r") 393 | { 394 | $i.enabled = "1" 395 | $i.selectedProfile = "xccdf_mil.disa.stig_profile_$ScapProfile" 396 | } 397 | } 398 | } 399 | else 400 | { 401 | $hashRole = $null 402 | $hashVer = $null 403 | $hashRole = $workingVersions.keys.Where({$i.benchmarkID -like "*$_*"}) 404 | $hashVer = $workingVersions."$hashRole" 405 | if($iVer -eq $hashVer) 406 | { 407 | $i.enabled = "1" 408 | $i.selectedProfile = "xccdf_mil.disa.stig_profile_$ScapProfile" 409 | } 410 | } 411 | }elseif($RunAll -eq $false) 412 | { 413 | foreach($r in $xmlRoles) 414 | { 415 | if($i.benchmarkID -like "*$r*" -and $iVer -eq $workingVersions."$r" -and $runAll -eq $false) 416 | { 417 | $i.enabled = "1" 418 | $i.selectedProfile = "xccdf_mil.disa.stig_profile_$ScapProfile" 419 | } 420 | } 421 | } 422 | } 423 | 424 | if(-not(Test-Path -Path (Split-Path $outPath))) 425 | { 426 | New-Item -ItemType Directory -Path (Split-Path $outPath) -Force 427 | } 428 | 429 | if(Test-Path -Path "$outPath\$fileName") 430 | { 431 | Remove-Item "$outPath\$fileName" -Force 432 | } 433 | 434 | $configXML.save("$outPath\$fileName") | Out-Null 435 | 436 | return 437 | } -------------------------------------------------------------------------------- /src/Common/PowerStigScan.Config.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Functions: 3 | CN01 - Get-PowerStigSqlConfig 4 | CN02 - Set-PowerStigSqlConfig 5 | CN03 - Get-PowerStigConfig 6 | CN04 - Set-PowerStigConfig 7 | #> 8 | 9 | #region Private 10 | 11 | #endregion Private 12 | 13 | #region Public 14 | #CN01 15 | <# 16 | .SYNOPSIS 17 | Command to retrieve configuration data from the PowerStig database 18 | 19 | .DESCRIPTION 20 | Retrieves information from the ConfigData table in the PowerStig database. This can only retrieve one configuration setting at a time. 21 | 22 | 23 | .PARAMETER SqlInstance 24 | SQL instance name that hosts the PowerStig database. If empty, this will use the settings in the ModuleBase\Common\config.ini file. 25 | 26 | .PARAMETER DatabaseName 27 | Name of the database that hosts the PowerStig tables. If empty, this will use the settings in the ModuleBase\Common\config.ini file. 28 | 29 | .EXAMPLE 30 | Get-PowerStigSqlConfig -SqlInstance TestSQL01 -DatabaseName Master -OutputFileLoc 31 | 32 | Get-PowerStigSqlConfig -OutputFileLoc 33 | 34 | #> 35 | function Get-PowerStigSqlConfig 36 | { 37 | [CmdletBinding()] 38 | Param( 39 | [Parameter(ParameterSetName='1',Mandatory=$false)][switch]$ORGsettingXML, 40 | [Parameter(ParameterSetName='2',Mandatory=$false)][switch]$FindingRepoTableRetentionDays, 41 | [Parameter(ParameterSetName='3',Mandatory=$false)][switch]$LastComplianceCheckAlert, 42 | [Parameter(ParameterSetName='4',Mandatory=$false)][switch]$LastComplianceCheckInDays, 43 | [Parameter(ParameterSetName='5',Mandatory=$false)][switch]$LastComplianceCheckAlertRecipients, 44 | [Parameter(ParameterSetName='6',Mandatory=$false)][switch]$ScanImportErrorLogRetentionDays, 45 | [Parameter(ParameterSetName='7',Mandatory=$false)][switch]$ScanImportLogRetentionDays, 46 | [Parameter(ParameterSetName='8',Mandatory=$false)][switch]$ScanLogRetentionDays, 47 | [Parameter(ParameterSetName='9',Mandatory=$false)][switch]$ComplianceCheckLogTableRetentionDays, 48 | [Parameter(ParameterSetName='10',Mandatory=$false)][switch]$FindingImportFilesTableRetentionDays, 49 | [Parameter(ParameterSetName='11',Mandatory=$false)][switch]$MailProfileName, 50 | 51 | [Parameter(Mandatory=$false)][switch]$DebugScript, 52 | 53 | [Parameter(Mandatory=$false)] 54 | [String]$SqlInstance, 55 | 56 | [Parameter(Mandatory=$false)] 57 | [String]$DatabaseName 58 | ) 59 | 60 | $workingPath = Split-Path $PsCommandPath 61 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 62 | 63 | if($null -eq $sqlInstance -or $sqlInstance -eq '') 64 | { 65 | $sqlInstance = $iniVar.SqlInstanceName 66 | } 67 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 68 | { 69 | $DatabaseName = $iniVar.DatabaseName 70 | } 71 | 72 | 73 | Switch($PSCmdlet.ParameterSetName){ 74 | "1" { $checkConfig = "ORGsettingXML" } 75 | "2" { $checkConfig = "FindingRepoTableRetentionDays" } 76 | "3" { $checkConfig = "LastComplianceCheckAlert" } 77 | "4" { $checkConfig = "LastComplianceCheckInDays" } 78 | "5" { $checkConfig = "LastComplianceCheckAlertRecipients" } 79 | "6" { $checkConfig = "ScanImportErrorLogRetentionDays" } 80 | "7" { $checkConfig = "ScanImportLogRetentionDays" } 81 | "8" { $checkConfig = "ScanLogRetentionDays" } 82 | "9" { $checkConfig = "ComplianceCheckLogTableRetentionDays" } 83 | "10" { $checkConfig = "FindingImportFilesTableRetentionDays" } 84 | "11" { $checkConfig = "MailProfileName" } 85 | 86 | } 87 | 88 | $Query = "powerstig.sproc_GetConfigSetting @ConfigProperty = $checkConfig" 89 | if($DebugScript) 90 | { 91 | Write-Host $Query 92 | } 93 | $Results = Invoke-PowerStigSqlCommand -Query $Query -SqlInstance $SqlInstance -DatabaseName $DatabaseName 94 | 95 | 96 | return $Results 97 | 98 | } 99 | 100 | #CN02 101 | <# 102 | .SYNOPSIS 103 | Command to allow changes to the configuration database for PowerStig 104 | 105 | .DESCRIPTION 106 | Allows for changes to the ConfigData table in the PowerStig database. This can only impact one configuration setting at a time. 107 | 108 | .PARAMETER SqlInstance 109 | SQL instance name that hosts the PowerStig database. If empty, this will use the settings in the ModuleBase\Common\config.ini file. 110 | 111 | .PARAMETER DatabaseName 112 | Name of the database that hosts the PowerStig tables. If empty, this will use the settings in the ModuleBase\Common\config.ini file. 113 | 114 | .EXAMPLE 115 | Set-PowerStigSqlConfig -SqlInstance TestSQL01 -DatabaseName Master -OutputFileLoc C:\Temp\CSV 116 | 117 | Set-PowerStigSqlConfig -OutputFileLoc C:\Temp\CSV 118 | 119 | 120 | #> 121 | function Set-PowerStigSqlConfig 122 | { 123 | [CmdletBinding()] 124 | Param( 125 | [Parameter(ParameterSetName='1',Mandatory=$false)][ValidateNotNullorEmpty()][String]$ORGsettingXML, 126 | [Parameter(ParameterSetName='2',Mandatory=$false)][ValidateNotNullorEmpty()][String]$FindingRepoTableRetentionDays, 127 | [Parameter(ParameterSetName='3',Mandatory=$false)][ValidateNotNullorEmpty()][String]$LastComplianceCheckAlert, 128 | [Parameter(ParameterSetName='4',Mandatory=$false)][ValidateNotNullorEmpty()][String]$LastComplianceCheckInDays, 129 | [Parameter(ParameterSetName='5',Mandatory=$false)][ValidateNotNullorEmpty()][String]$LastComplianceCheckAlertRecipients, 130 | [Parameter(ParameterSetName='6',Mandatory=$false)][ValidateNotNullorEmpty()][String]$ScanImportErrorLogRetentionDays, 131 | [Parameter(ParameterSetName='7',Mandatory=$false)][ValidateNotNullorEmpty()][String]$ScanImportLogRetentionDays, 132 | [Parameter(ParameterSetName='8',Mandatory=$false)][ValidateNotNullorEmpty()][String]$ScanLogRetentionDays, 133 | [Parameter(ParameterSetName='9',Mandatory=$false)][ValidateNotNullorEmpty()][String]$ComplianceCheckLogTableRetentionDays, 134 | [Parameter(ParameterSetName='10',Mandatory=$false)][ValidateNotNullorEmpty()][String]$FindingImportFilesTableRetentionDays, 135 | [Parameter(ParameterSetName='11',Mandatory=$false)][ValidateNotNullorEmpty()][String]$MailProfileName, 136 | 137 | [Parameter(Mandatory=$false)][switch]$DebugScript, 138 | 139 | [Parameter(Mandatory=$false)] 140 | [String]$SqlInstance, 141 | 142 | [Parameter(Mandatory=$false)] 143 | [String]$DatabaseName 144 | ) 145 | 146 | $workingPath = Split-Path $PsCommandPath 147 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 148 | 149 | if($null -eq $sqlInstance -or $sqlInstance -eq '') 150 | { 151 | $sqlInstance = $iniVar.SqlInstanceName 152 | } 153 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 154 | { 155 | $DatabaseName = $iniVar.DatabaseName 156 | } 157 | 158 | 159 | #Switch ParameterSet since each stored procedure can only handle a single change 160 | #TODO switch to a foreach loop per parameter 161 | Switch($PSCmdlet.ParameterSetName){ 162 | "1" { 163 | $setConfig = "ORGsettingXML" 164 | $newConfig = $ORGsettingXML 165 | } 166 | "2" { 167 | $setConfig = "FindingRepoTableRetentionDays" 168 | $newConfig = $FindingRepoTableRetentionDays 169 | } 170 | "3" { 171 | $setConfig = "LastComplianceCheckAlert" 172 | $newConfig = $LastComplianceCheckAlert 173 | } 174 | "4" { 175 | $setConfig = "LastComplianceCheckInDays" 176 | $newConfig = $LastComplianceCheckInDays 177 | } 178 | "5" { 179 | $setConfig = "LastComplianceCheckAlertRecipients" 180 | $newConfig = $LastComplianceCheckAlertRecipients 181 | } 182 | "6" { 183 | $setConfig = "ScanImportErrorLogRetentionDays" 184 | $newConfig = $ScanImportErrorLogRetentionDays 185 | } 186 | "7" { 187 | $setConfig = "ScanImportLogRetentionDays" 188 | $newConfig = $ScanImportLogRetentionDays 189 | } 190 | "8" { 191 | $setConfig = "ScanLogRetentionDays" 192 | $newConfig = $ScanLogRetentionDays 193 | } 194 | "9" { 195 | $setConfig = "ComplianceCheckLogTableRetentionDays" 196 | $newConfig = $ComplianceCheckLogTableRetentionDays 197 | } 198 | "10" { 199 | $setConfig = "FindingImportFilesTableRetentionDays" 200 | $newConfig = $FindingImportFilesTableRetentionDays 201 | } 202 | "11" { 203 | $setConfig = "MailProfileName" 204 | $newConfig = $MailProfileName 205 | } 206 | } 207 | 208 | # ' is escaped around $newConfig to prevent issues with Strings being passed, removal will cause filepaths to parse incorrectly 209 | $Query = "powerstig.sproc_UpdateConfig @ConfigProperty = $($setConfig), @NewConfigSetting = `'$newConfig`'" 210 | if($DebugScript) 211 | { 212 | Write-Host $Query 213 | } 214 | $Results = Invoke-PowerStigSqlCommand -Query $Query -SqlInstance $SqlInstance -DatabaseName $DatabaseName 215 | 216 | return $Results 217 | 218 | } 219 | 220 | #CN03 221 | <# 222 | 223 | #> 224 | function Get-PowerStigConfig 225 | { 226 | $workingPath = Split-Path $PsCommandPath 227 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 228 | 229 | $configObject = New-Object PSobject 230 | Add-Member -InputObject $configObject -NotePropertyName "CKLOutPath" -NotePropertyValue $iniVar.CKLOutPath 231 | Add-Member -InputObject $configObject -NotePropertyName "LogPath" -NotePropertyValue $iniVar.LogPath 232 | Add-Member -InputObject $configObject -NotePropertyName "ConcurrentScans" -NotePropertyValue $iniVar.ConcurrentScans 233 | Add-Member -InputObject $configObject -NotePropertyName "ScapProfile" -NotePropertyValue $iniVar.ScapProfile 234 | Add-Member -InputObject $configObject -NotePropertyName "ScapInstallDir" -NotePropertyValue $iniVar.ScapInstallDir 235 | Add-Member -InputObject $configObject -NotePropertyName "SQLInstanceName" -NotePropertyValue $iniVar.SQLInstanceName 236 | Add-Member -InputObject $configObject -NotePropertyName "DatabaseName" -NotePropertyValue $iniVar.DatabaseName 237 | 238 | Return $configObject 239 | } 240 | 241 | #CN04 242 | <# 243 | 244 | #> 245 | function Set-PowerStigConfig 246 | { 247 | [CmdletBinding()] 248 | Param( 249 | [Parameter(Mandatory=$false)] 250 | [ValidateNotNullorEmpty()] 251 | [String]$CKLOutPath, 252 | 253 | [Parameter(Mandatory=$false)] 254 | [ValidateNotNullorEmpty()] 255 | [String]$LogPath, 256 | 257 | [Parameter(Mandatory=$false)] 258 | [ValidateNotNullorEmpty()] 259 | [String]$ConcurrentScans, 260 | 261 | [Parameter(Mandatory=$false)] 262 | [ValidateNotNullorEmpty()] 263 | [ValidateSet('CAT_I_Only', 264 | 'Disable_EMET', 265 | 'Disable_Slow_Rules', 266 | 'MAC-1_Classified', 267 | 'MAC-1_Public', 268 | 'MAC-1_Sensitive', 269 | 'MAC-2_Classified', 270 | 'MAC-2_Public', 271 | 'MAC-2_Sensitive', 272 | 'MAC-3_Classified', 273 | 'MAC-3_Public', 274 | 'MAC-3_Sensitive', 275 | 'no_profile_selected')] 276 | [String]$ScapProfile, 277 | 278 | [Parameter(Mandatory=$false)] 279 | [ValidateNotNullorEmpty()] 280 | [String]$ScapInstallDir, 281 | 282 | [Parameter(Mandatory=$false)] 283 | [ValidateNotNullorEmpty()] 284 | [String]$SqlInstanceName, 285 | 286 | [Parameter(Mandatory=$false)] 287 | [ValidateNotNullorEmpty()] 288 | [String]$DatabaseName 289 | ) 290 | 291 | # Pull the current config to cover any unchanged parameter 292 | $workingObj = Get-PowerStigConfig 293 | 294 | #check each potential parameter, if they are used check to make sure there is an ending dash then write the value 295 | #to the working object. Working Object will be used to generate the final config file 296 | if($CKLOutPath -ne '') 297 | { 298 | if (!($CKLOutPath.EndsWith("\"))) 299 | { 300 | $CKLOutPath = $CKLOutPath + "\" 301 | } 302 | $workingObj.CKLOutPath = $CKLOutPath 303 | } 304 | if($LogPath -ne '') 305 | { 306 | if (!($LogPath.EndsWith("\"))) 307 | { 308 | $LogPath = $LogPath + "\" 309 | } 310 | $workingObj.LogPath = $LogPath 311 | } 312 | if($ScapInstallDir -ne '') 313 | { 314 | if(!($LogPath.EndsWith("\"))) 315 | { 316 | $ScapInstallDir = $ScapInstallDir + "\" 317 | } 318 | $workingObj.ScapInstallDir = $ScapInstallDir 319 | } 320 | if($SQLInstanceName -ne '') 321 | { 322 | $workingObj.SQLInstanceName = $SQLInstanceName 323 | } 324 | if($DatabaseName -ne '') 325 | { 326 | $workingObj.DatabaseName = $DatabaseName 327 | } 328 | if($ScapProfile -ne '') 329 | { 330 | $workingObj.ScapProfile = $ScapProfile 331 | } 332 | if($ConcurrentScans -ne '') 333 | { 334 | $workingObj.ConcurrentScans = $ConcurrentScans 335 | } 336 | 337 | $someFile += "; All Entries are space sensitive. Further versions will fix input validation.`r`n" 338 | $someFile += "; Concurrent scan option is only used here if you are running a standalone function`r`n" 339 | $someFile += "; else it falls back to SQL configuration`r`n" 340 | $someFile += "`r`n" 341 | $someFile += "[general]`r`n" 342 | $someFile += "CKLOutPath=$($workingObj.CKLOutPath)`r`n" 343 | $someFile += "LogPath=$($workingObj.LogPath)`r`n" 344 | $someFile += "ConcurrentScans=$($workingObj.ConcurrentScans)`r`n" 345 | $someFile += "`r`n" 346 | $someFile += "[SCAP]`r`n" 347 | $someFile += "ScapProfile=$($WorkingObj.ScapProfile)`r`n" 348 | $someFile += "ScapInstallDir=$($workingObj.ScapInstallDir)`r`n" 349 | $someFile += "`r`n" 350 | $someFile += "[database]`r`n" 351 | $someFile += "SQLInstanceName=$($workingObj.SQLInstanceName)`r`n" 352 | $someFile += "DatabaseName=$($workingObj.DatabaseName)`r`n" 353 | 354 | $workingPath = Split-Path $PsCommandPath 355 | $someFile | Out-File -FilePath $workingPath\Config.ini 356 | } 357 | 358 | Function Get-PowerStigOrgSettings 359 | { 360 | [cmdletBinding()] 361 | param( 362 | [Parameter(Mandatory=$true)] 363 | [ValidateSet('2012R2','2016','10','All')] 364 | [String]$Version, 365 | 366 | [Parameter(Mandatory=$false)] 367 | [String]$OutPath, 368 | 369 | [Parameter(Mandatory=$false)] 370 | [String]$SqlInstanceName, 371 | 372 | [Parameter(Mandatory=$false)] 373 | [String]$DatabaseName 374 | ) 375 | 376 | DynamicParam { 377 | $ParameterName = 'Role' 378 | $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary 379 | $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] 380 | $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute 381 | $ParameterAttribute.Mandatory = $true 382 | $ParameterAttribute.ParameterSetName = 'Role' 383 | $AttributeCollection.Add($ParameterAttribute) 384 | $roleSet = Import-CSV "$(Split-Path $PsCommandPath)\Roles.csv" -Header Role | Select-Object -ExpandProperty Role 385 | $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($roleSet) 386 | $AttributeCollection.Add($ValidateSetAttribute) 387 | $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) 388 | $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) 389 | return $RuntimeParameterDictionary 390 | } 391 | 392 | begin{ 393 | $Role = $PSBoundParameters[$ParameterName] 394 | } 395 | 396 | process{ 397 | 398 | $workingPath = Split-Path $PsCommandPath 399 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 400 | 401 | if($null -eq $OutPath -or $OutPath -eq '') 402 | { 403 | $OutPath = "$($iniVar.LogPath)\PSOrgSettings\$($Role)_org.xml" 404 | } 405 | 406 | if($null -eq $sqlInstance -or $sqlInstance -eq '') 407 | { 408 | $sqlInstance = $iniVar.SqlInstanceName 409 | } 410 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 411 | { 412 | $DatabaseName = $iniVar.DatabaseName 413 | } 414 | 415 | 416 | $generateOrgXML = "PowerSTIG.sproc_GenerateORGxml @OSName = `"$Version`", @ComplianceType = `"$Role`"" 417 | [xml]$orgFile = (Invoke-PowerStigSqlCommand -SqlInstance $SqlInstanceName -DatabaseName $DatabaseName -Query $GenerateOrgXML).OrgXML 418 | 419 | $orgFile.Save($OutPath) | Out-Null 420 | } 421 | 422 | } 423 | #endregion Public -------------------------------------------------------------------------------- /src/SQL/500.sql: -------------------------------------------------------------------------------- 1 | -- =============================================================================================== 2 | -- =============================================================================================== 3 | -- Purpose: Deployment script for PowerSTIG database objects 4 | -- Revisions: 5 | -- =============================================================================================== 6 | -- =============================================================================================== 7 | /* 8 | Copyright (C) 2019 Microsoft Corporation 9 | Disclaimer: 10 | This is SAMPLE code that is NOT production ready. It is the sole intention of this code to provide a proof of concept as a 11 | learning tool for Microsoft Customers. Microsoft does not provide warranty for or guarantee any portion of this code 12 | and is NOT responsible for any affects it may have on any system it is executed on or environment it resides within. 13 | Please use this code at your own discretion! 14 | Additional legalize: 15 | This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment. 16 | THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 17 | INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 18 | We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute 19 | the object code form of the Sample Code, provided that You agree: 20 | (i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code is embedded; 21 | (ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded; and 22 | (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits, including attorneys� fees, 23 | that arise or result from the use or distribution of the Sample Code. 24 | */ 25 | -- =============================================================================================== 26 | -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 27 | -- =============================================================================================== 28 | DECLARE @StepName varchar(256) 29 | DECLARE @StepMessage varchar(768) 30 | DECLARE @ErrorMessage varchar(2000) 31 | DECLARE @ErrorSeverity tinyint 32 | DECLARE @ErrorState tinyint 33 | DECLARE @StepAction varchar(25) 34 | DECLARE @UpdateVersion smallint 35 | DECLARE @CurrentVersion smallint 36 | SET @UpdateVersion = 500 37 | -- =============================================================================================== 38 | -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 39 | -- =============================================================================================== 40 | IF OBJECT_ID('PowerSTIG.DBversion') IS NOT NULL 41 | BEGIN 42 | IF EXISTS (SELECT VersionID FROM PowerSTIG.DBversion WHERE UpdateVersion = @UpdateVersion AND isActive = 1) 43 | BEGIN 44 | SET @StepMessage = 'Update version ['+CAST(@UpdateVersion as varchar(5))+'] already applied. This is an informational message only.' 45 | SET @StepAction = 'DEPLOY' 46 | PRINT @StepMessage 47 | -- 48 | EXEC PowerSTIG.sproc_InsertScanLog 49 | @LogEntryTitle = @StepName 50 | ,@LogMessage = @StepMessage 51 | ,@ActionTaken = @StepAction 52 | -- 53 | -- Bail out of this script. Already applied. 54 | SELECT 8675309 AS UpdateApplied; 55 | THROW 8675309, 'Database update previously applied. This is an informational message only.', 1 56 | END 57 | END 58 | -- =============================================================================================== 59 | PRINT '///////////////////////////////////////////////////////' 60 | PRINT 'PowerStigScan database object deployment start - '+CONVERT(VARCHAR,GETDATE(), 21) 61 | PRINT '\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' 62 | -- =============================================================================================== 63 | DROP TABLE IF EXISTS __PowerStigDBdeployVersion 64 | -- 65 | CREATE TABLE __PowerStigDBdeployVersion (UpdateVersion smallint,CurrentVersion smallint) 66 | -- 67 | INSERT INTO __PowerStigDBdeployVersion (UpdateVersion,CurrentVersion) VALUES (@UpdateVersion,NULL) 68 | -- 69 | SET @StepMessage = 'Update version ['+CAST(@UpdateVersion as varchar(5))+'] not yet applied. Executing script now. This is an informational message only.' 70 | SET @StepAction = 'DEPLOY' 71 | PRINT @StepMessage 72 | -- 73 | EXEC PowerSTIG.sproc_InsertScanLog 74 | @LogEntryTitle = @StepName 75 | ,@LogMessage = @StepMessage 76 | ,@ActionTaken = @StepAction 77 | -- 78 | INSERT INTO PowerSTIG.DBversion (UpdateVersion,VersionTS,isActive,VersionNotes) 79 | VALUES 80 | (@UpdateVersion,GETDATE(),0,NULL) 81 | -- =============================================================================================== 82 | -- =============================================================================================== 83 | -- Drop constraints 84 | -- =============================================================================================== 85 | PRINT 'Begin drop constraints' 86 | -- 87 | IF (OBJECT_ID('PowerSTIG.FK_FindingRepo_ComplianceType', 'F') IS NOT NULL) 88 | ALTER TABLE [PowerSTIG].[FindingRepo] DROP CONSTRAINT [FK_FindingRepo_ComplianceType] 89 | -- 90 | IF (OBJECT_ID('PowerSTIG.FK_FindingRepo_TargetComputer', 'F') IS NOT NULL) 91 | ALTER TABLE [PowerSTIG].[FindingRepo] DROP CONSTRAINT [FK_FindingRepo_TargetComputer] 92 | -- 93 | IF (OBJECT_ID('PowerSTIG.FK_TargetComputer', 'F') IS NOT NULL) 94 | ALTER TABLE [PowerSTIG].[TargetTypeMap] DROP CONSTRAINT [FK_TargetComputer] 95 | -- 96 | IF (OBJECT_ID('PowerSTIG.FK_ComplianceType', 'F') IS NOT NULL) 97 | ALTER TABLE [PowerSTIG].[TargetTypeMap] DROP CONSTRAINT [FK_ComplianceType] 98 | -- 99 | IF (OBJECT_ID('PowerSTIG.FK_FindingRepo_FindingCategory', 'F') IS NOT NULL) 100 | ALTER TABLE [PowerSTIG].[FindingRepo] DROP CONSTRAINT [FK_FindingRepo_FindingCategory] 101 | -- 102 | IF (OBJECT_ID('PowerSTIG.FK_ComplianceCheckLog_TargetComputer', 'F') IS NOT NULL) 103 | ALTER TABLE [PowerSTIG].[ComplianceCheckLog] DROP CONSTRAINT [FK_ComplianceCheckLog_TargetComputer] 104 | -- 105 | IF (OBJECT_ID('PowerSTIG.FK_FindingRepo_Finding', 'F') IS NOT NULL) 106 | ALTER TABLE [PowerSTIG].[FindingRepo] DROP CONSTRAINT [FK_FindingRepo_Finding] 107 | -- 108 | IF (OBJECT_ID('PowerSTIG.FK_ComplianceCheckLog_ComplianceType', 'F') IS NOT NULL) 109 | ALTER TABLE [PowerSTIG].[ComplianceCheckLog] DROP CONSTRAINT [FK_ComplianceCheckLog_ComplianceType] 110 | -- 111 | PRINT 'End drop constraints' 112 | GO 113 | -- =============================================================================================== 114 | -- Drop tables 115 | -- =============================================================================================== 116 | PRINT 'Begin drop tables' 117 | -- 118 | DROP TABLE IF EXISTS PowerSTIG.TargetTypeMap 119 | -- 120 | DROP TABLE IF EXISTS PowerSTIG.ComplianceTypes 121 | -- 122 | DROP TABLE IF EXISTS PowerSTIG.ComplianceTargets 123 | -- 124 | DROP TABLE IF EXISTS PowerSTIG.ComplianceIteration 125 | -- 126 | DROP TABLE IF EXISTS PowerSTIG.FindingImport 127 | -- 128 | DROP TABLE IF EXISTS PowerSTIG.UnreachableTargets 129 | -- 130 | DROP TABLE IF EXISTS PowerSTIG.FindingImportFiles 131 | -- 132 | DROP TABLE IF EXISTS PowerSTIG.ComplianceCheckLog 133 | -- 134 | DROP TABLE IF EXISTS PowerSTIG.FindingRepo 135 | -- 136 | DROP TABLE IF EXISTS PowerSTIG.DupFindingFileCheck 137 | -- 138 | DROP TABLE IF EXISTS PowerSTIG.FindingSubPlatform 139 | -- 140 | DROP TABLE IF EXISTS PowerSTIG.ScanImportLog 141 | -- 142 | DROP TABLE IF EXISTS PowerSTIG.ScanImportErrorLog 143 | -- 144 | DROP TABLE IF EXISTS PowerStig.ScanQueue 145 | -- 146 | DROP TABLE IF EXISTS PowerSTIG.FindingCategory 147 | -- 148 | DROP TABLE IF EXISTS PowerSTIG.FindingSeverity 149 | -- 150 | IF (SELECT CAST(SERVERPROPERTY('ProductMajorVersion')AS smallint)) >= 13 151 | BEGIN 152 | DECLARE @SQLcmd varchar(4000) 153 | SET @SQLcmd =' 154 | IF OBJECT_ID (''PowerSTIG.ComplianceConfig'') IS NOT NULL 155 | BEGIN 156 | ALTER TABLE [PowerSTIG].[ComplianceConfig] SET ( SYSTEM_VERSIONING = OFF) 157 | DROP TABLE IF EXISTS PowerSTIG.ComplianceConfigHistory 158 | END' 159 | EXEC(@SQLcmd) 160 | END 161 | -- 162 | DROP TABLE IF EXISTS PowerSTIG.ComplianceConfig 163 | -- 164 | DROP TABLE IF EXISTS PowerSTIG.Finding 165 | -- 166 | DROP TABLE IF EXISTS PowerSTIG.Scans 167 | -- 168 | DROP TABLE IF EXISTS PowerSTIG.MemberServerSTIG 169 | -- 170 | DROP TABLE IF EXISTS PowerSTIG.OrgSettingsRepo 171 | -- 172 | DROP TABLE IF EXISTS PowerSTIG.FireFoxSTIG 173 | -- 174 | DROP TABLE IF EXISTS PowerSTIG.AdminFunction 175 | -- 176 | DROP TABLE IF EXISTS PowerSTIG.AdminFunctionUsers 177 | -- 178 | DROP TABLE IF EXISTS PowerSTIG.AdminFunctionsMap 179 | -- 180 | DROP TABLE IF EXISTS PowerSTIG.StigText 181 | -- 182 | DROP TABLE IF EXISTS PowerSTIG.StigTextRepo 183 | -- 184 | DROP TABLE IF EXISTS PowerSTIG.ScanSource 185 | -- 186 | DROP TABLE IF EXISTS PowerSTIG.TargetTypeOS 187 | -- 188 | DROP TABLE IF EXISTS PowerSTIG.ComplianceTypesInfo 189 | -- 190 | DROP TABLE IF EXISTS PowerSTIG.RSpages 191 | -- 192 | DROP TABLE IF EXISTS PowerSTIG.ComplianceTargetRoles 193 | -- 194 | PRINT 'End drop tables' 195 | GO 196 | -- =============================================================================================== 197 | -- Drop views 198 | -- =============================================================================================== 199 | PRINT 'Begin drop views' 200 | DROP VIEW IF EXISTS PowerSTIG.vw_TargetTypeMap 201 | -- 202 | DROP VIEW IF EXISTS PowerSTIG.v_BulkFindingImport 203 | -- 204 | DROP VIEW IF EXISTS PowerSTIG.ComplianceSourceMap 205 | PRINT 'End drop views' 206 | GO 207 | -- =============================================================================================== 208 | -- Create tables 209 | -- =============================================================================================== 210 | PRINT 'Begin create tables' 211 | ---- 212 | CREATE TABLE PowerSTIG.Scans ( 213 | [ScanID] [int] IDENTITY(1,1) NOT NULL, 214 | [ScanGUID] [char](36) NOT NULL, 215 | [ScanSourceID] smallint NOT NULL, 216 | [ScanDate] [datetime] NOT NULL, 217 | [ScanVersion] varchar(8) NULL, 218 | [isProcessed] [bit] NOT NULL DEFAULT(0)) 219 | -- 220 | CREATE TABLE [PowerSTIG].[FindingSeverity]( 221 | [FindingSeverityID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY, 222 | [FindingSeverity] [varchar](128) NOT NULL) 223 | -- 224 | CREATE TABLE PowerSTIG.FindingCategory( 225 | FindingCategoryID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 226 | FindingCategory varchar(128) NOT NULL) 227 | -- 228 | CREATE TABLE PowerSTIG.Finding( 229 | FindingID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 230 | Finding varchar(128) NOT NULL, 231 | FindingText varchar(768) NULL) 232 | -- 233 | CREATE TABLE PowerSTIG.ComplianceTargets ( 234 | TargetComputerID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 235 | TargetComputer varchar(256) NOT NULL UNIQUE, 236 | isActive BIT NOT NULL DEFAULT(1), 237 | LastComplianceCheck datetime NOT NULL DEFAULT('1900-01-01 00:00:00.000'), 238 | OSid smallint NOT NULL DEFAULT(0), 239 | [IPv4address] varchar(15) NULL, 240 | [IPv6address] varchar(45) NULL, 241 | [MACaddress] varchar(17) NULL, 242 | [FQDN] varchar(384) NULL) 243 | -- 244 | CREATE TABLE PowerSTIG.ComplianceTypes ( 245 | ComplianceTypeID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 246 | ComplianceType varchar(256) NOT NULL UNIQUE, 247 | isActive BIT NOT NULL DEFAULT(1)) 248 | -- 249 | CREATE TABLE PowerSTIG.ComplianceCheckLog( 250 | CheckLogID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 251 | ScanID INT NOT NULL, 252 | TargetComputerID INT NOT NULL, 253 | ComplianceTypeID INT NOT NULL, 254 | LastComplianceCheck datetime NOT NULL DEFAULT('1900-01-01 00:00:00.000')) 255 | -- 256 | CREATE TABLE PowerSTIG.FindingRepo( 257 | [TargetComputerID] [int] NOT NULL, 258 | [FindingID] [int] NOT NULL, 259 | [InDesiredState] [bit] NOT NULL, 260 | [ComplianceTypeID] [int] NOT NULL, 261 | [ScanID] [int] NOT NULL) 262 | -- 263 | CREATE TABLE PowerStig.ScanQueue ( 264 | ScanQueueID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 265 | TargetComputer varchar(256) NOT NULL, 266 | ComplianceType varchar(256) NOT NULL, 267 | QueueStart datetime NOT NULL, 268 | QueueEnd datetime NOT NULL DEFAULT('1900-01-01 00:00:00.000')) 269 | -- 270 | CREATE TABLE PowerSTIG.ComplianceConfig ( 271 | ConfigID SMALLINT IDENTITY(1,1) NOT NULL PRIMARY KEY, 272 | ConfigProperty varchar(256) NOT NULL, 273 | ConfigSetting varchar(256) NOT NULL, 274 | ConfigNote varchar(1000) NULL, 275 | SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, 276 | SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, 277 | PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)) 278 | WITH 279 | ( 280 | SYSTEM_VERSIONING = ON (HISTORY_TABLE = PowerSTIG.ComplianceConfigHistory) 281 | ) 282 | -- 283 | CREATE TABLE PowerSTIG.FindingImport ( 284 | [TargetComputer] [varchar](255) NULL, 285 | [VulnID] [varchar](25) NULL, 286 | [StigType] [varchar](256) NULL, 287 | [DesiredState] [varchar](25) NULL, 288 | [ScanDate] [datetime] NULL, 289 | [GUID] [char](36) NULL, 290 | [ScanSource] varchar(25) NULL, 291 | [ImportDate] [datetime] NULL, 292 | [ScanVersion] varchar(8) NULL) 293 | -- 294 | CREATE TABLE PowerSTIG.AdminFunction ( 295 | FunctionID smallint IDENTITY(1,1) NOT NULL PRIMARY KEY, 296 | FunctionName varchar(128) NOT NULL UNIQUE, 297 | FunctionDescription varchar(768) NOT NULL DEFAULT('No function description specified.'), 298 | FunctionPage varchar(128) NULL, 299 | isActive BIT NOT NULL DEFAULT(0)) 300 | -- 301 | CREATE TABLE PowerSTIG.AdminFunctionUsers ( 302 | AdminID smallint IDENTITY(1,1) NOT NULL PRIMARY KEY, 303 | FQDNandAdmin varchar(256) NOT NULL UNIQUE) 304 | -- 305 | CREATE TABLE PowerSTIG.AdminFunctionsMap ( 306 | FunctionMapID smallint IDENTITY(1,1) NOT NULL PRIMARY KEY, 307 | FunctionID smallint NOT NULL, 308 | AdminID smallint NOT NULL, 309 | isActive BIT NOT NULL DEFAULT(1)) 310 | -- 311 | CREATE TABLE [PowerSTIG].[StigTextRepo]( 312 | [TextID] [int] IDENTITY(1,1) NOT NULL, 313 | [RuleID] [nvarchar](25) NOT NULL, 314 | [Severity] [nvarchar](25) NOT NULL, 315 | [Title] [nvarchar](1000) NOT NULL, 316 | [DSCresource] [nvarchar](256) NOT NULL, 317 | [RawString] [nvarchar](max) NOT NULL) 318 | -- 319 | CREATE TABLE PowerSTIG.ScanSource ( 320 | ScanSourceID smallint IDENTITY(1,1) NOT NULL PRIMARY KEY, 321 | ScanSource varchar(25) NOT NULL UNIQUE) 322 | -- 323 | CREATE TABLE PowerSTIG.TargetTypeOS( 324 | OSid smallint IDENTITY(1,1) NOT NULL PRIMARY KEY, 325 | OSname varchar(256) NOT NULL UNIQUE) 326 | -- 327 | CREATE TABLE PowerSTIG.OrgSettingsRepo ( 328 | OrgRepoID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 329 | TypesInfoID INT NOT NULL, 330 | Finding varchar(128) NULL, 331 | OrgValue varchar(4000)NULL) 332 | -- 333 | CREATE TABLE PowerSTIG.ComplianceTypesInfo ( 334 | TypesInfoID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 335 | ComplianceTypeID INT NOT NULL, 336 | OSid smallint NOT NULL DEFAULT(0), 337 | OrgValue varchar(10), 338 | OrgSettingAlias varchar(128) NOT NULL, 339 | OrgSettingFile varchar(256) NOT NULL) 340 | -- 341 | CREATE TABLE PowerSTIG.RSpages ( 342 | RSpageID smallint IDENTITY(1,1) NOT NULL PRIMARY KEY, 343 | PageName varchar(256) NOT NULL UNIQUE, 344 | ReportName varchar(256) NOT NULL UNIQUE, 345 | PageDescription varchar(512) NULL, 346 | ReportOrder smallint NOT NULL DEFAULT(2), 347 | isActive BIT NOT NULL DEFAULT(1)) 348 | -- 349 | CREATE TABLE PowerSTIG.ComplianceTargetRoles ( 350 | TargetRoleID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 351 | TargetComputerID INT NOT NULL, 352 | ComplianceTypeID INT NOT NULL, 353 | LastScanID INT NOT NULL) 354 | -- 355 | PRINT 'End create tables' 356 | -- =============================================================================================== 357 | -- Create views 358 | -- =============================================================================================== 359 | PRINT 'Begin create views' 360 | GO 361 | CREATE OR ALTER VIEW PowerSTIG.ComplianceSourceMap 362 | AS 363 | --------------------------------------------------------------------------------- 364 | -- The sample scripts are not supported under any Microsoft standard support 365 | -- program or service. The sample scripts are provided AS IS without warranty 366 | -- of any kind. Microsoft further disclaims all implied warranties including, 367 | -- without limitation, any implied warranties of merchantability or of fitness for 368 | -- a particular purpose. The entire risk arising out of the use or performance of 369 | -- the sample scripts and documentation remains with you. In no event shall 370 | -- Microsoft, its authors, or anyone else involved in the creation, production, or 371 | -- delivery of the scripts be liable for any damages whatsoever (including, 372 | -- without limitation, damages for loss of business profits, business interruption, 373 | -- loss of business information, or other pecuniary loss) arising out of the use 374 | -- of or inability to use the sample scripts or documentation, even if Microsoft 375 | -- has been advised of the possibility of such damages 376 | --------------------------------------------------------------------------------- 377 | -- =============================================================================================== 378 | -- PURPOSE: Combines Scans.ScanSourceID with ComplianceCheckLog for simplified queries. 379 | -- REVISIONS: 380 | -- 05212019 - Kevin Barlett, Microsoft - Initial creation. 381 | -- EXAMPLES: 382 | -- SELECT * FROM PowerSTIG.ComplianceSourceMap 383 | -- =============================================================================================== 384 | SELECT 385 | L.ScanID 386 | ,L.TargetComputerID 387 | ,L.ComplianceTypeID 388 | ,S.ScanSourceID 389 | ,L.LastComplianceCheck 390 | FROM 391 | PowerSTIG.ComplianceCheckLog L 392 | JOIN 393 | PowerSTIG.Scans S 394 | ON 395 | L.ScanID = S.ScanID 396 | GO 397 | -- =============================================================================================== 398 | -- Hydrate ComplianceConfig table 399 | -- =============================================================================================== 400 | PRINT 'Hydrating PowerSTIG.ComplianceConfig table' 401 | -- 402 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('FindingRepoTableRetentionDays','365',NULL) 403 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('LastComplianceCheckAlert','OFF','Possible values are ON or OFF. Controls whether the last compliance type checks for a target computer has violated the LastComplianceCheckInDays threshold.') 404 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('LastComplianceCheckInDays','90','Specifies the number of days that a compliance type check for a target computer may not occur.') 405 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('LastComplianceCheckAlertRecipients','Replace with valid email addresses','Recipient(s) for PowerStigScan notifications') 406 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('ComplianceCheckLogTableRetentionDays','365',NULL) 407 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('FindingImportFilesTableRetentionDays','365',NULL) 408 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('MailProfileName','Replace with SQL Mail Profile Name','SQL Server Database Mail profile for use with sending outbound mail') 409 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('ScanImportLogRetentionDays','365',NULL) 410 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('ScanImportErrorLogRetentionDays','365',NULL) 411 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('ScanLogRetentionDays','730','This setting controls the number of days of history to store in the PowerSTIG.ScanLog table.') 412 | INSERT INTO PowerSTIG.ComplianceConfig (ConfigProperty,ConfigSetting,ConfigNote) VALUES ('ORGsettingXML','C:\Program Files\WindowsPowerShell\Modules\PowerSTIG\3.1.0\StigData\Processed','This setting sets the location of the PowerStig ORG setting XML files.') 413 | GO 414 | -- =============================================================================================== 415 | -- Hydrate compliance types 416 | -- =============================================================================================== 417 | PRINT 'Hydrating compliance types in PowerSTIG.ComplianceTypes' 418 | -- 419 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('DotNetFramework',1) 420 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('FireFox',1) 421 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('IISServer',1) 422 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('IISSite',1) 423 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('InternetExplorer',1) 424 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('Excel2013',1) 425 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('Outlook2013',1) 426 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('PowerPoint2013',1) 427 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('Word2013',1) 428 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('OracleJRE',1) 429 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('SqlServer-2012-Database',1) 430 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('SqlServer-2012-Instance',1) 431 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('SqlServer-2016-Instance',1) 432 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('WindowsClient',1) 433 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('WindowsDefender',1) 434 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('WindowsDNSServer',1) 435 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('WindowsFirewall',1) 436 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('WindowsServer-DC',1) 437 | INSERT INTO PowerSTIG.ComplianceTypes (ComplianceType,isActive) VALUES ('WindowsServer-MS',1) 438 | -- 439 | GO 440 | -- =============================================================================================== 441 | -- Hydrate AdminFunction 442 | -- =============================================================================================== 443 | PRINT 'Hydrating admin functions in PowerSTIG.AdminFunction' 444 | INSERT INTO PowerSTIG.AdminFunction (FunctionName,FunctionDescription,FunctionPage,isActive) VALUES ('View Scan Log','View the Scan Log','ScanLog',1) 445 | INSERT INTO PowerSTIG.AdminFunction (FunctionName,FunctionDescription,FunctionPage,isActive) VALUES ('View Scan Queue',DEFAULT,'QueuedScans',1) 446 | INSERT INTO PowerSTIG.AdminFunction (FunctionName,FunctionDescription,FunctionPage,isActive) VALUES ('Add Target Computer',DEFAULT,'AddTargetComputer',1) 447 | INSERT INTO PowerSTIG.AdminFunction (FunctionName,FunctionDescription,FunctionPage,isActive) VALUES ('Initiate Scan',DEFAULT,NULL,1) 448 | INSERT INTO PowerSTIG.AdminFunction (FunctionName,FunctionDescription,FunctionPage,isActive) VALUES ('Modify Target Computer Roles',DEFAULT,NULL,1) 449 | INSERT INTO PowerSTIG.AdminFunction (FunctionName,FunctionDescription,FunctionPage,isActive) VALUES ('Modify ORG settings',DEFAULT,NULL,1) 450 | INSERT INTO PowerSTIG.AdminFunction (FunctionName,FunctionDescription,FunctionPage,isActive) VALUES ('View ORG settings',DEFAULT,NULL,1) 451 | INSERT INTO PowerSTIG.AdminFunction (FunctionName,FunctionDescription,FunctionPage,isActive) VALUES ('Add ORG setting',DEFAULT,NULL,1) 452 | GO 453 | -- =============================================================================================== 454 | -- Hydrate ScanSource 455 | -- =============================================================================================== 456 | PRINT 'Hydrating PowerSTIG.ScanSource' 457 | INSERT INTO PowerSTIG.ScanSource (ScanSource) VALUES ('SCAP') 458 | INSERT INTO PowerSTIG.ScanSource (ScanSource) VALUES ('POWERSTIG') 459 | GO 460 | -- =============================================================================================== 461 | -- Hydrate TargetTypeOS 462 | -- =============================================================================================== 463 | PRINT 'Hydrating PowerSTIG.TargetTypeOS' 464 | INSERT INTO PowerSTIG.TargetTypeOS (OSname) VALUES ('2012R2') 465 | INSERT INTO PowerSTIG.TargetTypeOS (OSname) VALUES ('2016') 466 | INSERT INTO PowerSTIG.TargetTypeOS (OSname) VALUES ('10') 467 | INSERT INTO PowerSTIG.TargetTypeOS (OSname) VALUES ('ALL') 468 | GO 469 | -- =============================================================================================== 470 | -- Hydrate RSpages 471 | -- =============================================================================================== 472 | PRINT 'Hydrating PowerSTIG.RSpages' 473 | INSERT INTO powerstig.rspages VALUES ('View Org Settings','ViewOrgSettings','This report displays the current ORG specific settings.',2,1) 474 | INSERT INTO powerstig.rspages VALUES ('View Scan Queue','ScanQueue','This report displays the current scan queue.',2,1) 475 | INSERT INTO powerstig.rspages VALUES ('Last Compliance Check','LastComplianceCheckByRoleAndTarget','This report displays the last compliance check by target computer and role.',2,1) 476 | INSERT INTO powerstig.rspages VALUES ('Edit Org Settings','EditOrgSettings','Use this page to modify and save ORG settings.',2,0) 477 | INSERT INTO powerstig.rspages VALUES ('Detailed Scan Results','DetailedScanResults','Use this report to view scan results by target and role with full STIG text.',2,1) 478 | INSERT INTO powerstig.rspages VALUES ('PowerSTIGscan Dashboard','PowerSTIGdashboardV1','Main report.',1,1) 479 | INSERT INTO powerstig.rspages VALUES ('View Scan Log','ViewScanLog','Use this report to view Scan Log entries for a specific date.',2,1) 480 | GO 481 | -- =============================================================================================== 482 | -- Create constraints 483 | -- =============================================================================================== 484 | PRINT 'Begin create constraints' 485 | -- 486 | ALTER TABLE PowerSTIG.FindingRepo WITH NOCHECK ADD CONSTRAINT [FK_FindingRepo_TargetComputer] 487 | FOREIGN KEY (TargetComputerID) REFERENCES [PowerSTIG].[ComplianceTargets] (TargetComputerID) 488 | -- 489 | ALTER TABLE PowerSTIG.FindingRepo WITH NOCHECK ADD CONSTRAINT [FK_FindingRepo_ComplianceType] 490 | FOREIGN KEY (ComplianceTypeID) REFERENCES [PowerSTIG].[ComplianceTypes] (ComplianceTypeID) 491 | -- 492 | ALTER TABLE PowerSTIG.ComplianceCheckLog WITH NOCHECK ADD CONSTRAINT [FK_ComplianceCheckLog_TargetComputer] 493 | FOREIGN KEY (TargetComputerID) REFERENCES [PowerSTIG].[ComplianceTargets] (TargetComputerID) 494 | -- 495 | ALTER TABLE PowerSTIG.ComplianceCheckLog WITH NOCHECK ADD CONSTRAINT [FK_ComplianceCheckLog_ComplianceType] 496 | FOREIGN KEY (ComplianceTypeID) REFERENCES [PowerSTIG].[ComplianceTypes] (ComplianceTypeID) 497 | -- 498 | ALTER TABLE PowerSTIG.FindingRepo WITH NOCHECK ADD CONSTRAINT [FK_FindingRepo_Finding] 499 | FOREIGN KEY (FindingID) REFERENCES [PowerSTIG].[Finding] (FindingID) 500 | -- 501 | PRINT 'End create constraints' 502 | GO 503 | -- =============================================================================================== 504 | -- Indexes 505 | -- =============================================================================================== 506 | PRINT 'Begin create indexes' 507 | -- 508 | IF NOT EXISTS (SELECT name FROM sys.indexes WHERE name = 'IX_UNQ_ConfigProperty') 509 | CREATE UNIQUE NONCLUSTERED INDEX IX_UNQ_ConfigProperty ON PowerSTIG.ComplianceConfig(ConfigProperty) 510 | -- 511 | IF NOT EXISTS (SELECT name FROM sys.indexes WHERE name = 'IX_UNQ_FunctionAdmin') 512 | CREATE UNIQUE NONCLUSTERED INDEX IX_UNQ_FunctionAdmin ON PowerSTIG.AdminFunctionsMap (FunctionID,AdminID) 513 | -- 514 | IF NOT EXISTS (SELECT name FROM sys.indexes WHERE name = 'IX_TargetComplianceCheck') 515 | CREATE NONCLUSTERED INDEX [IX_TargetComplianceCheck] ON PowerSTIG.ComplianceCheckLog(TargetComputerID,ComplianceTypeID,LastComplianceCheck) 516 | -- 517 | IF NOT EXISTS (SELECT name FROM sys.indexes WHERE name = 'IX_UNQ_OrgSettingsRepo') 518 | CREATE UNIQUE NONCLUSTERED INDEX IX_UNQ_OrgSettingsRepo ON PowerSTIG.OrgSettingsRepo (TypesInfoID,Finding) 519 | -- 520 | IF NOT EXISTS (SELECT name FROM sys.indexes WHERE name = 'IX_UNQ_Repo') 521 | CREATE UNIQUE NONCLUSTERED INDEX IX_UNQ_Repo ON PowerSTIG.FindingRepo (TargetComputerID,FindingID,ComplianceTypeID,ScanID) 522 | -- 523 | IF NOT EXISTS (SELECT name FROM sys.indexes WHERE name = 'IX_UNQ_BaseUpdate') 524 | CREATE UNIQUE NONCLUSTERED INDEX IX_UNQ_BaseUpdate ON PowerSTIG.DBversion(UpdateVersion) 525 | PRINT 'End create indexes' 526 | GO 527 | -- =============================================================================================== 528 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 529 | -- Logging 530 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 531 | -- =============================================================================================== 532 | DECLARE @StepName varchar(256) 533 | DECLARE @StepMessage varchar(768) 534 | DECLARE @ErrorMessage varchar(2000) 535 | DECLARE @ErrorSeverity tinyint 536 | DECLARE @ErrorState tinyint 537 | DECLARE @StepAction varchar(25) 538 | DECLARE @UpdateVersion SMALLINT 539 | DECLARE @CurrentVersion smallint 540 | SET @UpdateVersion = (SELECT TOP 1 UpdateVersion FROM __PowerStigDBdeployVersion) 541 | SET @CurrentVersion = (SELECT TOP 1 CurrentVersion FROM __PowerStigDBdeployVersion) 542 | SET @StepMessage = 'Update version ['+CAST(@UpdateVersion as varchar(5))+'] successfully applied. This is an informational message only.' 543 | SET @StepAction = 'DEPLOY' 544 | PRINT @StepMessage 545 | -- 546 | EXEC PowerSTIG.sproc_InsertScanLog 547 | @LogEntryTitle = @StepName 548 | ,@LogMessage = @StepMessage 549 | ,@ActionTaken = @StepAction 550 | -- 551 | UPDATE 552 | PowerSTIG.DBversion 553 | SET 554 | isActive = 1 555 | WHERE 556 | UpdateVersion = @UpdateVersion 557 | -- =============================================================================================== 558 | -- /////////////////////////////////////////////////////////////////////////////////////////////// 559 | -- =============================================================================================== 560 | DROP TABLE IF EXISTS __PowerStigDBdeployVersion 561 | -- =============================================================================================== 562 | PRINT '///////////////////////////////////////////////////////' 563 | PRINT 'PowerStigScan database object deployment complete - '+CONVERT(VARCHAR,GETDATE(), 21) 564 | PRINT '\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' 565 | -- =============================================================================================== -------------------------------------------------------------------------------- /src/Common/PowerStigScan.Main.ps1: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------------------------- 2 | # 3 | # Copyright (C) 2018 Microsoft Corporation 4 | # 5 | # Disclaimer: 6 | # This is SAMPLE code that is NOT production ready. It is the sole intention of this code to provide a proof of concept as a 7 | # learning tool for Microsoft Customers. Microsoft does not provide warranty for or guarantee any portion of this code 8 | # and is NOT responsible for any affects it may have on any system it is executed on or environment it resides within. 9 | # Please use this code at your own discretion! 10 | # Additional legalese: 11 | # This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment. 12 | # THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 13 | # INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 14 | # We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute 15 | # the object code form of the Sample Code, provided that You agree: 16 | # (i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code is embedded; 17 | # (ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded; and 18 | # (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits, including attorneys' fees, 19 | # that arise or result from the use or distribution of the Sample Code. 20 | # ----------------------------------------------------------------------------- 21 | 22 | <# 23 | Functions: 24 | Private: 25 | M01 - Get-Time 26 | M02 - InsertLog 27 | M03 - Get-PowerStigXMLPath 28 | M04 - Get-PowerStigXMLVersion 29 | M05 - Get-PowerStigServerRole 30 | M06 - Get-ServerVersion 31 | R01 - Get-PowerStigIsOffice 32 | R02 - Get-PowerStigIsIE 33 | R03 - Get-PowerStigIsDotNet 34 | R04 - Get-PowerStigIsFireFox 35 | R05 - Get-PowerStigIsFirewall 36 | R06 - Get-PowerStigIsIIS 37 | R07 - Get-PowerStigIsDNS 38 | R08 - Get-PowerStigIsSQL 39 | R09 - Get-PowerStigIsJRE 40 | Public: 41 | M07 - Invoke-PowerStigScan 42 | M08 - Invoke-PowerStigBatch 43 | #> 44 | 45 | #region Private 46 | 47 | #M01 48 | function Get-Time 49 | { 50 | return (get-date -UFormat %H:%M.%S) 51 | } 52 | 53 | #M02 54 | function InsertLog 55 | { 56 | param( 57 | [Parameter(Mandatory=$true)] 58 | [string]$LogEntryTitle, 59 | 60 | [Parameter(Mandatory=$true)] 61 | [string]$LogMessage, 62 | 63 | [Parameter(Mandatory=$true)] 64 | [ValidateSet('Insert', 'Update', 'Delete', 'Deploy', 'Error')] 65 | [string]$ActionTaken, 66 | 67 | [Parameter(Mandatory=$true)] 68 | [String]$CMSserver, 69 | 70 | [Parameter(Mandatory=$true)] 71 | [String]$CMSDatabaseName 72 | ) 73 | 74 | $InsertLog = "EXEC PowerSTIG.sproc_InsertScanLog @LogEntryTitle = '$LogEntryTitle',@LogMessage = '$LogMessage',@ActionTaken = '$ActionTaken'" 75 | Invoke-PowerStigSqlCommand -SQLInstance $CMSserver -DatabaseName $CMSDatabaseName -query $InsertLog 76 | } 77 | 78 | #M03 79 | function Get-PowerStigXMLPath 80 | { 81 | $powerStigXMLPath = "$($(get-module PowerSTIG).ModuleBase)\StigData\Processed" 82 | Return $powerStigXMLPath 83 | } 84 | 85 | #M04 86 | <# 87 | .SYNOPSIS 88 | Determine the newest stig version that is in the PowerStig directory 89 | 90 | .DESCRIPTION 91 | Will pull the version number from the STIGs until the highest number is returned 92 | 93 | .PARAMETER role 94 | The role that is being tested, valid options are DC (Domain Controller), DNS, MS (Member Server), ADDomain, ADForest, IE11, and IE11 95 | 96 | .PARAMETER osVersion 97 | Operating System version that is being targeted. Valid options are 2012R2 and 2016 98 | 99 | .EXAMPLE 100 | Get-PowerStigXmlVersion -Role DC -osVersion 2012R2 101 | 102 | #> 103 | function Get-PowerStigXmlVersion 104 | { 105 | [cmdletBinding()] 106 | param( 107 | [Parameter(Mandatory=$false)] 108 | [string]$osVersion 109 | ) 110 | 111 | DynamicParam { 112 | $ParameterName = 'Role' 113 | $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary 114 | $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] 115 | $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute 116 | $ParameterAttribute.Mandatory = $true 117 | $AttributeCollection.Add($ParameterAttribute) 118 | $roleSet = Import-CSV "$(Split-Path $PsCommandPath)\Roles.csv" -Header Role | Select-Object -ExpandProperty Role 119 | $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($roleSet) 120 | $AttributeCollection.Add($ValidateSetAttribute) 121 | $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) 122 | $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) 123 | return $RuntimeParameterDictionary 124 | } 125 | 126 | begin{ 127 | $Role = $PSBoundParameters[$ParameterName] 128 | } 129 | 130 | process{ 131 | [System.Array]$StigXmlBase = (get-childitem -path (Get-PowerStigXMLPath)).name 132 | # Regex pattern that tests for up to a two digit number followed by a decimal followed by up to a two digit number (i.e. 12.12,2.8,9.1) 133 | [regex]$RegexTest = "([1-9])?[0-9]\.[0-9]([0-9])?" 134 | # Holder variable for the current high value matching the previous regex 135 | $highVer = $null 136 | [System.Array]$StigXmlOs = @() 137 | 138 | # Test if the role is similar to ADDomain, ADForest, IE, or FW. If so then ensure that the OS Version is set to all 139 | Switch($Role) 140 | { 141 | "DotNetFramework" {$rRole = "DotNetFramework-4"; $osVersion = $null} 142 | "FireFox" {$rRole = "FireFox"; $osVersion = $null} 143 | "IISServer" {$rRole = "IISServer-8.5"; $osVersion = $null} 144 | "IISSite" {$rRole = "IISSite-8.5"; $osVersion = $null} 145 | "InternetExplorer" {$rRole = "InternetExplorer-11"; $osVersion = $null} 146 | "Excel2013" {$rRole = "Office-Excel2013"; $osVersion = $null} 147 | "Outlook2013" {$rRole = "Office-Outlook2013"; $osVersion = $null} 148 | "PowerPoint2013" {$rRole = "Office-PowerPoint2013"; $osVersion = $null} 149 | "Word2013" {$rRole = "Office-Word2013"; $osVersion = $null} 150 | "OracleJRE" {$rRole = "OracleJRE-8"; $osVersion = $null} 151 | "SqlServer-2012-Database" {$rRole = "SqlServer-2012-Database";$osVersion = $null} 152 | "SqlServer-2012-Instance" {$rRole = "SqlServer-2012-Instance";$osVersion = $null} 153 | "SqlServer-2016-Instance" {$rRole = "SqlServer-2016-Instance";$osVersion = $null} 154 | "WindowsClient" {$rRole = "WindowsClient-10"; $osVersion = $null} 155 | "WindowsDefender" {$rRole = "WindowsDefender-All"; $osVersion = $null} 156 | "WindowsDNSServer" {$rRole = "WindowsDNSServer-2012R2";$osVersion = $null} 157 | "WindowsFirewall" {$rRole = "WindowsFirewall-All"; $osVersion = $null} 158 | "WindowsServer-DC" {if($osVersion -eq "2012R2"){$rRole = "WindowsServer-2012R2-DC"}else{$rRole = "WindowsServer-2016-DC"}} 159 | "WindowsServer-MS" {if($osVersion -eq "2012R2"){$rRole = "WindowsServer-2012R2-MS"}else{$rRole = "WindowsServer-2016-MS"}} 160 | } 161 | 162 | # Parse through repository for STIGs that match only the current OS that we are looking for 163 | if($osVersion -ne "" -and $null -ne $osVersion) 164 | { 165 | foreach($a in $StigXMLBase) 166 | { 167 | if ($a -like "*$osVersion*") 168 | { 169 | $StigXmlOs += $a 170 | } 171 | } 172 | } 173 | else { 174 | $StigXMLOs = $StigXMLBase 175 | } 176 | 177 | # If previous check returns nothing, notify the user and terminate the function 178 | if($StigXmlOs.Count -eq 0) 179 | { 180 | Write-Error -Message "No STIGs Matching Desired OS" 181 | Return $null 182 | } 183 | 184 | foreach($g in $StigXmlOs) 185 | { 186 | if($g -like "*$rRole*") 187 | { 188 | if($g -match $RegexTest) 189 | { 190 | [version]$wStigVer = ($RegexTest.Matches($g)).value 191 | } 192 | 193 | if($null -eq $highVer) 194 | { 195 | [version]$highVer = $wStigVer 196 | } 197 | elseif ($wStigVer -gt $highVer) 198 | { 199 | $highVer = $wStigVer 200 | } 201 | } 202 | } 203 | $stringout = $highVer.Major.ToString() + "." + $highVer.Minor.ToString() 204 | 205 | Return $stringout 206 | 207 | } 208 | 209 | } 210 | 211 | function Get-PowerStigOSandFunction 212 | { 213 | [cmdletBinding()] 214 | param( 215 | [Parameter(Mandatory=$true)] 216 | [String]$ServerName 217 | ) 218 | 219 | $osVersion = (Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ServerName).Version 220 | $domainRole = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ServerName).DomainRole 221 | 222 | if($domainRole -eq 4 -or $domainRole -eq 5) 223 | { 224 | $role = "DC" 225 | $osVersion = Get-ServerVersion -osVersion $osVersion 226 | } 227 | elseif($domainRole -eq 2 -or $domainRole -eq 3) 228 | { 229 | $role = "MS" 230 | $osVersion = Get-ServerVersion -osVersion $osVersion 231 | } 232 | elseif($domainRole -eq 0 -or $domainRole -eq 1) 233 | { 234 | $role = "Client" 235 | $osVersion = "10" 236 | } 237 | 238 | Return New-Object -TypeName PSObject -Property @{ 239 | Role=$role 240 | OSVersion=$osVersion 241 | } 242 | } 243 | 244 | function Get-PowerStigServerRole 245 | { 246 | [CmdletBinding()] 247 | param( 248 | [Parameter(Mandatory=$true)] 249 | [String]$ServerName 250 | ) 251 | 252 | # Initialize Role Array 253 | $arrRole = @() 254 | 255 | # Gather domain role and OS version 256 | $domainRole = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ServerName).DomainRole 257 | $osVersion = (Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ServerName).Version 258 | 259 | # Determine MemberServer/Client/DomainController 260 | if($domainRole -eq 4 -or $domainRole -eq 5) 261 | { 262 | $arrRole += "WindowsServer-DC" 263 | $outVersion = Get-ServerVersion -osVersion $osVersion 264 | }elseif($domainRole -eq 2 -or $domainRole -eq 3) 265 | { 266 | $arrRole += "WindowsServer-MS" 267 | $outVersion = Get-ServerVersion -osVersion $osVersion 268 | }elseif($domainRole -eq 0 -or $domainRole -eq 1) 269 | { 270 | $arrRole += "WindowsClient" 271 | if($osVersion -like "10.*") 272 | { 273 | $outVersion = "10" 274 | }else{ 275 | Return 100 276 | } 277 | } 278 | 279 | if($arrRole -contains "WindowsServer-MS" -or $arrRole -contains "WindowsServer-DC") 280 | { 281 | if(Get-PowerStigIsOffice -ServerName $ServerName) 282 | { 283 | $arrRole += "Outlook2013" 284 | $arrRole += "PowerPoint2013" 285 | $arrRole += "Excel2013" 286 | $arrRole += "Word2013" 287 | } 288 | if(Get-PowerStigIsIE -ServerName $ServerName) 289 | { 290 | $arrRole += "InternetExplorer" 291 | } 292 | if(Get-PowerStigIsDotNet -ServerName $ServerName) 293 | { 294 | $arrRole += "DotNetFramework" 295 | } 296 | if(Get-PowerStigIsFireFox -ServerName $ServerName) 297 | { 298 | $arrRole += "FireFox" 299 | } 300 | if(Get-PowerStigIsFirewall -ServerName $ServerName) 301 | { 302 | $arrRole += "WindowsFirewall" 303 | } 304 | if(Get-PowerStigIsIIS -ServerName $ServerName) # MUSTREDO 305 | { 306 | $arrRole += "IISServer" 307 | $arrRole += "IISSite" 308 | } 309 | if(Get-PowerStigIsSQL -ServerName $ServerName) # MUSTREDO 310 | { 311 | $arrRole += "SQL" 312 | } 313 | if(Get-PowerStigIsJRE -ServerName $ServerName) 314 | { 315 | $arrRole += "OracleJRE" 316 | } 317 | if((Get-PowerStigIsDNS -ServerName $ServerName) -and $osVersion -notlike "10.*") 318 | { 319 | $arrRole += "WindowsDNSServer" 320 | } 321 | }elseif($arrRole -contains "WindowsClient") 322 | { 323 | if(Get-PowerStigIsOffice -ServerName $ServerName) 324 | { 325 | $arrRole += "Outlook2013" 326 | $arrRole += "PowerPoint2013" 327 | $arrRole += "Excel2013" 328 | $arrRole += "Word2013" 329 | } 330 | if(Get-PowerStigIsIE -ServerName $ServerName) 331 | { 332 | $arrRole += "InternetExplorer" 333 | } 334 | if(Get-PowerStigIsDotNet -ServerName $ServerName) 335 | { 336 | $arrRole += "DotNetFramework" 337 | } 338 | if(Get-PowerStigIsFireFox -ServerName $ServerName) 339 | { 340 | $arrRole += "FireFox" 341 | } 342 | if(Get-PowerStigIsFirewall -ServerName $ServerName) 343 | { 344 | $arrRole += "WindowsFirewall" 345 | } 346 | if(Get-PowerStigIsSQL -ServerName $ServerName) # MUSTREDO 347 | { 348 | $arrRole += "SQL" 349 | } 350 | if(Get-PowerStigIsJRE -ServerName $ServerName) 351 | { 352 | $arrRole += "OracleJRE" 353 | } 354 | } 355 | 356 | $outObj = New-Object -TypeName PSObject 357 | Add-Member -InputObject $outObj -NotePropertyName "Version" -NotePropertyValue $OutVersion 358 | Add-Member -InputObject $outObj -NotePropertyName "Roles" -NotePropertyValue $arrRole 359 | 360 | Return $outObj 361 | 362 | } 363 | 364 | # M06 365 | function Get-ServerVersion 366 | { 367 | [CmdletBinding()] 368 | param( 369 | [Parameter(Mandatory=$true)] 370 | [String]$osVersion 371 | ) 372 | 373 | if ($osVersion -like "6.3*") 374 | { 375 | Return "2012R2" 376 | }elseif ($osVersion -like "10.*") 377 | { 378 | Return "2016" 379 | } 380 | } 381 | 382 | # R01 383 | function Get-PowerStigIsOffice 384 | { 385 | [CmdletBinding()] 386 | param( 387 | [Parameter(Mandatory=$true)] 388 | [String]$ServerName 389 | ) 390 | 391 | $uninstallPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" 392 | if($ServerName -eq $env:COMPUTERNAME) 393 | { 394 | $keys = @(Get-ChildItem -path $uninstallPath | Where-Object {$_.name -like "*0FF1CE}"}) 395 | } 396 | else 397 | { 398 | $keys = @(Invoke-Command -computername $ServerName -scriptblock {param($uninstallPath) Get-ChildItem -path $uninstallPath | Where-Object {$_.name -like "*0FF1CE}"}} -ArgumentList $uninstallPath) 399 | } 400 | if($keys.count -ge 1) 401 | { 402 | Return $true 403 | } 404 | else { 405 | Return $false 406 | } 407 | } 408 | 409 | # R02 410 | function Get-PowerStigIsIE 411 | { 412 | [CmdletBinding()] 413 | param( 414 | [Parameter(Mandatory=$true)] 415 | [String]$ServerName 416 | ) 417 | 418 | if($ServerName -eq $env:COMPUTERNAME) 419 | { 420 | $outVal = (Get-windowsoptionalfeature -FeatureName Internet-Explorer-Optional-amd64 -online).state -eq "Enabled" 421 | } 422 | else 423 | { 424 | $outVal = Invoke-Command -ComputerName $ServerName -Scriptblock {(Get-windowsoptionalfeature -FeatureName Internet-Explorer-Optional-amd64 -online).state -eq "Enabled"} 425 | } 426 | 427 | Return $outVal 428 | } 429 | 430 | # R03 431 | function Get-PowerStigIsDotNet 432 | { 433 | [CmdletBinding()] 434 | param( 435 | [Parameter(Mandatory=$true)] 436 | [String]$ServerName 437 | ) 438 | 439 | # DotNet is currently unsupported by PowerStig. This will return false until further notice. 440 | 441 | Return $false 442 | } 443 | 444 | # R04 445 | function Get-PowerStigIsFireFox 446 | { 447 | [CmdletBinding()] 448 | param( 449 | [Parameter(Mandatory=$true)] 450 | [String]$ServerName 451 | ) 452 | 453 | if($ServerName -eq $env:COMPUTERNAME) 454 | { 455 | $outVal = Test-Path -path "HKLM:\Software\Mozilla\Mozilla Firefox\" 456 | } 457 | else 458 | { 459 | $outVal = Invoke-Command -ComputerName $ServerName -scriptblock {Test-Path -path "HKLM:\Software\Mozilla\Mozilla Firefox\"} 460 | } 461 | Return $outVal 462 | } 463 | 464 | function Get-PowerStigFireFoxDirectory 465 | { 466 | param( 467 | [Parameter(Mandatory=$true)] 468 | [String]$ServerName 469 | ) 470 | $InstallDirectory = invoke-command -ComputerName $ServerName -scriptblock {(get-itemproperty "$((Get-ChildItem "HKLM:\SOFTWARE\Mozilla\Mozilla FireFox").Name.Replace("HKEY_LOCAL_MACHINE","HKLM:"))\Main")."Install Directory"} 471 | 472 | Return $InstallDirectory 473 | } 474 | 475 | # R05 476 | function Get-PowerStigIsFirewall 477 | { 478 | [CmdletBinding()] 479 | param( 480 | [Parameter(Mandatory=$true)] 481 | [String]$ServerName 482 | ) 483 | 484 | Return $true 485 | } 486 | 487 | # R06 488 | function Get-PowerStigIsIIS 489 | { 490 | [CmdletBinding()] 491 | param( 492 | [Parameter(Mandatory=$true)] 493 | [String]$ServerName 494 | ) 495 | 496 | Return $false #(Get-WindowsFeature -ComputerName $ServerName -Name Web-Server).installstate -eq "Installed" 497 | } 498 | 499 | # R07 500 | function Get-PowerStigIsDNS 501 | { 502 | param( 503 | [Parameter(Mandatory=$true)] 504 | [String]$ServerName 505 | ) 506 | 507 | Return (Get-WindowsFeature -ComputerName $ServerName -Name DNS).installstate -eq "Installed" 508 | } 509 | 510 | # R08 511 | function Get-PowerStigIsSQL 512 | { 513 | [CmdletBinding()] 514 | param( 515 | [Parameter(Mandatory=$true)] 516 | [String]$ServerName 517 | ) 518 | 519 | Return $false 520 | } 521 | 522 | # R09 523 | function Get-PowerStigIsJRE 524 | { 525 | [CmdletBinding()] 526 | param( 527 | [Parameter(Mandatory=$true)] 528 | [String]$ServerName 529 | ) 530 | 531 | Return $false #Invoke-Command -ComputerName $ServerName -ScriptBlock {if ((Test-Path -Path "HKLM:\SOFTWARE\WOW6432Node\JavaSoft\Java Runtime Environment") -or (Test-Path -Path "HKLM:\SOFTWARE\JavaSoft\Java Runtime Environment")){Return $true}else{Return $false}} 532 | } 533 | #endregion Private 534 | 535 | 536 | #region Public 537 | # Scan Role via PowerSTIG 538 | # Generate Org File information per role, store in temp folder in $ServerFilePath\PSOrgSettings\$r_org.xml 539 | # This is the difficult spot, if SQL is enabled, store the data in the database and recall when scap is done 540 | # If +SQL+SCAP Stor and check if SCAP complete (should check only once per run). 541 | # If not, dump var to retrieve from DB after all scanning complete 542 | # Control number of PS scans from DB controlled metric 543 | # If +SQL-SCAP Stor and process results into new CKL 544 | # Send results to DB and proceed to build CKL file from the data present. 545 | # Control number of PS scans from DB controlled metric 546 | # If -SQL-SCAP process results into new CKL 547 | # Control number of PS scans from config.ini controlled metric 548 | # If -SQL+SCAP.... 549 | # Attempt to hold data in memory until SCAP completes? 550 | # Wait to start PowerStig until SCAP completes? 551 | # Write results to temp file until all scans complete? 552 | # Refuse configuration???? Cry in a corner???? Who would do such a thing? oh yeah... users. 553 | 554 | #If +SQL check for OrgSettings in Database, else see if there is a file generated in the local path. 555 | #if Neither database nor fileExists, copy from PowerSTIG module path to OrgPath. This will allow for a persistent 556 | #org settings file that can be reused, even after reinstall. 557 | 558 | # M07 559 | <# 560 | .SYNOPSIS 561 | Scans the target Computers with PowerStig reference configurations and, optionally, SCAP 5.1 562 | 563 | .DESCRIPTION 564 | This function will use PowerStig to build reference configurations for the roles that the server holds. These reference configurations will be used to determine if the Target has deviated from the expected configuration. A deviation is considered a finding when generating the checklist file. CKL files will be located in the location set in the CKLOutPath of the config.ini file in the $ModulePath\Common directory. 565 | 566 | .PARAMETER ServerName 567 | Short name or FQDN of server that is to be scanned. Should ensure that WinRM is enabled on the target server prior to running. 568 | 569 | .PARAMETER RunScap 570 | Utilizes SCAP 5.1 to run a scan against the target server. In order to run properly ensure that the ScapInstallDir and ScapProfile settings are set properly for the computer you are running this from and the environment that you are running against. Will only run Scans that have an equivilent PowerStig Scan. 571 | 572 | .PARAMETER FullScap 573 | Similar to RunScap, with the exception that it will run scans that do not match to a PowerStig scan as well, generating the checklists for those scans as well. 574 | 575 | .PARAMETER SqlBatch 576 | Will pull ServerNames from the Sql Database that is configured. This will also implement storage of findings for historical and reporting purposes. 577 | 578 | .PARAMETER SqlInstanceName 579 | Sql Instance to be used for the scan in coordination with SqlBatch. If no value is set, this will use the SqlInstanceName option in the config.ini in the $ModulePath\Common directory. 580 | 581 | .PARAMETER DatabaseName 582 | Database to be used for the scan in coordination with SqlBatch. If no value is set, this will use the DatabaseName option in the config.ini in the $ModulePath\Common directory. 583 | 584 | .PARAMETER DebugScript 585 | Enhanced logging is enabled for the PowerStig log located in the logPath configured in the $ModulePath\Common directory. 586 | 587 | .EXAMPLE 588 | Invoke-PowerStigScan -ServerName STIGDCTest01,Sql2012Test,Win10 -RunScap 589 | 590 | Will run a scan against STIGDCTest01, Sql2012Test, and Win10 and will also run a SCAP scan at the same time. The Scap results will take precedence over the PowerStig results if there is a conflict 591 | 592 | Invoke-PowerStigScan -SqlBatch -FullScap 593 | 594 | Will run a scan against every target that exists in the database. This will also run a SCAP scan against all eligible SCAP compliance types and generate checklists for SCAP only and PowerStig/SCAP comparisons. 595 | 596 | Invoke-PowerStigScan -SqlBatch 597 | 598 | Will run only the PowerStig scans against every target in the database. This will generate a CKL file for each scan completed 599 | 600 | #> 601 | function Invoke-PowerStigScan 602 | { 603 | # Two ways to get ServerName info is by Name or by SQL. 604 | # By Name can take an array of ServerNames passed to the property 605 | # Example: $ServerName = Get-AdComputer -filter * | Select-Object -ExpandProperty Name 606 | # RunScap will only run SCAP scans that coordinate with a PowerStig Scan 607 | # FullScap will run all valid SCAP scans on the target 608 | [cmdletBinding()] 609 | param( 610 | [Parameter(Mandatory=$true,Position=0,ParameterSetName='ByName')] 611 | [ValidateNotNullorEmpty()] 612 | [String[]]$ServerName, 613 | 614 | [Parameter(Mandatory=$false,ParameterSetName='SqlBatch')] 615 | [Parameter(Mandatory=$false,ParameterSetName='ByName')] 616 | [Switch]$RunScap, 617 | 618 | [Parameter(Mandatory=$false,ParameterSetName='SqlBatch')] 619 | [Parameter(Mandatory=$false,ParameterSetName='ByName')] 620 | [Switch]$FullScap, 621 | 622 | [Parameter(Mandatory=$true,ParameterSetName='SqlBatch')] 623 | [Switch]$SqlBatch, 624 | 625 | [Parameter(Mandatory=$false,ParameterSetName='SqlBatch')] 626 | [String]$SqlInstanceName, 627 | 628 | [Parameter(Mandatory=$false,ParameterSetName='SqlBatch')] 629 | [String]$DatabaseName, 630 | 631 | [Parameter(Mandatory=$false)] 632 | [Switch]$DebugScript 633 | ) 634 | 635 | ######################### 636 | #Initialize Variables # 637 | ######################### 638 | 639 | $workingPath = Split-Path $PsCommandPath 640 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 641 | $logDate = get-date -UFormat %m%d 642 | $logFileName = "PowerStig"+ $logDate + ".txt" 643 | $logPath = $iniVar.LogPath 644 | $cklOutPath = $iniVar.cklOutPath 645 | 646 | $Global:ProgressPreference = 'SilentlyContinue' 647 | 648 | $StartTime = Get-Date 649 | 650 | # Create the log path and file if they do not already exist. 651 | if(!(Test-Path -Path (Join-Path -Path $logPath -ChildPath $logFileName))) 652 | { 653 | $logFilePath = new-item -ItemType File -Path (Join-Path -Path $logPath -ChildPath $logFileName) -Force 654 | } 655 | else { 656 | $logFilePath = get-item -Path (Join-Path -Path $logPath -ChildPath $logFileName) 657 | } 658 | 659 | # If FullScap is selected, make RunScap true so any SCAP related items run for both options. 660 | if($FullScap -eq $true) 661 | { 662 | $RunScap = $true 663 | } 664 | 665 | Add-Content $logFilePath -Value "$(Get-Time):[Info]: New Scan Started - $(Get-Time)" 666 | 667 | # Initialize SQL options 668 | if($PSCmdlet.ParameterSetName -eq "SqlBatch") 669 | { 670 | if($null -eq $SqlInstanceName -or $SqlInstanceName -eq '') 671 | { 672 | $SqlInstanceName = $iniVar.SqlInstanceName 673 | } 674 | if($null -eq $DatabaseName -or $DatabaseName -eq '') 675 | { 676 | $DatabaseName = $iniVar.DatabaseName 677 | } 678 | 679 | # Get list of Servers from SQL. 680 | # If you do not cast the result as [String[]], ServerName will not take it due to the Parameter value 681 | $ServerName = [string[]](Get-PowerStigComputer | Select-Object -ExpandProperty TargetComputer) 682 | } 683 | 684 | if($DebugScript) 685 | { 686 | Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Variables Initialized as follows:" 687 | Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: RunScap = $RunScap" 688 | Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: FullScap = $FullScap" 689 | Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: SqlBatch = $SqlBatch" 690 | if($SqlBatch) 691 | { 692 | Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: SqlInstanceName = $SqlInstanceName" 693 | Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: DatabaseName = $DatabaseName" 694 | } 695 | } 696 | 697 | Add-Content $logFilePath -Value "$(Get-Time):[Info]: Cleaning old files." 698 | Get-ChildItem $logPath -Directory -Recurse | Where-Object {$_.Name -notlike "*SCAP*" -and $_.Name -notlike "*SCC*" -and $CKLOutPath -notlike "$($_.FullName)*" -and $_.FullName -notlike "$CKLOutPath*" -and $_.Name -notlike "*PSOrgSettings*"} | Remove-Item -Force -Recurse 699 | 700 | # If Scap enabled 701 | if($RunScap -eq $True) 702 | { 703 | # Initialize SCAP variables 704 | $ScapInstallDir = $iniVar.ScapInstallDir 705 | $ScapOnlyRoles = Get-ScapOnlyRoles 706 | 707 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][Info]: SCAP Processing initialized." 708 | # scapPath will hold SCAP settings such as hosts file and options.xml 709 | # logPath\SCC will hold all SCAP results. Remove the old results to ensure there are no conflicts 710 | ################ TODO ##################### 711 | # # 712 | # Move Old SCAP results to compressed folder# 713 | # # 714 | ################ END ##################### 715 | $scapPath = Join-Path -Path $logPath -ChildPath "SCAP" 716 | if(Test-Path (Join-Path -Path $logPath -ChildPath "SCC")) 717 | { 718 | Remove-Item (Join-Path -Path $logPath -ChildPath "SCC") -Recurse -Force 719 | } 720 | if(Test-Path $scapPath) 721 | { 722 | Remove-Item $scapPath -Recurse -Force 723 | } 724 | 725 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: scapPath = $scapPath"} 726 | 727 | # Create scapPath if it does not exist 728 | if(-not(Test-Path $scapPath)) 729 | { 730 | New-Item -Path $scapPath -ItemType Directory | Out-Null 731 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Created Scap Path at $scapPath" 732 | } 733 | 734 | # Initialize Hash Table to get list of SCAP scans that are required 735 | $runList = @{ 736 | "2012R2_MS" = 0 737 | "2012R2_DC" = 0 738 | "2016_MS" = 0 739 | "2016_DC" = 0 740 | "Client" = 0 741 | } 742 | # Initialize Arrays that will hold list of computers for each scan type to be added to hosts file consumed by SCAP 743 | $2012MS = @() 744 | $2012DC = @() 745 | $2016MS = @() 746 | $2016DC = @() 747 | $Client = @() 748 | 749 | # Determing type of batch 750 | foreach($s in $ServerName) 751 | { 752 | if($s -eq 'localhost') 753 | { 754 | $s = $ENV:ComputerName 755 | } 756 | # Get-PowerStigOSandFunction is the lightweight information grab that just returns OSVerion and domain role (DC,MS,Client) 757 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Current Server is $s"} 758 | if((Test-NetConnection -ComputerName $s -CommonTCPPort WINRM -WarningAction SilentlyContinue).TcpTestSucceeded -eq $false) 759 | { 760 | Add-Content -Path $logFilePath -Value "$(Get-Time):[ERROR]: Could not connect to $s over WINRM. Moving to next server." 761 | Continue 762 | } 763 | if ($s -eq $ENV:ComputerName) 764 | { 765 | $PSVersion = $PSVersionTable.PSVersion.ToString() 766 | } 767 | else 768 | { 769 | $PSVersion = Invoke-Command -ComputerName $s -ScriptBlock {$PSVersionTable.PSVersion.ToString()} 770 | } 771 | if($PSVersion -notlike "5.1.*") 772 | { 773 | Add-Content -Path $logFilePath -Value "$(Get-Time):[ERROR]: WMF 5.1 is not installed on $s. PowerStig cannot run on $s." 774 | Continue 775 | } 776 | $tempInfo = Get-PowerStigOSandFunction -ServerName $s 777 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: $s version is $($tempInfo.OSVersion)"} 778 | if($tempInfo.OsVersion -eq "2012R2") 779 | { 780 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: $s is 2012R2 = True"} 781 | if($tempinfo.Role -eq "DC" -and $runList."2012R2_DC" -ne 1) 782 | { 783 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Toggle switch for 2012R2_DC"} 784 | $runList."2012R2_DC" = 1 785 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable 2012DC"} 786 | $2012DC += $s 787 | } 788 | elseif($tempInfo.Role -eq "MS" -and $runList."2012R2_MS" -ne 1) 789 | { 790 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Toggle switch for 2012R2_MS"} 791 | $runList."2012R2_MS" = 1 792 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable 2012MS"} 793 | $2012MS += $s 794 | } 795 | elseif($tempInfo.Role -eq "MS" -and $runList."2012R2_MS" -eq 1) 796 | { 797 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable 2012MS"} 798 | $2012MS += $s 799 | } 800 | elseif($tempInfo.Role -eq "DC" -and $runList."2012_DC" -eq 1) 801 | { 802 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable 2012DC"} 803 | $2012DC += $s 804 | } 805 | } 806 | elseif($tempInfo.OsVersion -eq "2016") 807 | { 808 | if($tempInfo.Role -eq "DC" -and $runList."2016_DC" -ne 1) 809 | { 810 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Toggle switch for 2016_DC"} 811 | $runList."2016_DC" = 1 812 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable 2016DC"} 813 | $2016DC += $s 814 | } 815 | elseif($tempInfo.Role -eq "MS" -and $runList."2016_MS" -ne 1) 816 | { 817 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Toggle switch for 2016_MS"} 818 | $runList."2016_MS" = 1 819 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable 2016MS"} 820 | $2016MS += $s 821 | } 822 | elseif($tempInfo.Role -eq "MS" -and $runlist."2016_MS" -eq 1) 823 | { 824 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable 2016MS"} 825 | $2016MS += $s 826 | } 827 | elseif($tempInfo.Role -eq "DC" -and $runList."2016_DC" -eq 1) 828 | { 829 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable 2016DC"} 830 | $2016DC += $s 831 | } 832 | } 833 | elseif($tempInfo.OsVersion -eq "10" -and $runList."Client" -ne 1) 834 | { 835 | if($runList."Client" -ne 1) 836 | { 837 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Toggle switch for Client"} 838 | $runList."Client" = 1 839 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable Client"} 840 | $Client += $s 841 | } 842 | else 843 | { 844 | if($DebugScript){Add-Content $logFilePath -Value "$(Get-Time):[DEBUG]: Adding $s to variable Client"} 845 | $Client += $s 846 | } 847 | } 848 | } 849 | 850 | if($DebugScript) 851 | { 852 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: Setting base configuration for SCAP" 853 | } 854 | 855 | Set-PowerStigScapBasicOptions 856 | while(((Get-Process | Where-Object {$_.ProcessName -like "cscc*"}).count) -gt 0) 857 | { 858 | Start-Sleep -seconds 1 859 | } 860 | 861 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][Info]: The following option and hosts files will be generated and ran" 862 | foreach($r in $runList.Keys) 863 | { 864 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Processing $r" 865 | if(($runList.$r) -eq 1) 866 | { 867 | New-Item -Path "$LogPath\SCAP\$($r)_Hosts.txt" -ItemType File -Force | Out-Null 868 | if ($r -eq "2012R2_MS") 869 | { 870 | if($FullScap -eq $true) 871 | { 872 | Set-PowerStigScapRoleXML -OsVersion "2012R2" -isDomainController:$false -RunAll 873 | } 874 | else 875 | { 876 | Set-PowerStigScapRoleXML -OsVersion "2012R2" -isDomainController:$false 877 | } 878 | Add-Content -Path "$scapPath\$($r)_Hosts.txt" -value $2012MS -Force 879 | $params = " -f `"$scapPath\$($r)_Hosts.txt`" -o `"$scapPath\2012R2_MS_options.xml`" -q" 880 | Add-Content -path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Starting SCAP Scan for $r" 881 | if($DebugScript){Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: params = $params"} 882 | Start-Job -Name "SCAP_2012R2_MS" -ScriptBlock {param($params,$ScapInstallDir)write-host "ScapInstallDir = $ScapInstallDir";Write-Host "Params = $params";Invoke-Expression "& `"$ScapInstallDir\Cscc.exe`"$params"} -ArgumentList $params,$ScapInstallDir | Out-Null 883 | } 884 | elseif ($r -eq "2016_MS") 885 | { 886 | if($FullScap -eq $true) 887 | { 888 | Set-PowerStigScapRoleXML -OsVersion "2016" -isDomainController:$false -RunAll 889 | } 890 | else 891 | { 892 | Set-PowerStigScapRoleXML -OsVersion "2016" -isDomainController:$false 893 | } 894 | Add-Content -Path "$scapPath\$($r)_Hosts.txt" -value $2016MS -Force 895 | $params = " -f `"$scapPath\$($r)_Hosts.txt`" -o `"$scapPath\2016_MS_options.xml`" -q" 896 | Add-Content -path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Starting SCAP Scan for $r" 897 | if($DebugScript){Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: params = $params"} 898 | Start-Job -Name "SCAP_2016_MS" -ScriptBlock {param($params,$ScapInstallDir)write-host "ScapInstallDir = $ScapInstallDir";Write-Host "Params = $params";Invoke-Expression "& `"$ScapInstallDir\Cscc.exe`"$params"} -ArgumentList $params,$ScapInstallDir | Out-Null 899 | } 900 | elseif ($r -eq "2012R2_DC") 901 | { 902 | if($FullScap -eq $true) 903 | { 904 | Set-PowerStigScapRoleXML -OsVersion "2012R2" -isDomainController:$true -RunAll 905 | } 906 | else 907 | { 908 | Set-PowerStigScapRoleXML -OsVersion "2012R2" -isDomainController:$true 909 | } 910 | Add-Content -Path "$scapPath\$($r)_Hosts.txt" -value $2012DC -Force 911 | $params = " -f `"$scapPath\$($r)_Hosts.txt`" -o `"$scapPath\2012R2_DC_options.xml`" -q" 912 | Add-Content -path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Starting SCAP Scan for $r" 913 | if($DebugScript){Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: params = $params"} 914 | Start-Job -Name "SCAP_2012R2_DC" -ScriptBlock {param($params,$ScapInstallDir)write-host "ScapInstallDir = $ScapInstallDir";Write-Host "Params = $params";Invoke-Expression "& `"$ScapInstallDir\Cscc.exe`"$params"} -ArgumentList $params,$ScapInstallDir | Out-Null 915 | } 916 | elseif ($r -eq "2016_DC") 917 | { 918 | if($FullScap -eq $true) 919 | { 920 | Set-PowerStigScapRoleXML -OsVersion "2016" -isDomainController:$true -RunAll 921 | } 922 | else 923 | { 924 | Set-PowerStigScapRoleXML -OsVersion "2016" -isDomainController:$true 925 | } 926 | Add-Content -Path "$scapPath\$($r)_Hosts.txt" -value $2016DC -Force 927 | $params = " -f `"$scapPath\$($r)_Hosts.txt`" -o `"$scapPath\2016_DC_options.xml`" -q" 928 | Add-Content -path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Starting SCAP Scan for $r" 929 | if($DebugScript){Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: params = $params"} 930 | Start-Job -Name "SCAP_2016_DC" -ScriptBlock {param($params,$ScapInstallDir)write-host "ScapInstallDir = $ScapInstallDir";Write-Host "Params = $params";Invoke-Expression "& `"$ScapInstallDir\Cscc.exe`"$params"} -ArgumentList $params,$ScapInstallDir | Out-Null 931 | } 932 | elseif ($r -eq "Client") 933 | { 934 | if($FullScap -eq $true) 935 | { 936 | Set-PowerStigScapRoleXML -OsVersion "10" -isDomainController:$false -RunAll 937 | } 938 | else 939 | { 940 | Set-PowerStigScapRoleXML -OsVersion "10" -isDomainController:$false 941 | } 942 | Add-Content -Path "$scapPath\$($r)_Hosts.txt" -Value $Client -Force 943 | $params = " -f `"$scapPath\$($r)_Hosts.txt`" -o `"$scapPath\Client_options.xml`" -q" 944 | Add-Content -path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Starting SCAP Scan for $r" 945 | if($DebugScript){Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: params = $params"} 946 | Start-Job -Name "SCAP_Client" -ScriptBlock {param($params,$ScapInstallDir)write-host "ScapInstallDir = $ScapInstallDir";Write-Host "Params = $params";Invoke-Expression "& `"$ScapInstallDir\Cscc.exe`"$params"} -ArgumentList $params,$ScapInstallDir | Out-Null 947 | } 948 | } 949 | } 950 | 951 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][Info]: SCAP has started to run. Waiting until all jobs complete." 952 | 953 | while (((Get-Process | Where-Object {$_.ProcessName -like "cscc*"}).count) -gt 0 -or (Get-Job | Where-Object {$_.state -eq "Running" -and $_.name -like "SCAP*"}).count -gt 0) 954 | { 955 | Start-Sleep -Seconds 2 956 | } 957 | 958 | if($DebugScript){Write-Host "SCAP has ended."} 959 | 960 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][Info]: SCAP scans have finished." 961 | 962 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Processing SCAP results" 963 | 964 | $scapResultXccdf = Get-Childitem -path C:\Temp\PowerStig\SCC\Results -Include "*Xccdf*" -Recurse 965 | $scapTech = Get-PowerStigScapVersionMap 966 | 967 | 968 | foreach($x in $scapResultXccdf) 969 | { 970 | $isDC = $false 971 | $splitSeparator = "_XCCDF-Results_" 972 | $sScap = ($x.Name -Split $splitSeparator)[0] 973 | $workingRole = ($x.Name -Split $splitSeparator)[1] 974 | $importRole=$null 975 | 976 | foreach($k in $scapTech.keys) 977 | { 978 | [regex]$RoleMatch = $k 979 | if($RoleMatch.Matches($workingRole).Success -eq $true) 980 | { 981 | $importRole = $RoleMatch.Matches($workingRole).value 982 | Continue 983 | } 984 | } 985 | 986 | if($importRole -eq "Windows_Server_2016") 987 | { 988 | $tempObj = Get-PowerStigOSandFunction -ServerName $sScap 989 | if($tempObj.Role -eq "DC") 990 | { 991 | $isDC = $true 992 | } 993 | } 994 | 995 | $psRole = Convert-ScapRoleToPowerStig -Role $importRole -isDomainController:$isDC 996 | if($null -ne $psRole -and $psRole -ne '') 997 | { 998 | $pStigVersion = Get-PowerStigXmlVersion -Role $psRole 999 | } 1000 | else 1001 | { 1002 | $psRole = $importRole 1003 | $pStigVersion = $scapTech.$importRole 1004 | } 1005 | 1006 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][Info]: Adding results for $psRole for $sScap" 1007 | 1008 | if($debugScript) 1009 | { 1010 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: sScap=$sScap" 1011 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: workingRole=$workingRole" 1012 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: importRole=$importRole" 1013 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: isDC=$isDC" 1014 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: pStigVersion=$pStigVersion" 1015 | Add-Content -Path $logFilePath -Value "$(Get-Time):[SCAP][DEBUG]: psRole=$psRole" 1016 | } 1017 | 1018 | $scapResults = Get-PowerStigScapResults -ScapResultsXccdf $x.FullName 1019 | 1020 | if($SqlBatch -eq $true) 1021 | { 1022 | Import-PowerStigObject -ServerName $sScap -InputObj $scapResults -Role $psRole -ScanSource 'SCAP' -ScanVersion $pStigVersion 1023 | } 1024 | 1025 | if($ScapOnlyRoles -contains $importRole) 1026 | { 1027 | $sourceHash = @{} 1028 | $scapHash = Set-PowerStigResultHashTableFromObject -InputObject $scapResults 1029 | $sInfo = Get-PowerStigOSandFunction -ServerName $sScap 1030 | foreach($k in $scapHash.keys) 1031 | { 1032 | $SourceHash.add("$k","1") 1033 | } 1034 | Update-PowerStigCkl -ServerName $sScap -Role $importRole -osVersion $sInfo.OSVersion -InputObject $scapHash -outPath $cklOutPath -SourceHash $SourceHash 1035 | 1036 | } 1037 | } 1038 | 1039 | }# End SCAP run job 1040 | 1041 | #initialize Hashtable to test for orgSettings creation. Prevents duplicate effort 1042 | $orgSettingsProcessed = @{} 1043 | 1044 | $evalServers = @() 1045 | # Start of PowerStig scans as traditional means. 1046 | ######################################################################## 1047 | ## 1048 | ## Start of MOF Generation 1049 | ## 1050 | ######################################################################## 1051 | foreach($s in $ServerName) 1052 | { 1053 | if($s -eq 'localhost') 1054 | { 1055 | $s = $ENV:ComputerName 1056 | } 1057 | # Check connection to remote server on WinRM 1058 | Add-Content $logFilePath -Value "$(Get-Time):[$s][Info]: Testing Connectivity on port 5985 (WinRM)" 1059 | 1060 | if((Test-NetConnection -ComputerName $s -CommonTCPPort WINRM -WarningAction SilentlyContinue).TcpTestSucceeded -eq $false) 1061 | { 1062 | Add-Content -path $logFilePath -Value "$(Get-Time):[$s][Error]: Connection to $s Failed. Check network connectivity and that the server is listening for WinRM" 1063 | Continue 1064 | } 1065 | else 1066 | { 1067 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][Info]: Connection to $s successful" 1068 | 1069 | } 1070 | if ($s -eq $ENV:ComputerName) 1071 | { 1072 | $PSVersion = $PSVersionTable.PSVersion.ToString() 1073 | } 1074 | else 1075 | { 1076 | $PSVersion = Invoke-Command -ComputerName $s -ScriptBlock {$PSVersionTable.PSVersion.ToString()} 1077 | } 1078 | if($PSVersion -notlike "5.1.*") 1079 | { 1080 | Add-Content -Path $logFilePath -Value "$(Get-Time):[ERROR]: WMF 5.1 is not installed on $s. PowerStig cannot run on $s." 1081 | Continue 1082 | } 1083 | else 1084 | { 1085 | $evalServers += $s 1086 | } 1087 | # Check WSMan Settings 1088 | Add-Content $logFilePath -Value "$(Get-Time):[$s][Info]: Testing WSMAN configuration on target server" 1089 | 1090 | if($s -eq $ENV:ComputerName) 1091 | { 1092 | try { 1093 | [int]$maxEnvelope = (get-childitem "wsman:\localhost\MaxEnvelopeSizekb").value 1094 | } 1095 | catch { 1096 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][ERROR]: Query for WSMAN properties failed. Check user context that this is running under." 1097 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][ERROR]: $_" 1098 | Continue 1099 | } 1100 | 1101 | } 1102 | else 1103 | { 1104 | try{ 1105 | [int]$maxEnvelope = invoke-command -ComputerName $s -ScriptBlock {((get-childitem "wsman:\localhost\MaxEnvelopeSizekb").value)} 1106 | } 1107 | catch { 1108 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][ERROR]: Query for WSMAN properties failed. Check user context that this is running under." 1109 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][ERROR]: $_" 1110 | Continue 1111 | } 1112 | } 1113 | 1114 | #Configure WSMAN if necessary 1115 | if($maxEnvelope -lt 10000 -and $s -ne $ENV:ComputerName) 1116 | { 1117 | Add-Content -path $logFilePath -Value "$(Get-Time):[$s][Warning]: Attempting to set MaxEnvelopeSizeKb on $s." 1118 | try 1119 | { 1120 | invoke-command -computername $s -ScriptBlock {Set-Item -Path "WSMAN:\localhost\MaxEnvelopeSizekb" -Value 10000} 1121 | Add-Content -path $logFilePath -Value "$(Get-Time):[$s][Info]: MaxEnvelopeSizeKb successfully configured on $s." 1122 | } 1123 | catch 1124 | { 1125 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][ERROR]: Setting WSMAN failed on $s." 1126 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][ERROR]: $_" 1127 | Continue 1128 | } 1129 | } 1130 | elseif($maxEnvelope -lt 10000 -and $s -eq $ENV:ComputerName) 1131 | { 1132 | Add-Content -path $logFilePath -Value "$(Get-Time):[$s][Warning]: Attempting to set MaxEnvelopeSizeKb on $s." 1133 | try 1134 | { 1135 | Set-Item -Path "WSMAN:\localhost\MaxEnvelopeSizekb" -Value 10000 1136 | Add-Content -path $logFilePath -Value "$(Get-Time):[$s][Info]: MaxEnvelopeSizeKb successfully configured on $s." 1137 | } 1138 | catch 1139 | { 1140 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][ERROR]: Setting WSMAN failed on $s." 1141 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][ERROR]: $_" 1142 | Continue 1143 | } 1144 | } 1145 | else 1146 | { 1147 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][Info]: WSMan is correctly configured." 1148 | } 1149 | 1150 | ############################### 1151 | #Test WSMan Settings Complete # 1152 | ############################### 1153 | 1154 | $ServerFilePath = "$logpath\$s" 1155 | # Prepare Staging location 1156 | if(-not(test-path $ServerFilePath)) 1157 | { 1158 | 1159 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][Info]: Creating file path for this server at $ServerFilePath" 1160 | New-Item -ItemType Directory -Path $ServerFilePath | Out-Null 1161 | } 1162 | 1163 | # Gather Role information 1164 | $roles = Get-PowerStigServerRole -ServerName $s 1165 | Add-Content $logFilePath -Value "$(Get-Time):[$s][Info]: PowerStig scan started on $s for role $($roles.roles) and version $($roles.version)." 1166 | 1167 | # If SQL - Update role and OS information 1168 | if($SqlBatch -eq $true) 1169 | { 1170 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][Info]: Updating server information in SQL." 1171 | Set-PowerStigComputer -ServerName $s -osVersion $roles.Version -DebugScript:$DebugScript 1172 | } 1173 | 1174 | 1175 | $OrgPath = "$logPath\PSOrgSettings\" 1176 | if(-not(Test-Path $OrgPath)) 1177 | { 1178 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][Info]: Creating Org Settings path at $OrgPath" 1179 | New-Item -Path $OrgPath -ItemType Directory -Force | Out-Null 1180 | } 1181 | 1182 | foreach($r in $roles.roles) 1183 | { 1184 | $orgFileName = "$orgPath\$($r)_org.xml" 1185 | try 1186 | { 1187 | # Do scripting magic to build the orgsettings from the database. However, if there is not a database run, 1188 | # check the orgPath to determine if there was a previous org file for the role and use that first. 1189 | # $OrgSettingsPath 1190 | if ($SqlBatch -eq $true -and $orgSettingsProcessed.Contains("$r") -eq $false) 1191 | { 1192 | try 1193 | { 1194 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][Info]: Creating OrgSettings file for $r at $orgFileName" 1195 | if($DebugScript) 1196 | { 1197 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][DEBUG]: Command Passed is: Get-PowerStigOrgSettings -Version $($roles.Version) -Role $r -OutPath $orgFileName" 1198 | } 1199 | Get-PowerStigOrgSettings -Version $roles.Version -Role $r -OutPath $orgFileName 1200 | $orgSettingsProcessed.Add("$r","1") 1201 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][Info]: Org Settings generate from Database" 1202 | } 1203 | catch 1204 | { 1205 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][ERROR]: OrgSettings failed to generate:" 1206 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][ERROR]: $_" 1207 | } 1208 | } 1209 | 1210 | if (-not(Test-Path $orgFileName)) 1211 | { 1212 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][Info]: Processing Org Settings from local machine." 1213 | # If OrgSettings file exist in $OrgPath, use that else, copy from PowerStig and use the copied version 1214 | if(Test-Path $orgFileName) 1215 | { 1216 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][Info]: OrgSettings exist in $orgFileName" 1217 | } 1218 | elseif(-not(Test-Path $orgFileName)) 1219 | { 1220 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][Info]: No previous org files in location. Attempting to copy from default PowerStig Location ($(Get-PowerStigXMLPath)" 1221 | if($r -like "*WindowsServer*") 1222 | { 1223 | $xmlEval = $r.split("-")[0] + "-" + $roles.Version + "-" + $r.split("-")[1] 1224 | $highVer = Get-PowerStigXmlVersion -Role $r -osVersion $roles.Version 1225 | if($DebugScript) 1226 | { 1227 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][DEBUG]: xml evaluation term is $xmlEval" 1228 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][DEBUG]: High Version is $highVer" 1229 | } 1230 | $srcOrgFileName = Get-ChildItem -Path "$(Get-PowerStigXMLPath)" | Where-Object {$_.Name -like "*$xmlEval*" -and $_.Name -like "*$highVer*" -and $_.Name -like "*.org.default.xml"} | Select-Object -ExpandProperty Name 1231 | if($DebugScript) 1232 | { 1233 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][DEBUG]: Source xml file is $srcOrgFileName" 1234 | } 1235 | Copy-Item -Path "$(Get-PowerStigXMLPath)\$srcOrgFileName" -Destination $orgFileName 1236 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][Info]: Org Settings Copied from PowerStig Directory" 1237 | } 1238 | else 1239 | { 1240 | $highVer = Get-PowerStigXmlVersion -Role $r -osVersion $roles.Version 1241 | if($DebugScript) 1242 | { 1243 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][DEBUG]: High Version is $highVer" 1244 | } 1245 | $srcOrgFileName = Get-ChildItem -Path "$(Get-PowerStigXMLPath)" | Where-Object {$_.Name -like "*$r*" -and $_.Name -like "*$highVer*" -and $_.Name -like "*.org.default.xml"} | Select-Object -ExpandProperty Name 1246 | if($DebugScript) 1247 | { 1248 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][DEBUG]: Source xml file is $srcOrgFileName" 1249 | } 1250 | Copy-Item -Path "$(Get-PowerStigXMLPath)\$srcOrgFileName" -Destination $orgFileName 1251 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][Info]: Org Settings Copied from PowerStig Directory" 1252 | } 1253 | } 1254 | } 1255 | 1256 | # This is here for future development. 1257 | $arrSkipRule = $null 1258 | } 1259 | catch 1260 | { 1261 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][ERROR]: OrgSettings failed when running:" 1262 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][ERROR]: $_" 1263 | } 1264 | 1265 | Push-Location $ServerFilePath 1266 | try 1267 | { 1268 | $RunExpression = "& `"$workingPath\DSCCall.ps1`" -ComputerName $s -osVersion $($roles.Version) -Role $r -LogPath $logFilePath -OrgSettingsFilePath $orgFileName" 1269 | if($null -ne $arrSkipRule -and $arrSkipRule -ne "") 1270 | { 1271 | $RunExpression += " -SkipRules $arrSkipRule" 1272 | } 1273 | Invoke-Expression -Command $RunExpression | Out-Null 1274 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][Info]: MOF Created for $s for role $r" 1275 | $mofPath = "$ServerFilePath\PowerStig\" 1276 | $origMof = Get-ChildItem $mofPath | Where-Object {$_.Name -like "$s.mof"} | Select-Object -ExpandProperty FullName 1277 | $mofName = $origMof.Replace(".mof","_$r.mof") 1278 | Move-Item -path $origMof -Destination $mofName -Force 1279 | } 1280 | catch 1281 | { 1282 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][ERROR]: mof generation failed when running:" 1283 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][ERROR]: $RunExpression" 1284 | Add-Content -Path $logFilePath -Value "$(Get-Time):[$s][$r][ERROR]: $_" 1285 | Pop-Location 1286 | Continue 1287 | } 1288 | 1289 | 1290 | if($DebugScript) 1291 | { 1292 | Add-Content -Path $logFilePath -value "$(Get-Time):[$s][$r][Debug]: mofName is $mofName" 1293 | } 1294 | Pop-Location 1295 | 1296 | 1297 | } 1298 | 1299 | } 1300 | ##################################################################################################### 1301 | ## 1302 | ## End MOF Creation 1303 | ## 1304 | ##################################################################################################### 1305 | 1306 | 1307 | $concurrentScans = $iniVar.ConcurrentScans 1308 | $jobCount = $evalServers.count 1309 | 1310 | 1311 | foreach ($s in $evalServers) 1312 | { 1313 | $sOsVersion = (Get-PowerStigOSandFunction -ServerName $s).OSVersion 1314 | $jobScript = {param($s,$sOsVersion,$RunScap,$SqlBatch,$DebugScript)Start-PowerStigDSCScan -ServerName $s -osVersion $sOsVersion -isScap:$RunScap -isSql:$SqlBatch -DebugScript:$DebugScript} 1315 | 1316 | Start-Job -Name "PowerStig_$s" -ScriptBlock $jobScript -ArgumentList $s,$sOsVersion,$RunScap,$SqlBatch,$DebugScript | Out-Null 1317 | $jobCount -= 1 1318 | 1319 | Add-Content -Path $logFilePath -Value "$(Get-Time):[DSCMain][Info]: There are $jobCount jobs left to start" 1320 | 1321 | While((Get-Job | Where-Object {$_.state -eq "Running" -and $_.name -like "*PowerSTIG*"}).count -ge $concurrentScans) 1322 | { 1323 | Start-Sleep -Seconds 2 1324 | } 1325 | } 1326 | 1327 | $jobCount = (Get-Job | Where-Object {$_.state -eq "Running" -and $_.name -like "*PowerSTIG*"}).count 1328 | $newJobCount = 0 1329 | 1330 | While((Get-Job | Where-Object {$_.state -eq "Running" -and $_.name -like "*PowerSTIG*"}).count -gt 0) 1331 | { 1332 | if($jobCount -ne $newJobCount) 1333 | { 1334 | $jobCount = (Get-Job | Where-Object {$_.state -eq "Running" -and $_.name -like "*PowerSTIG*"}).count 1335 | Add-Content -Path $logFilePath -Value "$(Get-Time):[DSCMain][Info]: There are $jobCount jobs remaining." 1336 | } 1337 | Start-Sleep -Seconds 2 1338 | $newJobCount = (Get-Job | Where-Object {$_.state -eq "Running" -and $_.name -like "*PowerSTIG*"}).count 1339 | } 1340 | 1341 | $Timestamp = (get-date).ToString("yyyyMMdd") 1342 | 1343 | $FolderName = "Results_$TimeStamp" 1344 | 1345 | if(-not(Test-Path "$cklOutPath\$folderName")) 1346 | { 1347 | New-Item "$cklOutPath\$folderName" -ItemType Directory -Force | Out-Null 1348 | } 1349 | 1350 | Get-ChildItem $cklOutPath | Where-Object {$_.mode -notlike "d*" -and $_.CreationTime -gt $startTime} | ForEach-Object {Move-Item -path $_.FullName -Destination "$cklOutPath\$folderName\$($_.Name)" -Force} 1351 | 1352 | Add-Content -Path $logFilePath -Value "$(Get-Time):[Info]: SCAN COMPLETE" 1353 | 1354 | } 1355 | 1356 | Function Start-PowerStigDSCScan 1357 | { 1358 | #The goal of this script is to take a MOF file and Generate results 1359 | #params required include logging information, is it SCAP/SQL based, MofName, ServerName 1360 | [cmdletBinding()] 1361 | param( 1362 | [Parameter(Mandatory=$true)] 1363 | [String]$ServerName, 1364 | 1365 | [Parameter(Mandatory=$true)] 1366 | [String]$osVersion, 1367 | 1368 | [Parameter(Mandatory=$false)] 1369 | [Switch]$isScap, 1370 | 1371 | [Parameter(Mandatory=$false)] 1372 | [Switch]$isSql, 1373 | 1374 | [Parameter(Mandatory=$false)] 1375 | [Switch]$DebugScript 1376 | ) 1377 | 1378 | $workingPath = Split-Path $PsCommandPath 1379 | $iniVar = Import-PowerStigConfig -configFilePath $workingPath\Config.ini 1380 | $cklOutPath = $iniVar.CKLOutPath 1381 | $logPath = $iniVar.LogPath 1382 | $logDate = get-date -UFormat %m%d 1383 | $logFileName = "PowerStigJobLog"+ $logDate + ".txt" 1384 | 1385 | if(!(Test-Path -Path "$logPath\$logFileName")) 1386 | { 1387 | $logFilePath = new-item -ItemType File -Path "$logPath\$logFileName" -Force 1388 | } 1389 | else { 1390 | $logFilePath = get-item -Path "$logPath\$logFileName" 1391 | } 1392 | 1393 | if($isSql) 1394 | { 1395 | $SqlInstanceName = $iniVar.SqlInstanceName 1396 | $DatabaseName = $iniVar.DatabaseName 1397 | } 1398 | 1399 | Function Write-PowerStigPSLog 1400 | { 1401 | param( 1402 | [String]$Path, 1403 | [String]$Value 1404 | ) 1405 | 1406 | $mutex = [System.Threading.Mutex]::new($false,'LogWrite') 1407 | 1408 | $mutex.WaitOne() | Out-Null 1409 | 1410 | try{ 1411 | Add-Content -path $Path -Value $Value 1412 | } 1413 | catch{ 1414 | Write-Host "Logging failed due to process holding the log file open" 1415 | } 1416 | finally{ 1417 | $mutex.ReleaseMutex() 1418 | $mutex.Dispose() 1419 | } 1420 | } 1421 | 1422 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][Info]: Starting DSC Scan for $ServerName" 1423 | if($DebugScript) 1424 | { 1425 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][DEBUG]: Initialized Values:" 1426 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][DEBUG]: isScap is $isScap" 1427 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][DEBUG]: isSql is $isSql" 1428 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][DEBUG]: SqlInstanceName is $SqlInstanceName" 1429 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][DEBUG]: DatabaseName is $DatabaseName" 1430 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][DEBUG]: cklOutPath is $cklOutPath" 1431 | } 1432 | 1433 | $mofList = @(get-childitem -Path "C:\Temp\PowerStig\$ServerName\PowerStig\*" -Include "$ServerName*.mof" -Recurse) 1434 | 1435 | if($DebugScript) 1436 | { 1437 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][DEBUG]: Found the following mofs" 1438 | foreach($m in $mofList) 1439 | { 1440 | $tech = $m.Name.split("_")[$m.Name.Split("_").count - 1].replace(".mof","") 1441 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][DSC][DEBUG]: $tech" 1442 | } 1443 | } 1444 | 1445 | foreach($m in $mofList) 1446 | { 1447 | $r = $m.Name.split("_")[$m.Name.Split("_").count - 1].replace(".mof","") 1448 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][$r][DSC]: Starting scan for $r on $ServerName" 1449 | if($DebugScript) 1450 | { 1451 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][$r][DSC][DEBUG]: Test-DscConfiguration -ComputerName $Servername -ReferenceConfiguration $($m.FullName)" 1452 | } 1453 | try 1454 | { 1455 | $ScanObj = Test-DscConfiguration -ComputerName $ServerName -ReferenceConfiguration $m.FullName -ErrorAction Stop 1456 | } 1457 | catch 1458 | { 1459 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][$r][ERROR]: $_" 1460 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][$r][ERROR]: mof variable is $($m.FullName)" 1461 | Continue 1462 | } 1463 | 1464 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][$r][Info]: Converting results to PSObjects" 1465 | 1466 | try 1467 | { 1468 | $convertObj = Convert-PowerStigTest -TestResults $scanObj 1469 | $resultHash = Set-PowerStigResultHashTableFromObject -InputObject $ConvertObj 1470 | } 1471 | catch 1472 | { 1473 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][$r][ERROR]: $_" 1474 | Continue 1475 | } 1476 | 1477 | if($isSql) 1478 | { 1479 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][Info]: Importing Results to Database for $ServerName and role $r." 1480 | 1481 | Import-PowerStigObject -Servername $ServerName -InputObj $convertObj -Role $r -ScanSource 'POWERSTIG' -ScanVersion (Get-PowerStigXmlVersion -Role $r -osVersion $osVersion) 1482 | } 1483 | 1484 | $SourceHash = @{} 1485 | $outHash = @{} 1486 | if($isScap) 1487 | { 1488 | $ScapRole = Convert-PowerStigRoleToScap -OsVersion $osVersion -Role $r 1489 | # SourceHash will hold the VulnID number with a 1(SCAP) or 0(PowerStig) 1490 | 1491 | if($Null -ne $ScapRole) 1492 | { 1493 | # Determine SCAP Results File or Pass Hash 1494 | $ScapFile = Get-ChildItem "$logPath\SCC\Results\$ServerName\XML\" -Recurse | Where-Object {$_.Name -like "*XCCDF*" -and $_.Name -like "*$ScapRole*"} 1495 | if($null -ne $ScapFile) 1496 | { 1497 | $ScapHash = Get-PowerStigScapResults -ScapResultsXccdf $ScapFile.FullName -OutHash 1498 | 1499 | foreach($k in $resultHash.Keys) 1500 | { 1501 | if($ScapHash.ContainsKey($k)) 1502 | { 1503 | $outHash.add("$k",$($ScapHash.$k)) 1504 | $SourceHash.add("$k","1") 1505 | } 1506 | else 1507 | { 1508 | $outHash.add("$k",$($resultHash.$k)) 1509 | $SourceHash.add("$k","0") 1510 | } 1511 | } 1512 | if($DebugScript){Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][Debug]: SCAP and PowerShell results have been compared and hash tables created."} 1513 | } 1514 | else 1515 | { 1516 | foreach($k in $resultHash.keys) 1517 | { 1518 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][Warning]: SCAP results not found for $ServerName and role $r." 1519 | $SourceHash.add("$k","0") 1520 | } 1521 | $outHash = $resultHash 1522 | if($DebugScript){Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][Debug]: Results Hash table created for $ServerName and $r created."} 1523 | } 1524 | 1525 | # if DSC hash and SCAP hash has same key - Default to SCAP hash 1526 | # if DSC hash only - Use that 1527 | # if SCAP hash only - Use that 1528 | # Pass hash to New-CKL 1529 | } 1530 | else 1531 | { 1532 | foreach($k in $resultHash.keys) 1533 | { 1534 | $SourceHash.add("$k","0") 1535 | } 1536 | $outHash = $resultHash 1537 | if($DebugScript){Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][Debug]: Results Hash table created for $ServerName and $r created."} 1538 | 1539 | } 1540 | 1541 | } #End isScap - Compare/Create Results 1542 | else 1543 | { 1544 | foreach($k in $resultHash.keys) 1545 | { 1546 | $SourceHash.add("$k","0") 1547 | } 1548 | $outHash = $resultHash 1549 | } 1550 | 1551 | Update-PowerStigCkl -ServerName $ServerName -Role $r -osVersion $osVersion -InputObject $outHash -outPath $cklOutPath -SourceHash $SourceHash 1552 | # End -not isScap - Compare/Create Results 1553 | 1554 | 1555 | 1556 | } 1557 | 1558 | Write-PowerStigPSLog -Path $logFilePath -Value "$(Get-Time):[$ServerName][Info]: Job complete for server $ServerName" 1559 | } 1560 | 1561 | Function Install-PowerStigSQLDatabase 1562 | { 1563 | param( 1564 | [Parameter(ParameterSetName='Set1',Position=0,Mandatory=$true)][String]$SqlInstanceName, 1565 | [parameter(ParameterSetName='Set1',Position=1,Mandatory=$true)][String]$DatabaseName 1566 | ) 1567 | 1568 | $workingPath = Split-Path $PsCommandPath 1569 | 1570 | & $workingPath\..\SQL\DBdeployer.ps1 -DBServerName $SqlInstanceName -DatabaseName $DatabaseName 1571 | 1572 | Set-PowerStigConfig -SqlInstanceName $SqlInstanceName -DatabaseName $DatabaseName 1573 | 1574 | # TODO # 1575 | # Add function to import org settings automatically 1576 | } 1577 | 1578 | #endregion Public --------------------------------------------------------------------------------