diff --git a/CHANGELOG.md b/CHANGELOG.md index 94e77b64d..3a628c985 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 other values that the default values. - Now updates GitHub Actions automatically by allowing dependabot sending in pull requests. + - Add new resource SqlAuditSpecification. ### Changed diff --git a/appveyor.yml b/appveyor.yml index ffa55bc2a..094cb8f05 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,7 +24,7 @@ environment: matrix: # DEBUG: Comment and un-comment the different SQL Server version that should be tested. - TEST_CONFIGURATION: Integration_SQL2016 - - TEST_CONFIGURATION: Integration_SQL2017 + #- TEST_CONFIGURATION: Integration_SQL2017 #- TEST_CONFIGURATION: Integration_SQL2019 #- TEST_CONFIGURATION: Integration_SQL2022 @@ -83,7 +83,7 @@ test_script: #'tests/Integration/DSC_SqlLogin.Integration.Tests.ps1' #'tests/Integration/DSC_SqlEndpoint.Integration.Tests.ps1' #'tests/Integration/DSC_SqlDatabaseMail.Integration.Tests.ps1' - 'tests/Integration/DSC_SqlRSSetup.Integration.Tests.ps1' + #'tests/Integration/DSC_SqlRSSetup.Integration.Tests.ps1' #'tests/Integration/DSC_SqlDatabaseDefaultLocation.Integration.Tests.ps1' #'tests/Integration/DSC_SqlDatabase.Integration.Tests.ps1' #'tests/Integration/DSC_SqlAlwaysOnService.Integration.Tests.ps1' @@ -93,10 +93,11 @@ test_script: #'tests/Integration/DSC_SqlTraceFlag.Integration.Tests.ps1' ## Group 3 #'tests/Integration/DSC_SqlRole.Integration.Tests.ps1' - 'tests/Integration/DSC_SqlRS.Integration.Tests.ps1' + #'tests/Integration/DSC_SqlRS.Integration.Tests.ps1' #'tests/Integration/DSC_SqlDatabaseUser.Integration.Tests.ps1' #'tests/Integration/DSC_SqlReplication.Integration.Tests.ps1' - #'tests/Integration/DSC_SqlAudit.Integration.Tests.ps1' + 'tests/Integration/DSC_SqlAudit.Integration.Tests.ps1' + 'tests/Integration/DSC_SqlServerAuditSpecification.Integration.Tests.ps1' ## Group 4 #'tests/Integration/DSC_SqlScript.Integration.Tests.ps1' #'tests/Integration/DSC_SqlDatabasePermission.Integration.Tests.ps1' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2152b922a..5b5ad9eb4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -216,6 +216,7 @@ stages: 'tests/Integration/DSC_SqlDatabaseUser.Integration.Tests.ps1' 'tests/Integration/DSC_SqlReplication.Integration.Tests.ps1' 'tests/Integration/DSC_SqlAudit.Integration.Tests.ps1' + 'tests/Integration/DSC_SqlServerAuditSpecification.Integration.Tests.ps1' # Group 4 'tests/Integration/DSC_SqlScript.Integration.Tests.ps1' 'tests/Integration/DSC_SqlDatabasePermission.Integration.Tests.ps1' diff --git a/source/DSCResources/DSC_SqlServerAuditSpecification/DSC_SqlServerAuditSpecification.psm1 b/source/DSCResources/DSC_SqlServerAuditSpecification/DSC_SqlServerAuditSpecification.psm1 new file mode 100644 index 000000000..ee0ab55f0 --- /dev/null +++ b/source/DSCResources/DSC_SqlServerAuditSpecification/DSC_SqlServerAuditSpecification.psm1 @@ -0,0 +1,1456 @@ +$script:sqlServerDscHelperModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\SqlServerDsc.Common' +$script:resourceHelperModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\DscResource.Common' + +Import-Module -Name $script:sqlServerDscHelperModulePath +Import-Module -Name $script:resourceHelperModulePath + +$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' + +<# + .SYNOPSIS + Returns the current state of the server audit specification. + + .PARAMETER Name + Specifies the name of the server audit specification to be added or removed. + + .PARAMETER ServerName + Specifies the host name of the SQL Server on which the instance exist. + + .PARAMETER InstanceName + Specifies the SQL instance in which the server audit specification exist. + + .NOTES + DO NOT CHANGE THE CAPITALS IN THE PARAMETERS! These are used to find the + places to insert an underscore, see function Get-DatabaseObjectNameFromPSParamName + for more information. +#> +function Get-TargetResource +{ + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('SqlServerDsc.AnalyzerRules\Measure-CommandsNeededToLoadSMO', '', Justification='The command Invoke-Query is used which calls the command Connect-Sql')] + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter(Mandatory = $true)] + [System.String] + $ServerName, + + [Parameter(Mandatory = $true)] + [System.String] + $InstanceName + ) + + Write-Verbose -Message ( + $script:localizedData.RetrievingAuditSpecificationInformation -f + $Name, + $ServerName, + $InstanceName + ) + + $returnValue = @{ + Ensure = 'Absent' + Name = $Name + ServerName = $ServerName + InstanceName = $InstanceName + AuditName = '' + ApplicationRoleChangePasswordGroup = $false + AuditChangeGroup = $false + BackupRestoreGroup = $false + BrokerLoginGroup = $false + DatabaseChangeGroup = $false + DatabaseLogoutGroup = $false + DatabaseMirroringLoginGroup = $false + DatabaseObjectAccessGroup = $false + DatabaseObjectChangeGroup = $false + DatabaseObjectOwnershipChangeGroup = $false + DatabaseObjectPermissionChangeGroup = $false + DatabaseOperationGroup = $false + DatabaseOwnershipChangeGroup = $false + DatabasePermissionChangeGroup = $false + DatabasePrincipalChangeGroup = $false + DatabasePrincipalImpersonationGroup = $false + DatabaseRoleMemberChangeGroup = $false + DbccGroup = $false + FailedDatabaseAuthenticationGroup = $false + FailedLoginGroup = $false + FulltextGroup = $false + LoginChangePasswordGroup = $false + LogoutGroup = $false + SchemaObjectAccessGroup = $false + SchemaObjectChangeGroup = $false + SchemaObjectOwnershipChangeGroup = $false + SchemaObjectPermissionChangeGroup = $false + ServerObjectChangeGroup = $false + ServerObjectOwnershipChangeGroup = $false + ServerObjectPermissionChangeGroup = $false + ServerOperationGroup = $false + ServerPermissionChangeGroup = $false + ServerPrincipalChangeGroup = $false + ServerPrincipalImpersonationGroup = $false + ServerRoleMemberChangeGroup = $false + ServerStateChangeGroup = $false + SuccessfulDatabaseAuthenticationGroup = $false + SuccessfulLoginGroup = $false + TraceChangeGroup = $false + UserChangePasswordGroup = $false + UserDefinedAuditGroup = $false + TransactionGroup = $false + Enabled = $false + } + + # Default parameters for the cmdlet Invoke-Query used throughout. + $invokeQueryParameters = @{ + ServerName = $ServerName + InstanceName = $InstanceName + Database = 'MASTER' + } + + $dataSetAudit = Invoke-Query @invokeQueryParameters -WithResults -Query ( + 'Select + s.server_specification_id, + s.is_state_enabled, + a.name as auditName + FROM sys.server_audits AS a + JOIN sys.server_audit_specifications AS s + ON a.audit_guid = s.audit_guid + where s.name = ''{0}''' -f + $Name) + + if ($null -ne $dataSetAudit -and $dataSetAudit.Tables[0].Rows.Count -gt 0) + { + Write-Verbose -Message ( + $script:localizedData.AuditSpecificationExist -f $Name, $ServerName, $InstanceName + ) + + $dataSetRow = $dataSetAudit.Tables[0].Rows[0] + + $dataSetAuditSpecification = Invoke-Query @invokeQueryParameters -WithResults -Query ( + 'Select audit_action_name + from sys.server_audit_specification_details + where server_specification_id = {0}' -f + $dataSetRow.server_specification_id) + + # This should always happen! + if ($null -ne $dataSetAuditSpecification -and $dataSetAuditSpecification.Tables.Count -gt 0) + { + $resultSet = Convert-ToHashTable -DataTable $dataSetAuditSpecification.Tables[0] + + $returnValue['Ensure'] = 'Present' + $returnValue['AuditName'] = $dataSetRow.auditName + $returnValue['ApplicationRoleChangePasswordGroup'] = $resultSet['APPLICATION_ROLE_CHANGE_PASSWORD_GROUP'] + $returnValue['AuditChangeGroup'] = $resultSet['AUDIT_CHANGE_GROUP'] + $returnValue['BackupRestoreGroup'] = $resultSet['BACKUP_RESTORE_GROUP'] + $returnValue['BrokerLoginGroup'] = $resultSet['BROKER_LOGIN_GROUP'] + $returnValue['DatabaseChangeGroup'] = $resultSet['DATABASE_CHANGE_GROUP'] + $returnValue['DatabaseLogoutGroup'] = $resultSet['DATABASE_LOGOUT_GROUP'] + $returnValue['DatabaseMirroringLoginGroup'] = $resultSet['DATABASE_MIRRORING_LOGIN_GROUP'] + $returnValue['DatabaseObjectAccessGroup'] = $resultSet['DATABASE_OBJECT_ACCESS_GROUP'] + $returnValue['DatabaseObjectChangeGroup'] = $resultSet['DATABASE_OBJECT_CHANGE_GROUP'] + $returnValue['DatabaseObjectOwnershipChangeGroup'] = $resultSet['DATABASE_OBJECT_OWNERSHIP_CHANGE_GROUP'] + $returnValue['DatabaseObjectPermissionChangeGroup'] = $resultSet['DATABASE_OBJECT_PERMISSION_CHANGE_GROUP'] + $returnValue['DatabaseOperationGroup'] = $resultSet['DATABASE_OPERATION_GROUP'] + $returnValue['DatabaseOwnershipChangeGroup'] = $resultSet['DATABASE_OWNERSHIP_CHANGE_GROUP'] + $returnValue['DatabasePermissionChangeGroup'] = $resultSet['DATABASE_PERMISSION_CHANGE_GROUP'] + $returnValue['DatabasePrincipalChangeGroup'] = $resultSet['DATABASE_PRINCIPAL_CHANGE_GROUP'] + $returnValue['DatabasePrincipalImpersonationGroup'] = $resultSet['DATABASE_PRINCIPAL_IMPERSONATION_GROUP'] + $returnValue['DatabaseRoleMemberChangeGroup'] = $resultSet['DATABASE_ROLE_MEMBER_CHANGE_GROUP'] + $returnValue['DbccGroup'] = $resultSet['DBCC_GROUP'] + $returnValue['FailedDatabaseAuthenticationGroup'] = $resultSet['FAILED_DATABASE_AUTHENTICATION_GROUP'] + $returnValue['FailedLoginGroup'] = $resultSet['FAILED_LOGIN_GROUP'] + $returnValue['FulltextGroup'] = $resultSet['FULLTEXT_GROUP'] + $returnValue['LoginChangePasswordGroup'] = $resultSet['LOGIN_CHANGE_PASSWORD_GROUP'] + $returnValue['LogoutGroup'] = $resultSet['LOGOUT_GROUP'] + $returnValue['SchemaObjectAccessGroup'] = $resultSet['SCHEMA_OBJECT_ACCESS_GROUP'] + $returnValue['SchemaObjectChangeGroup'] = $resultSet['SCHEMA_OBJECT_CHANGE_GROUP'] + $returnValue['SchemaObjectOwnershipChangeGroup'] = $resultSet['SCHEMA_OBJECT_OWNERSHIP_CHANGE_GROUP'] + $returnValue['SchemaObjectPermissionChangeGroup'] = $resultSet['SCHEMA_OBJECT_PERMISSION_CHANGE_GROUP'] + $returnValue['ServerObjectChangeGroup'] = $resultSet['SERVER_OBJECT_CHANGE_GROUP'] + $returnValue['ServerObjectOwnershipChangeGroup'] = $resultSet['SERVER_OBJECT_OWNERSHIP_CHANGE_GROUP'] + $returnValue['ServerObjectPermissionChangeGroup'] = $resultSet['SERVER_OBJECT_PERMISSION_CHANGE_GROUP'] + $returnValue['ServerOperationGroup'] = $resultSet['SERVER_OPERATION_GROUP'] + $returnValue['ServerPermissionChangeGroup'] = $resultSet['SERVER_PERMISSION_CHANGE_GROUP'] + $returnValue['ServerPrincipalChangeGroup'] = $resultSet['SERVER_PRINCIPAL_CHANGE_GROUP'] + $returnValue['ServerPrincipalImpersonationGroup'] = $resultSet['SERVER_PRINCIPAL_IMPERSONATION_GROUP'] + $returnValue['ServerRoleMemberChangeGroup'] = $resultSet['SERVER_ROLE_MEMBER_CHANGE_GROUP'] + $returnValue['ServerStateChangeGroup'] = $resultSet['SERVER_STATE_CHANGE_GROUP'] + $returnValue['SuccessfulDatabaseAuthenticationGroup'] = $resultSet['SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP'] + $returnValue['SuccessfulLoginGroup'] = $resultSet['SUCCESSFUL_LOGIN_GROUP'] + $returnValue['TraceChangeGroup'] = $resultSet['TRACE_CHANGE_GROUP'] + $returnValue['UserChangePasswordGroup'] = $resultSet['USER_CHANGE_PASSWORD_GROUP'] + $returnValue['UserDefinedAuditGroup'] = $resultSet['USER_DEFINED_AUDIT_GROUP'] + $returnValue['TransactionGroup'] = $resultSet['TRANSACTION_GROUP'] + $returnValue['Enabled'] = $dataSetRow.is_state_enabled + } + } + + return $returnValue +} + +<# + .SYNOPSIS + Creates, removes or updates a server audit specification to it's desired state. + + .PARAMETER Name + Specifies the name of the server audit specification to be added or removed. + + .PARAMETER ServerName + Specifies the host name of the SQL Server on which the instance exist. + + .PARAMETER InstanceName + Specifies the SQL instance in which the server audit specification exist. + + .PARAMETER Ensure + Specifies if the server audit specification should be present or absent. + If 'Present' then the server audit specification will be added to the instance + and, if needed, the server audit specification will be updated. If 'Absent' + then the server audit specification will be removed from the instance. + Defaults to 'Present'. + + .PARAMETER AuditName + Specifies the audit that should be used to store the server audit specification + events. + + .PARAMETER Enabled + Specifies if the server audit specification should be enabled or disabled. + + .PARAMETER ApplicationRoleChangePasswordGroup + Specifies if this audit specification should be on or off + + .PARAMETER AuditChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER BackupRestoreGroup + Specifies if this audit specification should be on or off + + .PARAMETER BrokerLoginGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseLogoutGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseMirroringLoginGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseObjectAccessGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseObjectChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseObjectOwnershipChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseObjectPermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseOperationGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseOwnershipChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabasePermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabasePrincipalChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabasePrincipalImpersonationGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseRoleMemberChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DbccGroup + Specifies if this audit specification should be on or off + + .PARAMETER FailedDatabaseAuthenticationGroup + Specifies if this audit specification should be on or off + + .PARAMETER FailedLoginGroup + Specifies if this audit specification should be on or off + + .PARAMETER FulltextGroup + Specifies if this audit specification should be on or off + + .PARAMETER LoginChangePasswordGroup + Specifies if this audit specification should be on or off + + .PARAMETER LogoutGroup + Specifies if this audit specification should be on or off + + .PARAMETER SchemaObjectAccessGroup + Specifies if this audit specification should be on or off + + .PARAMETER SchemaObjectChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER SchemaObjectOwnershipChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER SchemaObjectPermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerObjectChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerObjectOwnershipChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerObjectPermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerOperationGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerPermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerPrincipalChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerPrincipalImpersonationGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerRoleMemberChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerStateChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER SuccessfulDatabaseAuthenticationGroup + Specifies if this audit specification should be on or off + + .PARAMETER SuccessfulLoginGroup + Specifies if this audit specification should be on or off + + .PARAMETER TraceChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER UserChangePasswordGroup + Specifies if this audit specification should be on or off + + .PARAMETER UserDefinedAuditGroup + Specifies if this audit specification should be on or off + + .PARAMETER TransactionGroup + Specifies if this audit specification should be on or off +#> +function Set-TargetResource +{ + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('SqlServerDsc.AnalyzerRules\Measure-CommandsNeededToLoadSMO', '', Justification='The command Invoke-Query is used which calls the command Connect-Sql')] + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter(Mandatory = $true)] + [System.String] + $ServerName, + + [Parameter(Mandatory = $true)] + [System.String] + $InstanceName, + + [Parameter()] + [System.String] + $AuditName, + + [Parameter()] + [System.Boolean] + $ApplicationRoleChangePasswordGroup = $false, + + [Parameter()] + [System.Boolean] + $AuditChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $BackupRestoreGroup = $false, + + [Parameter()] + [System.Boolean] + $BrokerLoginGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseLogoutGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseMirroringLoginGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseObjectAccessGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseObjectChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseObjectOwnershipChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseObjectPermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseOperationGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseOwnershipChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabasePermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabasePrincipalChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabasePrincipalImpersonationGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseRoleMemberChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DbccGroup = $false, + + [Parameter()] + [System.Boolean] + $FailedDatabaseAuthenticationGroup = $false, + + [Parameter()] + [System.Boolean] + $FailedLoginGroup = $false, + + [Parameter()] + [System.Boolean] + $FulltextGroup = $false, + + [Parameter()] + [System.Boolean] + $LoginChangePasswordGroup = $false, + + [Parameter()] + [System.Boolean] + $LogoutGroup = $false, + + [Parameter()] + [System.Boolean] + $SchemaObjectAccessGroup = $false, + + [Parameter()] + [System.Boolean] + $SchemaObjectChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $SchemaObjectOwnershipChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $SchemaObjectPermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerObjectChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerObjectOwnershipChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerObjectPermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerOperationGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerPermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerPrincipalChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerPrincipalImpersonationGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerRoleMemberChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerStateChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $SuccessfulDatabaseAuthenticationGroup = $false, + + [Parameter()] + [System.Boolean] + $SuccessfulLoginGroup = $false, + + [Parameter()] + [System.Boolean] + $TraceChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $UserChangePasswordGroup = $false, + + [Parameter()] + [System.Boolean] + $UserDefinedAuditGroup = $false, + + [Parameter()] + [System.Boolean] + $TransactionGroup = $false, + + [Parameter()] + [System.Boolean] + $Enabled = $false, + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Boolean] + $Force = $false + ) + + Write-Verbose -Message ( + $script:localizedData.SetAuditSpecification -f $Name, $ServerName, $InstanceName + ) + + $TargetResourceParameters = @{ + ServerName = $ServerName + InstanceName = $InstanceName + Name = $Name + } + + # Get-TargetResource will also help us to test if the database exist. + $getTargetResourceResult = Get-TargetResource @TargetResourceParameters + + # Default parameters for the cmdlet Invoke-Query used throughout. + $invokeQueryParameters = @{ + ServerName = $ServerName + InstanceName = $InstanceName + Database = 'MASTER' + } + + $desiredValues = @{ } + $PSBoundParameters + + $auditSpecificationAddDropString = Get-AuditSpecificationMutationString -CurrentValues $getTargetResourceResult -DesiredValues $desiredValues + + Write-Debug -Message $( + Get-AuditSpecificationMutationString -CurrentValues $getTargetResourceResult -DesiredValues $desiredValues + ) + + $recreateAudit = $false + + if ($getTargetResourceResult.Ensure -eq $Ensure) + { + if ($Ensure -eq 'Present') + { + # Update, if needed. + Write-Verbose -Message ( + $script:localizedData.CreateAuditSpecification -f $Name, $serverName, $instanceName + ) + + Disable-AuditSpecification -ServerName $serverName -Name $Name -InstanceName $instanceName + + try + { + Invoke-Query @invokeQueryParameters -Query ( + 'ALTER SERVER AUDIT SPECIFICATION [{0}] FOR SERVER AUDIT [{1}] {2}' -f + $Name, + $AuditName, + $auditSpecificationAddDropString + ) + } + catch + { + #If something went wrong, try to recreate te resource. + $recreateAudit = $true + + $errorMessage = $script:localizedData.FailedUpdateAuditSpecification -f $Name, $serverName, $instanceName + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ + } + + if ($Enabled -eq $true) + { + Enable-AuditSpecification -ServerName $serverName -Name $Name -InstanceName $instanceName + } + } + } + + # Throw if not opt-in to re-create server audit specification. + if ($recreateAudit -and -not $Force) + { + $errorMessage = $script:localizedData.ForceNotEnabled + New-InvalidOperationException -Message $errorMessage + } + + if (($Ensure -eq 'Absent' -and $getTargetResourceResult.Ensure -ne $Ensure) -or $recreateAudit) + { + Write-Verbose -Message ( + $script:localizedData.DropAuditSpecification -f $Name, $serverName, $instanceName + ) + + Disable-AuditSpecification -ServerName $serverName -Name $Name -InstanceName $instanceName + + # Drop the server audit. + try + { + Invoke-Query @invokeQueryParameters -Query ( + 'DROP SERVER AUDIT SPECIFICATION [{0}];' -f $Name + ) + } + catch + { + $errorMessage = $script:localizedData.FailedDropAuditSpecification -f $Name, $serverName, $instanceName + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ + } + } + + <# + This evaluation is made to handle creation and re-creation of a database + user to minimize the logic when the user has a different user type, or + when there are restrictions on altering an existing database user. + #> + if (($Ensure -eq 'Present' -and $getTargetResourceResult.Ensure -ne $Ensure) -or $recreateAudit) + { + Write-Verbose -Message ( + $script:localizedData.CreateAuditSpecification -f $Name, $serverName, $instanceName + ) + + try + { + #when target audit already has an audit specification, graceful abort. + #only one audit spec for each audit per database/server can exist. + $DataSetAudit = Invoke-Query @invokeQueryParameters -WithResults -Query ( + 'select sas.name from + sys.server_audits sa inner join + sys.server_audit_specifications sas + on sa.audit_guid = sas.audit_guid + where sa.name = ''{0}''' -f + $AuditName) + if ($null -eq $DataSetAudit -or $DataSetAudit.Tables[0].Rows.Count -gt 0) + { + $errorMessage = $script:localizedData.AuditAlreadyInUse -f + $AuditName, + $Name, + $serverName, + $instanceName, + $DataSetAudit.Tables[0].Rows[0] + New-InvalidOperationException -Message $errorMessage #-ErrorRecord $_ + } + } + catch + { + $errorMessage = $script:localizedData.FailedCreateAuditSpecification -f $Name, $serverName, $instanceName + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ + } + + # Create, if needed and possible. + try + { + Invoke-Query @invokeQueryParameters -Query ( + 'CREATE SERVER AUDIT SPECIFICATION [{0}] FOR SERVER AUDIT [{1}] {2}' -f + $Name, + $AuditName, + $auditSpecificationAddDropString) + + if ($Enabled -eq $true) + { + Enable-AuditSpecification -ServerName $serverName -Name $Name -InstanceName $instanceName + } + } + catch + { + $errorMessage = $script:localizedData.FailedCreateAuditSpecification -f $Name, $serverName, $instanceName + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ + } + } +} + + + +<# + .SYNOPSIS + Determines if the server audit specification is in desired state. + + .PARAMETER Name + Specifies the name of the server audit specification to be added or removed. + + .PARAMETER ServerName + Specifies the host name of the SQL Server on which the instance exist. + + .PARAMETER InstanceName + Specifies the SQL instance in which the server audit specification exist. + + .PARAMETER Ensure + Specifies if the server audit specification should be present or absent. + If 'Present' then the server audit specification will be added to the instance + and, if needed, the server audit specification will be updated. If 'Absent' + then the server audit specification will be removed from the instance. + Defaults to 'Present'. + + .PARAMETER AuditName + Specifies the audit that should be used to store the server audit specification + events. + + .PARAMETER Enabled + Specifies if the server audit specification should be enabled or disabled. + + .PARAMETER ApplicationRoleChangePasswordGroup + Specifies if this audit specification should be on or off + + .PARAMETER AuditChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER BackupRestoreGroup + Specifies if this audit specification should be on or off + + .PARAMETER BrokerLoginGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseLogoutGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseMirroringLoginGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseObjectAccessGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseObjectChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseObjectOwnershipChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseObjectPermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseOperationGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseOwnershipChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabasePermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabasePrincipalChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabasePrincipalImpersonationGroup + Specifies if this audit specification should be on or off + + .PARAMETER DatabaseRoleMemberChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER DbccGroup + Specifies if this audit specification should be on or off + + .PARAMETER FailedDatabaseAuthenticationGroup + Specifies if this audit specification should be on or off + + .PARAMETER FailedLoginGroup + Specifies if this audit specification should be on or off + + .PARAMETER FulltextGroup + Specifies if this audit specification should be on or off + + .PARAMETER LoginChangePasswordGroup + Specifies if this audit specification should be on or off + + .PARAMETER LogoutGroup + Specifies if this audit specification should be on or off + + .PARAMETER SchemaObjectAccessGroup + Specifies if this audit specification should be on or off + + .PARAMETER SchemaObjectChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER SchemaObjectOwnershipChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER SchemaObjectPermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerObjectChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerObjectOwnershipChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerObjectPermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerOperationGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerPermissionChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerPrincipalChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerPrincipalImpersonationGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerRoleMemberChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER ServerStateChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER SuccessfulDatabaseAuthenticationGroup + Specifies if this audit specification should be on or off + + .PARAMETER SuccessfulLoginGroup + Specifies if this audit specification should be on or off + + .PARAMETER TraceChangeGroup + Specifies if this audit specification should be on or off + + .PARAMETER UserChangePasswordGroup + Specifies if this audit specification should be on or off + + .PARAMETER UserDefinedAuditGroup + Specifies if this audit specification should be on or off + + .PARAMETER TransactionGroup + Specifies if this audit specification should be on or off +#> +function Test-TargetResource +{ + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('SqlServerDsc.AnalyzerRules\Measure-CommandsNeededToLoadSMO', '', Justification='The command Invoke-Query is called when Get-TargetResource is called')] + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter(Mandatory = $true)] + [System.String] + $ServerName, + + [Parameter(Mandatory = $true)] + [System.String] + $InstanceName, + + [Parameter()] + [System.String] + $AuditName, + + [Parameter()] + [System.Boolean] + $ApplicationRoleChangePasswordGroup = $false, + + [Parameter()] + [System.Boolean] + $AuditChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $BackupRestoreGroup = $false, + + [Parameter()] + [System.Boolean] + $BrokerLoginGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseLogoutGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseMirroringLoginGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseObjectAccessGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseObjectChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseObjectOwnershipChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseObjectPermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseOperationGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseOwnershipChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabasePermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabasePrincipalChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabasePrincipalImpersonationGroup = $false, + + [Parameter()] + [System.Boolean] + $DatabaseRoleMemberChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $DbccGroup = $false, + + [Parameter()] + [System.Boolean] + $FailedDatabaseAuthenticationGroup = $false, + + [Parameter()] + [System.Boolean] + $FailedLoginGroup = $false, + + [Parameter()] + [System.Boolean] + $FulltextGroup = $false, + + [Parameter()] + [System.Boolean] + $LoginChangePasswordGroup = $false, + + [Parameter()] + [System.Boolean] + $LogoutGroup = $false, + + [Parameter()] + [System.Boolean] + $SchemaObjectAccessGroup = $false, + + [Parameter()] + [System.Boolean] + $SchemaObjectChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $SchemaObjectOwnershipChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $SchemaObjectPermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerObjectChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerObjectOwnershipChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerObjectPermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerOperationGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerPermissionChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerPrincipalChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerPrincipalImpersonationGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerRoleMemberChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $ServerStateChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $SuccessfulDatabaseAuthenticationGroup = $false, + + [Parameter()] + [System.Boolean] + $SuccessfulLoginGroup = $false, + + [Parameter()] + [System.Boolean] + $TraceChangeGroup = $false, + + [Parameter()] + [System.Boolean] + $UserChangePasswordGroup = $false, + + [Parameter()] + [System.Boolean] + $UserDefinedAuditGroup = $false, + + [Parameter()] + [System.Boolean] + $TransactionGroup = $false, + + [Parameter()] + [System.Boolean] + $Enabled = $false, + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Boolean] + $Force = $false + ) + + Write-Verbose -Message ( + $script:localizedData.EvaluateAuditSpecification -f $Name, $ServerName, $InstanceName + ) + + $TargetResourceParameters = @{ + ServerName = $ServerName + InstanceName = $InstanceName + Name = $Name + } + + # Get-TargetResource will also help us to test if the audit exist. + $getTargetResourceResult = Get-TargetResource @TargetResourceParameters + + if ($getTargetResourceResult.Ensure -eq $Ensure) + { + if ($Ensure -eq 'Present') + { + <# + Make sure default values are part of desired values if the user did + not specify them in the configuration. + #> + $desiredValues = @{ } + $PSBoundParameters + $desiredValues['Ensure'] = $Ensure + + $testDscParameterStateParameters = @{ + CurrentValues = $getTargetResourceResult + DesiredValues = $desiredValues + Properties = @( + 'Ensure' + 'AuditName' + 'ApplicationRoleChangePasswordGroup' + 'AuditChangeGroup' + 'BackupRestoreGroup' + 'BrokerLoginGroup' + 'DatabaseChangeGroup' + 'DatabaseLogoutGroup' + 'DatabaseMirroringLoginGroup' + 'DatabaseObjectAccessGroup' + 'DatabaseObjectChangeGroup' + 'DatabaseObjectOwnershipChangeGroup' + 'DatabaseObjectPermissionChangeGroup' + 'DatabaseOperationGroup' + 'DatabaseOwnershipChangeGroup' + 'DatabasePermissionChangeGroup' + 'DatabasePrincipalChangeGroup' + 'DatabasePrincipalImpersonationGroup' + 'DatabaseRoleMemberChangeGroup' + 'DbccGroup' + 'FailedDatabaseAuthenticationGroup' + 'FailedLoginGroup' + 'FulltextGroup' + 'LoginChangePasswordGroup' + 'LogoutGroup' + 'SchemaObjectAccessGroup' + 'SchemaObjectChangeGroup' + 'SchemaObjectOwnershipChangeGroup' + 'SchemaObjectPermissionChangeGroup' + 'ServerObjectChangeGroup' + 'ServerObjectOwnershipChangeGroup' + 'ServerObjectPermissionChangeGroup' + 'ServerOperationGroup' + 'ServerPermissionChangeGroup' + 'ServerPrincipalChangeGroup' + 'ServerPrincipalImpersonationGroup' + 'ServerRoleMemberChangeGroup' + 'ServerStateChangeGroup' + 'SuccessfulDatabaseAuthenticationGroup' + 'SuccessfulLoginGroup' + 'TraceChangeGroup' + 'UserChangePasswordGroup' + 'UserDefinedAuditGroup' + 'TransactionGroup' + 'Enabled' + ) + TurnOffTypeChecking = $true + # TODO: Remove verbose + Verbose = $true + } + + $propertiesNotInDesiredState = Compare-DscParameterState @testDscParameterStateParameters + + if ($propertiesNotInDesiredState) + { + $testTargetResourceReturnValue = $false + } + else + { + $testTargetResourceReturnValue = $true + } + } + else + { + $testTargetResourceReturnValue = $true + } + } + else + { + $testTargetResourceReturnValue = $false + } + + if ($testTargetResourceReturnValue) + { + Write-Verbose -Message $script:localizedData.InDesiredState + } + else + { + Write-Verbose -Message $script:localizedData.NotInDesiredState + } + + return $testTargetResourceReturnValue +} + +<# + .SYNOPSIS + Converts a data table to a HashTable + + .PARAMETER DataTable + The data table to be converted to a hashtable. The data table can have one + or two columns. When the data table has one column, the hashtable will use + $true as value for the second column. +#> +function Convert-ToHashTable +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [system.Data.DataTable] + $DataTable + ) + + $resultSet = @{} + + foreach ($item in $DataTable) + { + if ($DataTable.Columns.Count -eq 1) + { + $resultSet.Add($item[0], $true) + } + if ($DataSet.Columns.Count -eq 2) + { + $resultSet.Add($item[0], $item[1]) + } + } + return $resultSet +} + +<# + .SYNOPSIS + Disables a server audit specification. + + .PARAMETER Name + Specifies the name of the server audit specification to be disabled. + + .PARAMETER ServerName + Specifies the host name of the SQL Server on which the instance exist. + + .PARAMETER InstanceName + Specifies the SQL instance in which the audit exist. +#> +function Disable-AuditSpecification +{ + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $ServerName, + + [Parameter(Mandatory = $true)] + [System.String] + $InstanceName, + + [Parameter(Mandatory = $true)] + [System.String] + $Name + ) + + Write-Verbose -Message ( + $script:localizedData.DisableAuditSpecification -f $Name, $serverName, $instanceName + ) + + $invokeQueryParameters = @{ + ServerName = $ServerName + InstanceName = $InstanceName + Database = 'MASTER' + } + + Invoke-Query @invokeQueryParameters -Query ( + 'ALTER SERVER AUDIT SPECIFICATION [{0}] WITH (STATE = OFF);' -f $Name + ) +} + +<# + .SYNOPSIS + Enables a server audit specification. + + .PARAMETER Name + Specifies the name of the server audit specification to be enabled. + + .PARAMETER ServerName + Specifies the host name of the SQL Server on which the instance exist. + + .PARAMETER InstanceName + Specifies the SQL instance in which the audit exist. +#> +function Enable-AuditSpecification +{ + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $ServerName, + + [Parameter(Mandatory = $true)] + [System.String] + $InstanceName, + + [Parameter(Mandatory = $true)] + [System.String] + $Name + ) + + Write-Verbose -Message ( + $script:localizedData.EnableAuditSpecification -f $Name, $serverName, $instanceName + ) + + $invokeQueryParameters = @{ + ServerName = $ServerName + InstanceName = $InstanceName + Database = 'MASTER' + } + + Invoke-Query @invokeQueryParameters -Query ( + 'ALTER SERVER AUDIT SPECIFICATION [{0}] WITH (STATE = ON);' -f $Name + ) +} + +<# + .SYNOPSIS + Converts the parameter name to the equivalent database object name. + + .PARAMETER InString + Specifies the name of the parameter to be converted to a server policy string. + + .EXAMPLE + $strKey = 'AuditChangeGroup' + $ret = Get-DatabaseObjectNameFromPSParamName -InString $strKey + $ret + Should return 'AUDIT_CHANGE_GROUP' in $ret + + .NOTES + Trough this function the capital letters in Get- Test- and Set-TargetResource + parameters get converted, e.g. FulltextGroup and AuditChangeGroup to + FULLTEXT_GROUP and AUDIT_CHANGE_GROUP. + This is the naming of audit specification within SQL Server. + + DO NOT CHANGE THE CAPITALS IN THE PARAMETERS! + These are used to find the places to insert an underscore. +#> +function Get-DatabaseObjectNameFromPSParamName +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $InString + ) + + return ($InString -creplace '([A-Z\W_]|\d+)(? +function Get-AuditSpecificationMutationString +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter(Mandatory = $true)] + [Hashtable] + $CurrentValues, + + [Parameter(Mandatory = $true)] + [hashtable] + $DesiredValues + ) + + $resultString = '' + + $CurrentValues.GetEnumerator() | ForEach-Object { + if ($null -eq $_.Value -or $_.Value -eq '') + { + $val = 'False' + } + else + { + $val = $_.Value + } + $resultString += Test-SingleRow -CurrentKey $_.Key -CurrentValue $val -DesiredValues $DesiredValues + } + + return $resultString.TrimEnd(',') +} + +<# + .SYNOPSIS + Builds a ADD/DROP string for all the needed changes of the database audit + specification + + .PARAMETER $CurrentKey + Specifies the current Key to be checked against the hash DesiredValues. + + .PARAMETER $CurrentValue + Specifies the current Value to be checked against the hash DesiredValues. + + .PARAMETER $DesiredValues + Specifies the hashtable containing the desired settings. Usually this + should be all of the input parameters of Set-TargetResource. +#> +function Test-SingleRow +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter(Mandatory = $true)] + [String] + $CurrentKey, + + [Parameter(Mandatory = $true)] + [String] + $CurrentValue, + + [Parameter(Mandatory = $true)] + [hashtable] + $DesiredValues + ) + + $return = '' + + if ($CurrentKey -ne 'Name' -and + $CurrentKey -ne 'ServerName' -and + $CurrentKey -ne 'InstanceName' -and + $CurrentKey -ne 'AuditName' -and + $CurrentKey -ne 'Enabled' -and + $CurrentKey -ne 'Ensure' -and + $CurrentKey -ne 'Force') + { + if ($null -eq $DesiredValues.$CurrentKey) + { + $desiredValue = 'False' + } + else + { + $desiredValue = $DesiredValues.$CurrentKey + } + + #When not equal + if ($CurrentValue -ne $desiredValue) + { + $DatabaseCompatibleKeyString = Get-DatabaseObjectNameFromPSParamName -InString $CurrentKey + + if ($desiredValue -eq 'True') + { + #When desired, add it. + $return = 'ADD ({0}),' -f $DatabaseCompatibleKeyString + } + else + { + #When not wanted, drop it. + $return = 'DROP ({0}),' -f $DatabaseCompatibleKeyString + } + } + } + + return $return +} diff --git a/source/DSCResources/DSC_SqlServerAuditSpecification/DSC_SqlServerAuditSpecification.schema.mof b/source/DSCResources/DSC_SqlServerAuditSpecification/DSC_SqlServerAuditSpecification.schema.mof new file mode 100644 index 000000000..8aff2e0f1 --- /dev/null +++ b/source/DSCResources/DSC_SqlServerAuditSpecification/DSC_SqlServerAuditSpecification.schema.mof @@ -0,0 +1,53 @@ +[ClassVersion("1.0.0.0"), FriendlyName("SqlServerAuditSpecification")] +class DSC_SqlServerAuditSpecification : OMI_BaseResource +{ + [Key, Description("Specifies the host name of the SQL Server on which the instance exist.")] String ServerName; + [Key, Description("Specifies the SQL instance in which the Audit exist.")] String InstanceName; + [Key, Description("Specifies the name of the SQL audit specification to be added or removed.")] String Name; + [Write, Description("Specifies if the audit specification should be enabled. Defaults to $false")] Boolean Enabled; + [Write, Description("Specifies the audit to be used as storage.")] String AuditName; + [Write, Description("Specifies if this property should be audited.")] Boolean ApplicationRoleChangePasswordGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean AuditChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean BackupRestoreGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean BrokerLoginGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseLogoutGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseMirroringLoginGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseObjectAccessGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseObjectChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseObjectOwnershipChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseObjectPermissionChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseOperationGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseOwnershipChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabasePermissionChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabasePrincipalChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabasePrincipalImpersonationGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DatabaseRoleMemberChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean DbccGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean FailedDatabaseAuthenticationGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean FailedLoginGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean FulltextGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean LoginChangePasswordGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean LogoutGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean SchemaObjectAccessGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean SchemaObjectChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean SchemaObjectOwnershipChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean SchemaObjectPermissionChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerObjectChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerObjectOwnershipChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerObjectPermissionChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerOperationGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerPermissionChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerPrincipalChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerPrincipalImpersonationGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerRoleMemberChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean ServerStateChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean SuccessfulDatabaseAuthenticationGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean SuccessfulLoginGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean TraceChangeGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean UserChangePasswordGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean UserDefinedAuditGroup; + [Write, Description("Specifies if this property should be audited.")] Boolean TransactionGroup; + [Write, Description("Specifies if the audit should be present or absent. If 'Present' then the audit will be added to the server and, if needed, the audit will be updated. If 'Absent' then the audit will be removed from the server. Defaults to 'Present'."), ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] String Ensure; + [Write, Description("Specifies if it is allowed to re-create the server audit when the DestinationType changes. Defaults to $false not allowing server audits to be re-created.")] Boolean Force; +}; diff --git a/source/DSCResources/DSC_SqlServerAuditSpecification/en-US/DSC_SqlServerAuditSpecification.strings.psd1 b/source/DSCResources/DSC_SqlServerAuditSpecification/en-US/DSC_SqlServerAuditSpecification.strings.psd1 new file mode 100644 index 000000000..d3e9c9b3b --- /dev/null +++ b/source/DSCResources/DSC_SqlServerAuditSpecification/en-US/DSC_SqlServerAuditSpecification.strings.psd1 @@ -0,0 +1,17 @@ +ConvertFrom-StringData @' + RetrievingAuditSpecificationInformation = Retrieving information about Audit specification '{0}' from the server '{1}' instance '{2}'. (SSAS0001) + EvaluateAuditSpecification = Determining if the audit specification '{0}' on server '{1}' instance '{2}' is in the desired state. (SSAS0002) + AuditSpecificationExist = The audit specification '{0}' exist in on server '{1}' instance '{2}'. (SSAS0003) + InDesiredState = The audit specification is in desired state. (SSAS0004) + NotInDesiredState = The audit specification is not in desired state. (SSAS0005) + DisableAuditSpecification = Disabling audit audit specification '{0}' on server '{1}' instance '{2}'. (SSAS0006) + EnableAuditSpecification = Enabling audit audit specification '{0}' on server '{1}' instance '{2}'. (SSAS0007) + CreateAuditSpecification = Creating the audit specification '{0}' on server '{1}' instance '{2}'. (SSAS008) + FailedCreateAuditSpecification = Failed creating audit specification '{0}' on server '{1}' instance '{2}'. (SSAS0009) + AuditAlreadyInUse = Audit {0} for audit specification '{1}' on server '{2}' instance '{3}' is already in use for audit specification '{4}' (SSAS0010) + DropAuditSpecification = Removing the audit specification '{0}' from server '{1}' instance '{2}'. (SSAS0011) + FailedDropAuditSpecification = Failed removing the audit specification '{0}' from server '{1}' instance '{2}'. (SSAS0012) + SetAuditSpecification = Setting the audit specification '{0}' on server '{1}' instance '{2}' to the desired state. (SSAS0013) + FailedUpdateAuditSpecification = Failed updating audit specification '{0}' on server '{1}' instance '{2}'. (SSAS0014) + ForceNotEnabled = Unable to re-create the server audit. The server audit needs to be re-created but the configuration has not opt-in to re-create the audit. To opt-in set the parameter Force to $true. (SSAS0015) +'@ diff --git a/source/Examples/README.md b/source/Examples/README.md index 60629599c..98c764eb1 100644 --- a/source/Examples/README.md +++ b/source/Examples/README.md @@ -16,6 +16,7 @@ These are the links to the examples for each individual resource. - [SqlAlias](Resources/SqlAlias) - [SqlAlwaysOnService](Resources/SqlAlwaysOnService) - [SqlAudit](Resources/SqlAudit) +- [SqlServerAuditSpecification](Resources/SqlServerAuditSpecification) - [SqlDatabase](Resources/SqlDatabase) - [SqlDatabaseDefaultLocation](Resources/SqlDatabaseDefaultLocation) - [SqlDatabasePermission](Resources/SqlDatabasePermission) diff --git a/source/Examples/Resources/SqlServerAuditSpecification/1-AddServerAuditSpecificationAdminAudit.ps1 b/source/Examples/Resources/SqlServerAuditSpecification/1-AddServerAuditSpecificationAdminAudit.ps1 new file mode 100644 index 000000000..0288f2607 --- /dev/null +++ b/source/Examples/Resources/SqlServerAuditSpecification/1-AddServerAuditSpecificationAdminAudit.ps1 @@ -0,0 +1,65 @@ +<# + .EXAMPLE + This example shows how to ensure that an audit destination + is absent on the instance sqltest.company.local\DSC. +#> +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [System.Management.Automation.PSCredential] + $SqlAdministratorCredential + ) + + Import-DscResource -ModuleName SqlServerDsc + + node localhost + { + SqlAudit SecurityLogAudit_Server + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'SecLogAudit' + LogType = 'SecurityLog' + Enabled = $true + PsDscRunAsCredential = $SqlAdministratorCredential + } + + SqlServerAuditSpecification 'ServerAuditSpecification_AdminAudit' + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'AdminAudit' + AuditName = 'SecLogAudit' + Enabled = $true + AuditChangeGroup = $true + BackupRestoreGroup = $true + DatabaseObjectChangeGroup = $true + DatabaseObjectOwnershipChangeGroup = $true + DatabaseObjectPermissionChangeGroup = $true + DatabaseOwnershipChangeGroup = $true + DatabasePermissionChangeGroup = $true + DatabasePrincipalChangeGroup = $true + DatabasePrincipalImpersonationGroup = $true + DatabaseRoleMemberChangeGroup = $true + SchemaObjectChangeGroup = $true + SchemaObjectOwnershipChangeGroup = $true + SchemaObjectPermissionChangeGroup = $true + ServerObjectChangeGroup = $true + ServerObjectOwnershipChangeGroup = $true + ServerObjectPermissionChangeGroup = $true + ServerOperationGroup = $true + ServerPermissionChangeGroup = $true + ServerPrincipalChangeGroup = $true + ServerPrincipalImpersonationGroup = $true + ServerRoleMemberChangeGroup = $true + ServerStateChangeGroup = $true + TraceChangeGroup = $true + DependsOn = '[SqlAudit]SecurityLogAudit_Server' + PsDscRunAsCredential = $SqlAdministratorCredential + } + } +} diff --git a/source/Examples/Resources/SqlServerAuditSpecification/2-AddServerAuditSpecificationLoginAudit.ps1 b/source/Examples/Resources/SqlServerAuditSpecification/2-AddServerAuditSpecificationLoginAudit.ps1 new file mode 100644 index 000000000..bf8e5a29b --- /dev/null +++ b/source/Examples/Resources/SqlServerAuditSpecification/2-AddServerAuditSpecificationLoginAudit.ps1 @@ -0,0 +1,49 @@ +<# + .EXAMPLE + This example shows how to ensure that an audit destination + is absent on the instance sqltest.company.local\DSC. +#> +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [System.Management.Automation.PSCredential] + $SqlAdministratorCredential + ) + + Import-DscResource -ModuleName SqlServerDsc + + node localhost + { + SqlAudit SecurityLogAudit_Server + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'SecLogAudit' + LogType = 'SecurityLog' + Enabled = $true + PsDscRunAsCredential = $SqlAdministratorCredential + } + + SqlServerAuditSpecification 'ServerAuditSpecification_AdminAudit' + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'AdminAudit' + AuditName = 'SecLogAudit' + Enabled = $true + DatabaseLogoutGroup = $true + FailedDatabaseAuthenticationGroup = $true + FailedLoginGroup = $true + LoginChangePasswordGroup = $true + LogoutGroup = $true + SuccessfulDatabaseAuthenticationGroup = $true + SuccessfulLoginGroup = $true + DependsOn = '[SqlAudit]SecurityLogAudit_Server' + PsDscRunAsCredential = $SqlAdministratorCredential + } + } +} diff --git a/source/Examples/Resources/SqlServerAuditSpecification/3-AddServerAuditAuditChange.ps1 b/source/Examples/Resources/SqlServerAuditSpecification/3-AddServerAuditAuditChange.ps1 new file mode 100644 index 000000000..f4fa11bac --- /dev/null +++ b/source/Examples/Resources/SqlServerAuditSpecification/3-AddServerAuditAuditChange.ps1 @@ -0,0 +1,44 @@ +<# + .EXAMPLE + This example shows how to ensure that an audit destination + is absent on the instance sqltest.company.local\DSC. +#> +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [System.Management.Automation.PSCredential] + $SqlAdministratorCredential + ) + + Import-DscResource -ModuleName SqlServerDsc + + node localhost + { + SqlAudit SecurityLogAudit_Server + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'SecLogAudit' + LogType = 'SecurityLog' + Enabled = $true + PsDscRunAsCredential = $SqlAdministratorCredential + } + + SqlServerAuditSpecification 'ServerAuditSpecification_AuditAudit' + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'AuditAudit' + AuditName = 'SecLogAudit' + Enabled = $true + AuditChangeGroup = $true + TraceChangeGroup = $true + DependsOn = "[SqlAudit]SecurityLogAudit_Server" + PsDscRunAsCredential = $SqlAdministratorCredential + } + } +} diff --git a/source/Examples/Resources/SqlServerAuditSpecification/4-AddMultipleServerAudits.ps1 b/source/Examples/Resources/SqlServerAuditSpecification/4-AddMultipleServerAudits.ps1 new file mode 100644 index 000000000..e73789ca0 --- /dev/null +++ b/source/Examples/Resources/SqlServerAuditSpecification/4-AddMultipleServerAudits.ps1 @@ -0,0 +1,90 @@ +<# + .EXAMPLE + This example shows how to add multiple audit specifications to the same instance. + Each audit can only contain one audit specification. +#> +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [System.Management.Automation.PSCredential] + $SqlAdministratorCredential + ) + + Import-DscResource -ModuleName SqlServerDsc + + node localhost + { + SqlAudit SecurityLogAudit_Server01 + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'SecLogAudit01' + LogType = 'SecurityLog' + Enabled = $true + PsDscRunAsCredential = $SqlAdministratorCredential + } + + SqlAudit SecurityLogAudit_Server02 + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'SecLogAudit02' + LogType = 'SecurityLog' + Enabled = $true + PsDscRunAsCredential = $SqlAdministratorCredential + } + + SqlServerAuditSpecification ServerAuditSpecification_AuditAudit + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'AuditAudit' + AuditName = 'SecLogAudit01' + Enabled = $true + AuditChangeGroup = $true + TraceChangeGroup = $true + DependsOn = '[SqlAudit]SecurityLogAudit_Server01' + PsDscRunAsCredential = $SqlAdministratorCredential + } + + SqlServerAuditSpecification ServerAuditSpecification_AdminAudit + { + Ensure = 'Present' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'AdminAudit' + AuditName = 'SecLogAudit02' + Enabled = $true + AuditChangeGroup = $true + BackupRestoreGroup = $true + DatabaseObjectChangeGroup = $true + DatabaseObjectOwnershipChangeGroup = $true + DatabaseObjectPermissionChangeGroup = $true + DatabaseOwnershipChangeGroup = $true + DatabasePermissionChangeGroup = $true + DatabasePrincipalChangeGroup = $true + DatabasePrincipalImpersonationGroup = $true + DatabaseRoleMemberChangeGroup = $true + SchemaObjectChangeGroup = $true + SchemaObjectOwnershipChangeGroup = $true + SchemaObjectPermissionChangeGroup = $true + ServerObjectChangeGroup = $true + ServerObjectOwnershipChangeGroup = $true + ServerObjectPermissionChangeGroup = $true + ServerOperationGroup = $true + ServerPermissionChangeGroup = $true + ServerPrincipalChangeGroup = $true + ServerPrincipalImpersonationGroup = $true + ServerRoleMemberChangeGroup = $true + ServerStateChangeGroup = $true + TraceChangeGroup = $true + DependsOn = '[SqlAudit]SecurityLogAudit_Server02' + PsDscRunAsCredential = $SqlAdministratorCredential + } + } +} diff --git a/source/Examples/Resources/SqlServerAuditSpecification/5-RemoveAuditSpecification.ps1 b/source/Examples/Resources/SqlServerAuditSpecification/5-RemoveAuditSpecification.ps1 new file mode 100644 index 000000000..3a4497229 --- /dev/null +++ b/source/Examples/Resources/SqlServerAuditSpecification/5-RemoveAuditSpecification.ps1 @@ -0,0 +1,29 @@ +<# + .EXAMPLE + This example shows how to ensure that an audit destination + is absent on the instance sqltest.company.local\DSC. +#> +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [System.Management.Automation.PSCredential] + $SqlAdministratorCredential + ) + + Import-DscResource -ModuleName SqlServerDsc + + node localhost + { + SqlServerAuditSpecification 'ServerAuditSpecification_AdminAudit' + { + Ensure = 'Absent' + ServerName = 'sqltest.company.local' + InstanceName = 'DSC' + Name = 'AdminAudit' + AuditName = 'SecLogAudit' + PsDscRunAsCredential = $SqlAdministratorCredential + } + } +} diff --git a/tests/Integration/DSC_SqlServerAuditSpecification.Integration.Tests.ps1 b/tests/Integration/DSC_SqlServerAuditSpecification.Integration.Tests.ps1 new file mode 100644 index 000000000..dcd0c8dd3 --- /dev/null +++ b/tests/Integration/DSC_SqlServerAuditSpecification.Integration.Tests.ps1 @@ -0,0 +1,210 @@ +BeforeDiscovery { + try + { + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + } + + <# + Need to define that variables here to be used in the Pester Discover to + build the ForEach-blocks. + #> + $script:dscResourceFriendlyName = 'SqlServerAuditSpecification' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" +} + +BeforeAll { + # Need to define the variables here which will be used in Pester Run. + $script:dscModuleName = 'SqlServerDsc' + $script:dscResourceFriendlyName = 'SqlServerAuditSpecification' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Integration' + + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" + . $configFile +} + +Describe "$($script:dscResourceName)_Integration" -Tag @('Integration_SQL2016', 'Integration_SQL2017', 'Integration_SQL2019') { + BeforeAll { + $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" + } + + Context ('When using configuration <_>') -ForEach @( + "$($script:dscResourceName)_AddAudit1_Config" + ) { + BeforeAll { + $configurationName = $_ + } + + AfterAll { + Wait-ForIdleLcm + } + + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.AuditSpecificationName1 + $resourceCurrentState.ServerName | Should -Be $ConfigurationData.AllNodes.ServerName + $resourceCurrentState.InstanceName | Should -Be $ConfigurationData.AllNodes.InstanceName + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + Context ('When using configuration <_>') -ForEach @( + "$($script:dscResourceName)_AddSecLogAudit_Config" + ) { + BeforeAll { + $configurationName = $_ + } + + AfterAll { + Wait-ForIdleLcm + } + + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.AuditSpecificationName2 + $resourceCurrentState.ServerName | Should -Be $ConfigurationData.AllNodes.ServerName + $resourceCurrentState.InstanceName | Should -Be $ConfigurationData.AllNodes.InstanceName + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + Context ('When using configuration <_>') -ForEach @( + "$($script:dscResourceName)_RemoveAudit1_Config" + ) { + BeforeAll { + $configurationName = $_ + } + + AfterAll { + Wait-ForIdleLcm + } + + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.Ensure | Should -Be 'Absent' + $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.AuditSpecificationName1 + $resourceCurrentState.ServerName | Should -Be $ConfigurationData.AllNodes.ServerName + $resourceCurrentState.InstanceName | Should -Be $ConfigurationData.AllNodes.InstanceName + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } +} diff --git a/tests/Integration/DSC_SqlServerAuditSpecification.config.ps1 b/tests/Integration/DSC_SqlServerAuditSpecification.config.ps1 new file mode 100644 index 000000000..9d45f578d --- /dev/null +++ b/tests/Integration/DSC_SqlServerAuditSpecification.config.ps1 @@ -0,0 +1,227 @@ +#region HEADER +# Integration Test Config Template Version: 1.2.0 +#endregion + +$configFile = [System.IO.Path]::ChangeExtension($MyInvocation.MyCommand.Path, 'json') +if (Test-Path -Path $configFile) +{ + <# + Allows reading the configuration data from a JSON file, + for real testing scenarios outside of the CI. + #> + $ConfigurationData = Get-Content -Path $configFile | ConvertFrom-Json +} +else +{ + $ConfigurationData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + CertificateFile = $env:DscPublicCertificatePath + + UserName = "$env:COMPUTERNAME\SqlAdmin" + Password = 'P@ssw0rd1' + + ServerName = $env:COMPUTERNAME + InstanceName = 'DSCSQLTEST' + + AuditName1 = 'FileAudit' + Path1 = 'C:\Temp\audit' + MaximumFileSize1 = 10 + MaximumFileSizeUnit1 = 'Megabyte' + MaximumRolloverFiles1 = 11 + + AuditName2 = 'SecLogAudit' + LogType2 = 'SecurityLog' + + AuditSpecificationName1 = 'AdminAudit1' + AuditSpecificationName2 = 'AdminAudit2' + } + ) + } +} + +<# + .SYNOPSIS + Creates a Server Audit with File destination. +#> +Configuration DSC_SqlServerAuditSpecification_AddAudit1_Config +{ + Import-DscResource -ModuleName 'SqlServerDsc' + + node $AllNodes.NodeName + { + SqlAudit 'Integration_TestPrepare' + { + Ensure = 'Present' + ServerName = $Node.ServerName + InstanceName = $Node.InstanceName + Name = $Node.AuditName1 + Path = $Node.Path1 + MaximumFileSize = $Node.MaximumFileSize1 + MaximumFileSizeUnit = $Node.MaximumFileSizeUnit1 + MaximumRolloverFiles = $Node.MaximumRolloverFiles1 + + PsDscRunAsCredential = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + } + + SqlServerAuditSpecification 'Integration_Test' + { + Ensure = 'Present' + ServerName = $Node.ServerName + InstanceName = $Node.InstanceName + Name = $Node.AuditSpecificationName1 + AuditName = $Node.AuditName1 + Enabled = $true + AuditChangeGroup = $true + BackupRestoreGroup = $true + DatabaseObjectChangeGroup = $true + DatabaseObjectOwnershipChangeGroup = $true + DatabaseObjectPermissionChangeGroup = $true + DatabaseOwnershipChangeGroup = $true + DatabasePermissionChangeGroup = $true + DatabasePrincipalChangeGroup = $true + DatabasePrincipalImpersonationGroup = $true + DatabaseRoleMemberChangeGroup = $true + SchemaObjectChangeGroup = $true + SchemaObjectOwnershipChangeGroup = $true + SchemaObjectPermissionChangeGroup = $true + ServerObjectChangeGroup = $true + ServerObjectOwnershipChangeGroup = $true + ServerObjectPermissionChangeGroup = $true + ServerOperationGroup = $true + ServerPermissionChangeGroup = $true + ServerPrincipalChangeGroup = $true + ServerPrincipalImpersonationGroup = $true + ServerRoleMemberChangeGroup = $true + ServerStateChangeGroup = $true + TraceChangeGroup = $true + DependsOn = '[SqlAudit]Integration_TestPrepare' + + PsDscRunAsCredential = $SqlAdministratorCredential + } + } +} + +<# + .SYNOPSIS + Creates a audit to the security log, with a filer. +#> +Configuration DSC_SqlServerAuditSpecification_AddSecLogAudit_Config +{ + Import-DscResource -ModuleName 'SqlServerDsc' + + node $AllNodes.NodeName + { + SqlAudit 'Integration_TestPrepare' + { + Ensure = 'Present' + ServerName = $Node.ServerName + InstanceName = $Node.InstanceName + Name = $Node.AuditName2 + LogType = $Node.LogType2 + + PsDscRunAsCredential = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + } + + SqlServerAuditSpecification 'Integration_Test' + { + Ensure = 'Present' + ServerName = $Node.ServerName + InstanceName = $Node.InstanceName + Name = $Node.AuditSpecificationName2 + AuditName = $Node.AuditName2 + Enabled = $true + AuditChangeGroup = $true + BackupRestoreGroup = $true + DatabaseObjectChangeGroup = $true + DatabaseObjectOwnershipChangeGroup = $true + DatabaseObjectPermissionChangeGroup = $true + DatabaseOwnershipChangeGroup = $true + DatabasePermissionChangeGroup = $true + DatabasePrincipalChangeGroup = $true + DatabasePrincipalImpersonationGroup = $true + DatabaseRoleMemberChangeGroup = $true + SchemaObjectChangeGroup = $true + SchemaObjectOwnershipChangeGroup = $true + SchemaObjectPermissionChangeGroup = $true + ServerObjectChangeGroup = $true + ServerObjectOwnershipChangeGroup = $true + ServerObjectPermissionChangeGroup = $true + ServerOperationGroup = $true + ServerPermissionChangeGroup = $true + ServerPrincipalChangeGroup = $true + ServerPrincipalImpersonationGroup = $true + ServerRoleMemberChangeGroup = $true + ServerStateChangeGroup = $true + TraceChangeGroup = $true + DependsOn = '[SqlAudit]Integration_TestPrepare' + + PsDscRunAsCredential = $SqlAdministratorCredential + } + } +} + +<# + .SYNOPSIS + Removes the file audit. +#> +Configuration DSC_SqlServerAuditSpecification_RemoveAudit1_Config +{ + Import-DscResource -ModuleName 'SqlServerDsc' + + node $AllNodes.NodeName + { + SqlAudit 'Integration_TestPrepare' + { + Ensure = 'Absent' + ServerName = $Node.ServerName + InstanceName = $Node.InstanceName + Name = $Node.AuditName1 + + PsDscRunAsCredential = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + } + + SqlServerAuditSpecification 'Integration_Test' + { + Ensure = 'Absent' + ServerName = $Node.ServerName + InstanceName = $Node.InstanceName + Name = $Node.AuditSpecificationName1 + AuditName = $Node.AuditName1 + Enabled = $true + AuditChangeGroup = $true + BackupRestoreGroup = $true + DatabaseObjectChangeGroup = $true + DatabaseObjectOwnershipChangeGroup = $true + DatabaseObjectPermissionChangeGroup = $true + DatabaseOwnershipChangeGroup = $true + DatabasePermissionChangeGroup = $true + DatabasePrincipalChangeGroup = $true + DatabasePrincipalImpersonationGroup = $true + DatabaseRoleMemberChangeGroup = $true + SchemaObjectChangeGroup = $true + SchemaObjectOwnershipChangeGroup = $true + SchemaObjectPermissionChangeGroup = $true + ServerObjectChangeGroup = $true + ServerObjectOwnershipChangeGroup = $true + ServerObjectPermissionChangeGroup = $true + ServerOperationGroup = $true + ServerPermissionChangeGroup = $true + ServerPrincipalChangeGroup = $true + ServerPrincipalImpersonationGroup = $true + ServerRoleMemberChangeGroup = $true + ServerStateChangeGroup = $true + TraceChangeGroup = $true + DependsOn = '[SqlAudit]Integration_TestPrepare' + + PsDscRunAsCredential = $SqlAdministratorCredential + } + } +} diff --git a/tests/Unit/Stubs/SMO.cs b/tests/Unit/Stubs/SMO.cs index 1ae7ad165..aaa1dd207 100644 --- a/tests/Unit/Stubs/SMO.cs +++ b/tests/Unit/Stubs/SMO.cs @@ -146,6 +146,62 @@ public enum OnFailureAction : int FailOperation = 2, } + public enum AuditActionType : int + { + ApplicationRoleChangePasswordGroup = 0, + AuditChangeGroup = 1, + BackupRestoreGroup = 2, + BatchCompletedGroup = 3, + BatchStartedGroup = 4, + BrokerLoginGroup = 5, + DatabaseChangeGroup = 6, + DatabaseLogoutGroup = 7, + DatabaseMirroringLoginGroup = 8, + DatabaseObjectAccessGroup = 9, + DatabaseObjectChangeGroup = 10, + DatabaseObjectOwnershipChangeGroup = 11, + DatabaseObjectPermissionChangeGroup = 12, + DatabaseOperationGroup = 13, + DatabaseOwnershipChangeGroup = 14, + DatabasePermissionChangeGroup = 15, + DatabasePrincipalChangeGroup = 16, + DatabasePrincipalImpersonationGroup = 17, + DatabaseRoleMemberChangeGroup = 18, + DbccGroup = 19, + Delete = 20, + Execute = 21, + FailedDatabaseAuthenticationGroup = 22, + FailedLoginGroup = 23, + FullTextGroup = 24, + GlobalTransactionsLoginGroup = 25, + Insert = 26, + LoginChangePasswordGroup = 27, + LogoutGroup = 28, + Receive = 29, + References = 30, + SchemaObjectAccessGroup = 31, + SchemaObjectChangeGroup = 32, + SchemaObjectOwnershipChangeGroup = 33, + SchemaObjectPermissionChangeGroup = 34, + Select = 35, + ServerObjectChangeGroup = 36, + ServerObjectOwnershipChangeGroup = 37, + ServerObjectPermissionChangeGroup = 38, + ServerOperationGroup = 39, + ServerPermissionChangeGroup = 40, + ServerPrincipalChangeGroup = 41, + ServerPrincipalImpersonationGroup = 42, + ServerRoleMemberChangeGroup = 43, + ServerStateChangeGroup = 44, + SuccessfulDatabaseAuthenticationGroup = 45, + SuccessfulLoginGroup = 46, + TraceChangeGroup = 47, + Update = 48, + UserChangePasswordGroup = 49, + UserDefinedAuditGroup = 50, + TransactionGroup = 51, + } + public enum SqlSmoState : int { Pending = 0, @@ -159,6 +215,27 @@ public enum SqlSmoState : int #region Public Classes + public class SqlSmoObject + { + // Property + public System.Object UserData { get; set; } + public Microsoft.SqlServer.Management.Smo.SqlSmoState State { get; set; } + // public Microsoft.SqlServer.Management.Smo.AbstractCollectionBase ParentCollection { get; set; } + // public Microsoft.SqlServer.Management.Sdk.Sfc.Urn Urn { get; set; } + // public Microsoft.SqlServer.Management.Smo.SqlPropertyCollection Properties { get; set; } + // public Microsoft.SqlServer.Management.Common.ServerVersion ServerVersion { get; set; } + // public Microsoft.SqlServer.Management.Common.DatabaseEngineType DatabaseEngineType { get; set; } + // public Microsoft.SqlServer.Management.Common.DatabaseEngineEdition DatabaseEngineEdition { get; set; } + // public Microsoft.SqlServer.Management.Smo.ExecutionManager ExecutionManager { get; set; } + + // Fabricated constructor + private SqlSmoObject() { } + public static SqlSmoObject CreateTypeInstance() + { + return new SqlSmoObject(); + } + } + // Typename: Microsoft.SqlServer.Management.Smo.ObjectPermissionSet // BaseType: Microsoft.SqlServer.Management.Smo.PermissionSetBase // Used by: @@ -959,6 +1036,75 @@ public static PropertyCollection CreateTypeInstance() } } + public class ServerAuditSpecification + { + // Constructor + public ServerAuditSpecification() { } + public ServerAuditSpecification(Microsoft.SqlServer.Management.Smo.Server server, System.String name) { } + + // Property + public Microsoft.SqlServer.Management.Smo.Server Parent { get; set; } + public System.String AuditName { get; set; } + public System.DateTime? CreateDate { get; set; } + public System.DateTime? DateLastModified { get; set; } + public System.Boolean? Enabled { get; set; } + public System.Guid? Guid { get; set; } + public System.Int32? ID { get; set; } + public System.String Name { get; set; } + // public Microsoft.SqlServer.Management.Smo.AbstractCollectionBase ParentCollection { get; set; } + // public Microsoft.SqlServer.Management.Sdk.Sfc.Urn Urn { get; set; } + // public Microsoft.SqlServer.Management.Smo.SqlPropertyCollection Properties { get; set; } + // public Microsoft.SqlServer.Management.Common.ServerVersion ServerVersion { get; set; } + // public Microsoft.SqlServer.Management.Common.DatabaseEngineType DatabaseEngineType { get; set; } + // public Microsoft.SqlServer.Management.Common.DatabaseEngineEdition DatabaseEngineEdition { get; set; } + // public Microsoft.SqlServer.Management.Smo.ExecutionManager ExecutionManager { get; set; } + public System.Object UserData { get; set; } + public Microsoft.SqlServer.Management.Smo.SqlSmoState? State { get; set; } + } + + public class ServerAuditSpecificationCollection + { + // Property + public Microsoft.SqlServer.Management.Smo.Server Parent { get; set; } + // Item is handled differently in the real class, see: + // https://github.com/microsoft/sqlmanagementobjects/blob/main/src/Microsoft/SqlServer/Management/Smo/Collections/ServerAuditSpecificationCollection.cs + public Microsoft.SqlServer.Management.Smo.ServerAuditSpecification Item { get; set; } + public System.Boolean? IsSynchronized { get; set; } + public System.Object SyncRoot { get; set; } + public System.Int32? Count { get; set; } + public Microsoft.SqlServer.Management.Smo.SqlSmoObject ParentInstance { get; set; } + + // Fabricated constructor + private ServerAuditSpecificationCollection() { } + public static ServerAuditSpecificationCollection CreateTypeInstance() + { + return new ServerAuditSpecificationCollection(); + } + } + + public class AuditSpecificationDetail + { + // Constructor + public AuditSpecificationDetail(Microsoft.SqlServer.Management.Smo.AuditActionType action, System.String objectClass, System.String objectSchema, System.String objectName, System.String principal) { } + public AuditSpecificationDetail(Microsoft.SqlServer.Management.Smo.AuditActionType action, System.String objectSchema, System.String objectName, System.String principal) { } + public AuditSpecificationDetail(Microsoft.SqlServer.Management.Smo.AuditActionType action, System.String objectName, System.String principal) { } + public AuditSpecificationDetail(Microsoft.SqlServer.Management.Smo.AuditActionType action) { } + + // Property + public Microsoft.SqlServer.Management.Smo.AuditActionType Action { get; set; } + public System.String ObjectClass { get; set; } + public System.String ObjectName { get; set; } + public System.String ObjectSchema { get; set; } + public System.String Principal { get; set; } + + // Fabricated constructor + private AuditSpecificationDetail() { } + public static AuditSpecificationDetail CreateTypeInstance() + { + return new AuditSpecificationDetail(); + } + } + #endregion Public Classes }