summaryrefslogtreecommitdiffstats
path: root/ansible_collections/lowlydba/sqlserver/plugins
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 16:03:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 16:03:42 +0000
commit66cec45960ce1d9c794e9399de15c138acb18aed (patch)
tree59cd19d69e9d56b7989b080da7c20ef1a3fe2a5a /ansible_collections/lowlydba/sqlserver/plugins
parentInitial commit. (diff)
downloadansible-66cec45960ce1d9c794e9399de15c138acb18aed.tar.xz
ansible-66cec45960ce1d9c794e9399de15c138acb18aed.zip
Adding upstream version 7.3.0+dfsg.upstream/7.3.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/lowlydba/sqlserver/plugins')
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/attributes.py48
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/sql_credentials.py32
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/state.py24
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/module_utils/_SqlServerUtils.psm1186
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/ag_listener.ps186
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/ag_listener.py84
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/ag_replica.ps1193
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/ag_replica.py147
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job.ps1133
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job.py84
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_category.ps164
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_category.py48
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_schedule.ps1164
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_schedule.py142
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_step.ps1157
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_step.py118
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/availability_group.ps1235
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/availability_group.py157
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/backup.ps1138
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/backup.py197
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/credential.ps1117
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/credential.py91
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/database.ps1242
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/database.py94
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/dba_multitool.ps165
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/dba_multitool.py63
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/first_responder_kit.ps180
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/first_responder_kit.py84
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/hadr.ps171
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/hadr.py66
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/install_script.ps186
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/install_script.py104
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/instance_info.ps157
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/instance_info.py34
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/login.ps1144
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/login.py89
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/maintenance_solution.ps1105
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/maintenance_solution.py101
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/memory.ps150
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/memory.py46
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/nonquery.ps151
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/nonquery.py48
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/resource_governor.ps169
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/resource_governor.py47
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/restore.ps1170
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/restore.py230
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/rg_resource_pool.ps1118
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/rg_resource_pool.py90
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/rg_workload_group.ps1112
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/rg_workload_group.py100
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/sa.ps1101
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/sa.py74
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/sp_configure.ps159
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/sp_configure.py50
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/sp_whoisactive.ps157
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/sp_whoisactive.py53
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/spn.ps169
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/spn.py70
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/tcp_port.ps169
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/tcp_port.py70
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/traceflag.ps167
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/traceflag.py55
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/user.ps1142
-rw-r--r--ansible_collections/lowlydba/sqlserver/plugins/modules/user.py81
64 files changed, 6278 insertions, 0 deletions
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/attributes.py b/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/attributes.py
new file mode 100644
index 00000000..76cf703c
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/attributes.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+
+ DOCUMENTATION = r'''
+options: {}
+'''
+
+ CHECK_MODE = r'''
+options: {}
+attributes:
+ check_mode:
+ support: full
+ description: Can run in check_mode and return changed status prediction without modifying target.
+'''
+
+ CHECK_MODE_READ_ONLY = r'''
+options: {}
+attributes:
+ check_mode:
+ support: full
+ description: This module is "read only" and operates the same regardless of check mode.
+'''
+
+ PLATFORM_ALL = r'''
+options: {}
+attributes:
+ platform:
+ platforms: all
+ support: full
+ description: Target OS/families that can be operated against.
+'''
+
+ PLATFORM_WIN = r'''
+options: {}
+attributes:
+ platform:
+ platforms: Windows
+ support: full
+ description: Target OS/families that can be operated against.
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/sql_credentials.py b/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/sql_credentials.py
new file mode 100644
index 00000000..1af7e9a4
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/sql_credentials.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# Options for authenticating with SQL Authentication.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+
+ DOCUMENTATION = r'''
+options:
+ sql_instance:
+ description:
+ - The SQL Server instance to modify.
+ type: str
+ required: true
+ sql_username:
+ description:
+ - Username for SQL Authentication.
+ type: str
+ required: false
+ sql_password:
+ description:
+ - Password for SQL Authentication.
+ type: str
+ required: false
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/state.py b/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/state.py
new file mode 100644
index 00000000..d2ede689
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/doc_fragments/state.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# Options for object state.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+
+ DOCUMENTATION = r'''
+options:
+ state:
+ description:
+ - Whether or not the object should be C(present) or C(absent).
+ required: false
+ type: str
+ default: 'present'
+ choices: ['present', 'absent']
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/module_utils/_SqlServerUtils.psm1 b/ansible_collections/lowlydba/sqlserver/plugins/module_utils/_SqlServerUtils.psm1
new file mode 100644
index 00000000..e45b7c74
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/module_utils/_SqlServerUtils.psm1
@@ -0,0 +1,186 @@
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# Private
+
+function Get-LowlyDbaSqlServerAuthSpec {
+ <#
+ .SYNOPSIS
+ Output the auth spec used by every module.
+
+ .DESCRIPTION
+ Standardized way to access the common auth spec for modules.
+ Uses the recommended Ansible naming convention.
+ #>
+ @{
+ options = @{
+ sql_instance = @{type = 'str'; required = $true }
+ sql_username = @{type = 'str'; required = $false }
+ sql_password = @{type = 'str'; required = $false; no_log = $true }
+ }
+ required_together = @(
+ , @('sql_username', 'sql_password')
+ )
+ }
+}
+
+function Get-SqlCredential {
+ <#
+ .SYNOPSIS
+ Build a credential object for SQL Authentication.
+
+ .DESCRIPTION
+ Standardized way to build a SQL Credential object that is required for SQL Authentication.
+ #>
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true)]
+ [ValidateScript({ $_.GetType().FullName -eq 'Ansible.Basic.AnsibleModule' })]
+ $Module
+ )
+ try {
+ $sqlInstance = $module.Params.sql_instance
+ if ($null -ne $Module.Params.sql_username) {
+ [securestring]$secPassword = ConvertTo-SecureString $Module.Params.sql_password -AsPlainText -Force
+ [pscredential]$sqlCredential = New-Object System.Management.Automation.PSCredential ($Module.Params.sql_username, $secPassword)
+ }
+ else {
+ $sqlCredential = $null
+ }
+ return $sqlInstance, $sqlCredential
+ }
+ catch {
+ Write-Error ("Error building Credential for SQL Authentication spec.")
+ }
+}
+
+function ConvertTo-SerializableObject {
+ <#
+ .SYNOPSIS
+ Transforms some members of a DbaTools result objects to be more serialization-friendly and prevent infinite recursion.
+
+ .DESCRIPTION
+ Stringifies version properties so we don't get serialized [System.Version] objects which aren't very useful.
+ #>
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
+ [Object]
+ $InputObject,
+ [Parameter()]
+ [string[]]
+ $ExcludeProperty = @(
+ <#
+ Returning a list of properties as a property is redundant.
+ #>
+ 'Properties',
+ <#
+ Urn is not useful.
+ #>
+ 'Urn',
+ <#
+ ExecutionManager can contain a login password in plain text.
+ #>
+ 'ExecutionManager',
+ <#
+ UserData is not useful.
+ #>
+ 'UserData',
+ <#
+ ParentCollection is redundant.
+ #>
+ 'ParentCollection',
+ <#
+ DatabaseEngineEdition is not useful.
+ #>
+ 'DatabaseEngineEdition',
+ <#
+ DatabaseEngineType is not useful.
+ #>
+ 'DatabaseEngineType',
+ <#
+ ServerVersion is not useful.
+ #>
+ 'ServerVersion',
+ <#
+ Server is redundant.
+ #>
+ 'Server',
+ <#
+ Parent is not useful.
+ #>
+ 'Parent'
+ ),
+ [bool]$UseDefaultProperty = $true
+ )
+
+ Begin {
+ # We need to remove this type data so that arrays don't get serialized weirdly.
+ # In some cases, an array gets serialized as an object with a Count and Value property where the value is the actual array.
+ # See: https://stackoverflow.com/a/48858780/3905079
+ # This only affects Windows PowerShell.
+ # This has to come after the AnsibleModule is created, otherwise it will break the sanity tests.
+ if (-not $IsLinux) {
+ Remove-TypeData -TypeName System.Array -ErrorAction SilentlyContinue
+ }
+ }
+
+ Process {
+ $defaultProperty = $InputObject.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames
+ if ($defaultProperty -and $UseDefaultProperty) {
+ $objectProperty = $InputObject.PSObject.Properties | Where-Object { $_.Name -in $defaultProperty -and $_.Name -notin $ExcludeProperty }
+ }
+ else {
+ $objectProperty = $InputObject.PSObject.Properties | Where-Object { $_.Name -notin $ExcludeProperty }
+ }
+ $properties = foreach ($p in $objectProperty) {
+ $pName = $p.Name
+ $pValue = $p.Value
+
+ switch ($p) {
+ { $null -eq $pValue } {
+ @{
+ Name = $pName
+ Expression = { $null }.GetNewClosure()
+ }
+ break
+ }
+ { $pValue -is [datetime] } {
+ @{
+ Name = $pName
+ Expression = { $pValue.ToString('o') }.GetNewClosure()
+ }
+ break
+ }
+ { $pValue -is [enum] -or $pValue -is [type] } {
+ @{
+ Name = $pName
+ Expression = { $pValue.ToString() }.GetNewClosure()
+ }
+ break
+ }
+ { $pValue.GetType().Name -like '*Collection' } {
+ @{
+ Name = $pName
+ Expression = { [string[]]($pValue.Name) }.GetNewClosure()
+ }
+ break
+ }
+ { $pValue.GetType().Name -eq 'User' } {
+ @{
+ Name = $pName
+ Expression = { [string[]]($pValue.Name) }.GetNewClosure()
+ }
+ break
+ }
+ default { $pName }
+ }
+ }
+ return $InputObject | Select-Object -Property $properties
+ }
+}
+
+$exportMembers = @("Get-SqlCredential", "ConvertTo-SerializableObject", "Get-LowlyDbaSqlServerAuthSpec")
+Export-ModuleMember -Function $exportMembers
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_listener.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_listener.ps1
new file mode 100644
index 00000000..dd377141
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_listener.ps1
@@ -0,0 +1,86 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ ag_name = @{type = 'str'; required = $true }
+ listener_name = @{type = 'str'; required = $true }
+ ip_address = @{type = 'str'; required = $false }
+ subnet_ip = @{type = 'str'; required = $false }
+ subnet_mask = @{type = 'str'; required = $false; default = '255.255.255.0' }
+ port = @{type = 'int'; required = $false; default = 1433 }
+ dhcp = @{type = 'bool'; required = $false; default = $false }
+ state = @{type = "str"; required = $false; default = "present"; choices = @("present", "absent") }
+ }
+}
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$agName = $module.Params.ag_name
+$listenerName = $module.Params.listener_name
+$subnetIp = $module.Params.subnet_ip
+$subnetMask = $module.Params.subnet_mask
+$ipAddress = $module.Params.ip_address
+$port = $module.Params.port
+$dhcp = $module.Params.dhcp
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{
+ "*:SqlInstance" = $sqlInstance
+ "*:SqlCredential" = $sqlCredential
+ "*:EnableException" = $true
+ "*:Confirm" = $false
+ "*:WhatIf" = $checkMode
+}
+
+try {
+ $existingListener = Get-DbaAgListener -AvailabilityGroup $agName -Listener $listenerName
+ if ($state -eq "present") {
+ if ($null -eq $existingListener) {
+ $listenerParams = @{
+ AvailabilityGroup = $agName
+ Name = $listenerName
+ Port = $port
+ Dhcp = $dhcp
+ SubnetMask = $subnetMask
+ }
+ if ($null -ne $ipAddress) {
+ $listenerParams.Add("IPAddress", $ipAddress)
+ }
+ if ($null -ne $subnetIp) {
+ $listenerParams.Add("SubnetIP", $subnetIp)
+ }
+ $output = Add-DbaAgListener @listenerParams
+ $module.Result.changed = $true
+ }
+ elseif ($existingListener.Port -ne $port) {
+ $output = Set-DbaAgListener -AvailabilityGroup $agName -Listener $listenerName -Port $port
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "absent") {
+ if ($null -ne $existingListener) {
+ $output = Remove-DbaAgListener -AvailabilityGroup $agName -Listener $listenerName
+ $module.Result.changed = $true
+ }
+ }
+
+ if ($output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Configuring availability group listener failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_listener.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_listener.py
new file mode 100644
index 00000000..12f0ec63
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_listener.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: ag_listener
+short_description: Configures an availability group listener
+description:
+ - Creates an Availability Group Listener for an existing availability group.
+version_added: 0.5.0
+options:
+ ag_name:
+ description:
+ - Name of the target availability group.
+ type: str
+ required: true
+ listener_name:
+ description:
+ - Name of the Listener to be configured.
+ type: str
+ required: true
+ ip_address:
+ description:
+ - IP address(es) of the listener. Comma separated if multiple.
+ type: str
+ required: false
+ subnet_ip:
+ description:
+ - Subnet IP address(es) of the listener. Comma separated if multiple.
+ type: str
+ required: false
+ subnet_mask:
+ description:
+ - Sets the subnet IP mask(s) of the availability group listener. Comma separated if multiple.
+ type: str
+ required: false
+ default: 255.255.255.0
+ port:
+ description:
+ - Sets the port number used to communicate with the availability group.
+ type: int
+ required: false
+ default: 1433
+ dhcp:
+ description:
+ - Indicates whether the listener uses DHCP.
+ type: bool
+ required: false
+ default: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create Availability Group
+ lowlydba.sqlserver.availability_group:
+ sql_instance: sql-01.myco.io
+ ag_name: AG_MyDatabase
+
+- name: Create AG Listener
+ lowlydba.sqlserver.ag_listener:
+ sql_instance_primary: sql-01.myco.io
+ ag_name: AG_MyDatabase
+ listener_name: aglMyDatabase
+ ip_address: 10.0.20.20,10.1.77.77
+ subnet_ip: 255.255.252.0
+ subnet_mask: 255.255.255.0
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Add-DbaAgListener) or C(Set-DbaAgListener) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_replica.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_replica.ps1
new file mode 100644
index 00000000..cd7d0930
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_replica.ps1
@@ -0,0 +1,193 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ sql_instance_replica = @{type = 'str'; required = $true }
+ sql_username_replica = @{type = 'str'; required = $false }
+ sql_password_replica = @{type = 'str'; required = $false; no_log = $true }
+ ag_name = @{type = 'str'; required = $true }
+ endpoint = @{type = 'str'; required = $false; default = 'hadr_endpoint' }
+ endpoint_url = @{type = 'str'; required = $false }
+ backup_priority = @{type = 'int'; required = $false; default = 50 }
+ failover_mode = @{
+ type = 'str'
+ required = $false
+ default = 'Manual'
+ choices = @('Manual', 'Automatic')
+ }
+ availability_mode = @{
+ type = 'str'
+ required = $false; default = 'AsynchronousCommit'
+ choices = @('SynchronousCommit', 'AsynchronousCommit')
+ }
+ seeding_mode = @{
+ type = 'str'
+ required = $false
+ default = 'Automatic'
+ choices = @('Manual', 'Automatic')
+ }
+ connection_mode_in_primary_role = @{
+ type = 'str'
+ required = $false
+ default = 'AllowAllConnections'
+ choices = @('AllowReadIntentConnectionsOnly', 'AllowAllConnections')
+ }
+ connection_mode_in_secondary_role = @{
+ type = 'str'
+ required = $false
+ default = 'AllowNoConnections'
+ choices = @('AllowNoConnections', 'AllowReadIntentConnectionsOnly', 'AllowAllConnections')
+ }
+ read_only_routing_connection_url = @{
+ type = 'str'
+ required = $false
+ }
+ read_only_routing_list = @{
+ type = 'str'
+ required = $false
+ }
+ cluster_type = @{
+ type = 'str'
+ required = $false
+ default = 'Wsfc'
+ choices = @('Wsfc', 'External', 'None')
+ }
+ configure_xe_session = @{ type = 'bool'; required = $false; default = $false }
+ session_timeout = @{ type = 'int'; required = $false }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+ required_together = @(
+ , @('sql_username_replica', 'sql_password_replica')
+ )
+}
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$readOnlyRoutingConnectionUrl = $module.params.read_only_routing_connection_url
+$readOnlyRoutingList = $module.Params.read_only_routing_list
+$failoverMode = $module.Params.failover_mode
+$seedingMode = $module.Params.seeding_mode
+$agName = $module.Params.ag_name
+$clusterType = $module.Params.cluster_type
+$availabilityMode = $module.Params.availability_mode
+$replicaSqlInstance = $module.Params.sql_instance_replica
+$connectionModeInPrimaryRole = $module.Params.connection_mode_in_primary_role
+$connectionModeInSecondaryRole = $module.Params.connection_mode_in_secondary_role
+$configureXESession = $module.Params.configure_xe_session
+$state = $module.Params.state
+[nullable[int]]$sessionTimeout = $module.Params.session_timeout
+$endpoint = $module.Params.endpoint
+$endpointUrl = $module.Params.endpoint_url
+$backupPriority = $module.Params.backup_priority
+
+if ($null -ne $module.Params.sql_username_replica) {
+ [securestring]$replicaSecPassword = ConvertTo-SecureString $Module.Params.sql_password_replica -AsPlainText -Force
+ [pscredential]$replicaSqlCredential = New-Object System.Management.Automation.PSCredential ($Module.Params.sql_username_replica, $replicaSecPassword)
+}
+if ($null -eq $replicaSqlCredential) {
+ $replicaSqlCredential = $sqlCredential
+}
+$module.Result.changed = $false
+$checkMode = $module.CheckMode
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+try {
+ $replicaInstance = Connect-DbaInstance -SqlInstance $replicaSqlInstance -SqlCredential $replicaSqlCredential
+ $allReplicas = Get-DbaAgReplica -SqlInstance $replicaSqlInstance -SqlCredential $replicaSqlCredential -AvailabilityGroup $agName
+ $existingReplica = $allReplicas | Where-Object Name -eq $replicaInstance.DomainInstanceName
+
+ if ($state -eq "present") {
+ $addReplicaSplat = @{
+ SqlInstance = $replicaSqlInstance
+ SqlCredential = $replicaSqlCredential
+ Endpoint = $endpoint
+ AvailabilityMode = $availabilityMode
+ FailoverMode = $failoverMode
+ BackupPriority = $backupPriority
+ ConnectionModeInPrimaryRole = $connectionModeInPrimaryRole
+ ConnectionModeInSecondaryRole = $connectionModeInSecondaryRole
+ SeedingMode = $seedingMode
+ ClusterType = $clusterType
+ }
+ if ($null -ne $readOnlyRoutingList) {
+ $addReplicaSplat.Add("ReadOnlyRoutingList", $readOnlyRoutingList)
+ }
+ if ($null -ne $readOnlyRoutingConnectionUrl) {
+ $addReplicaSplat.Add("ReadOnlyRoutingConnectionUrl", $readOnlyRoutingConnectionUrl)
+ }
+ if ($null -ne $endpointUrl) {
+ $addReplicaSplat.Add("EndpointUrl", $endpointUrl)
+ }
+ if ($configureXESession -eq $true) {
+ $addReplicaSplat.Add("ConfigureXESession", $true)
+ }
+ if ($null -ne $sessionTimeout) {
+ $addReplicaSplat.Add("SessionTimeout", $sessionTimeout)
+ }
+
+ if ($null -eq $existingReplica) {
+ $availabilityGroup = Get-DbaAvailabilityGroup -SqlInstance $sqlInstance -SqlCredential $sqlCredential -AvailabilityGroup $agName
+ $output = $availabilityGroup | Add-DbaAgReplica @addReplicaSplat
+ $module.Result.changed = $true
+ }
+ else {
+ $compareReplicaProperty = @(
+ 'AvailabilityMode'
+ 'FailoverMode'
+ 'BackupPriority'
+ 'ConnectionModeInPrimaryRole'
+ 'ConnectionModeInSecondaryRole'
+ 'SeedingMode'
+ 'SessionTimeout'
+ 'EndpointUrl'
+ )
+ $setReplicaSplat = @{}
+ $addReplicaSplat.GetEnumerator() | Where-Object Key -in $compareReplicaProperty | ForEach-Object { $setReplicaSplat.Add($_.Key, $_.Value) }
+ [string[]]$compareProperty = $setReplicaSplat.Keys
+ $replicaDiff = Compare-Object -ReferenceObject $setReplicaSplat -DifferenceObject $existingReplica -Property $compareProperty
+ $setReplicaSplat.Add("SqlInstance", $sqlInstance)
+ $setReplicaSplat.Add("SqlCredential", $sqlCredential)
+ $setReplicaSplat.Add("Replica", $existingReplica.Name)
+ $setReplicaSplat.Add("AvailabilityGroup", $agName)
+ if ($replicaDiff) {
+ $output = Set-DbaAgReplica @setReplicaSplat
+ $module.Result.changed = $true
+ }
+ }
+ }
+}
+catch {
+ $module.FailJson("Configuring Availability Group replica failed: $($_.Exception.Message)")
+}
+try {
+ if ($state -eq "absent") {
+ if ($null -ne $existingReplica) {
+ $output = $existingReplica | Remove-DbaAgReplica
+ $module.Result.changed = $true
+ }
+ }
+}
+catch {
+ $module.FailJson("Removing Availability Group replica failed: $($_.Exception.Message)")
+}
+
+try {
+ if ($output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error parsing results - operation likely completed: $($_.Exception.Message)")
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_replica.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_replica.py
new file mode 100644
index 00000000..d817d333
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/ag_replica.py
@@ -0,0 +1,147 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: ag_replica
+short_description: Configures an availability group replica
+description:
+ - Configures an availability group replica.
+version_added: 0.5.0
+options:
+ sql_instance_replica:
+ description:
+ - The SQL Server instance where of the replica to be configured.
+ type: str
+ required: true
+ sql_username_replica:
+ description:
+ - Username for SQL Authentication for the secondary replica.
+ type: str
+ required: false
+ sql_password_replica:
+ description:
+ - Password for SQL Authentication for the secondary replica.
+ type: str
+ required: false
+ ag_name:
+ description:
+ - Name of the Availability Group that will have the new replica joined to it.
+ type: str
+ required: true
+ endpoint:
+ description:
+ - By default, this command will attempt to find a DatabaseMirror endpoint. If one does not exist, it will create it.
+ type: str
+ required: false
+ default: 'hadr_endpoint'
+ endpoint_url:
+ description:
+ - By default, the property C(Fqdn) of C(Get-DbaEndpoint) is used as I(endpoint_url).
+ Use I(endpoint_url) if a different URL is required due to special network configurations.
+ type: str
+ required: false
+ backup_priority:
+ description:
+ - Sets the backup priority availability group replica.
+ type: int
+ default: 50
+ failover_mode:
+ description:
+ - Whether the replica have Automatic or Manual failover.
+ type: str
+ required: false
+ default: 'Manual'
+ choices: ['Automatic', 'Manual']
+ availability_mode:
+ description:
+ - Whether the replica should be Asynchronous or Synchronous.
+ type: str
+ required: false
+ default: 'AsynchronousCommit'
+ choices: ['AsynchronousCommit', 'SynchronousCommit']
+ seeding_mode:
+ description:
+ - Default seeding mode for the replica. Should remain as the default otherwise manual setup may be required.
+ type: str
+ required: false
+ default: 'Automatic'
+ choices: ['Automatic', 'Manual']
+ connection_mode_in_primary_role:
+ description:
+ - Which connections can be made to the database when it is in the primary role.
+ type: str
+ required: false
+ default: 'AllowAllConnections'
+ choices: ['AllowReadIntentConnectionsOnly','AllowAllConnections']
+ connection_mode_in_secondary_role:
+ description:
+ - Which connections can be made to the database when it is in the secondary role.
+ type: str
+ required: false
+ default: 'AllowNoConnections'
+ choices: ['AllowNoConnections','AllowReadIntentConnectionsOnly','AllowAllConnections']
+ read_only_routing_connection_url:
+ description:
+ - Sets the read only routing connection url for the availability replica.
+ type: str
+ required: false
+ read_only_routing_list:
+ description:
+ - Sets the read only routing ordered list of replica server names to use when redirecting read-only connections through this availability replica.
+ type: str
+ required: false
+ cluster_type:
+ description:
+ - Cluster type of the Availability Group. Only supported in SQL Server 2017 and above.
+ type: str
+ required: false
+ default: 'Wsfc'
+ choices: ['Wsfc', 'External', 'None']
+ configure_xe_session:
+ description:
+ - Configure the AlwaysOn_health extended events session to start automatically as the SSMS wizard would do.
+ type: bool
+ default: false
+ session_timeout:
+ description:
+ - How many seconds an availability replica waits for a ping response from a connected replica before considering the connection to have failed.
+ type: int
+ required: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create Availability Group
+ lowlydba.sqlserver.availability_group:
+ sql_instance: sql-01.myco.io
+ ag_name: AG_MyDatabase
+
+- name: Add a DR replica
+ lowlydba.sqlserver.ag_replica:
+ ag_name: 'AG_MyDatabase'
+ sql_instance_primary: sql-01.myco.io
+ sql_instance_replica: sql-02.myco.io
+ failover_mode: 'Manual'
+ availability_mode: 'Asynchronous'
+ seeding_mode: 'Automatic'
+ connection_mode_in_primary_role: 'AllowAllConnections'
+ connection_mode_in_secondary_role: 'AllowNoConnections'
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Add-DbaAgReplica) or C(Set-DbaAgReplica) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job.ps1
new file mode 100644
index 00000000..cf261f3e
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job.ps1
@@ -0,0 +1,133 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ job = @{type = 'str'; required = $true }
+ description = @{type = 'str'; required = $false; }
+ category = @{type = 'str'; required = $false; }
+ enabled = @{type = 'bool'; required = $false; default = $true }
+ owner_login = @{type = 'str'; required = $false; }
+ start_step_id = @{type = 'int'; required = $false; }
+ schedule = @{type = 'str'; required = $false; }
+ force = @{type = 'bool'; required = $false; default = $false }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$job = $module.Params.job
+$description = $module.Params.description
+$enabled = $module.Params.enabled
+$ownerLogin = $module.Params.owner_login
+$category = $module.Params.category
+$schedule = $module.Params.schedule
+[nullable[int]]$startStepId = $module.Params.start_step_id
+$force = $module.Params.force
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+# Configure Agent job
+try {
+ $existingJob = Get-DbaAgentJob -SqlInstance $sqlInstance -SqlCredential $sqlCredential -Job $job -EnableException
+ $output = $existingJob
+
+ if ($state -eq "absent") {
+ if ($null -ne $existingJob) {
+ $output = $existingJob | Remove-DbaAgentJob -Confirm:$false -WhatIf:$checkMode -EnableException
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "present") {
+ $jobParams = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Job = $job
+ WhatIf = $checkMode
+ Force = $force
+ EnableException = $true
+ }
+
+ if ($enabled -eq $false) {
+ $jobParams.add("Disabled", $true)
+ }
+
+ if ($null -ne $ownerLogin) {
+ $jobParams.add("OwnerLogin", $ownerLogin)
+ }
+
+ if ($null -ne $schedule) {
+ $jobParams.add("Schedule", $schedule)
+ }
+
+ if ($null -ne $category) {
+ $jobParams.add("Category", $category)
+ }
+
+ if ($null -ne $description) {
+ $jobParams.add("Description", $description)
+ }
+
+ if ($null -ne $startStepID) {
+ $jobParams.add("StartStepId", $startStepID)
+ }
+
+ # Create new job
+ if ($null -eq $existingJob) {
+ try {
+ $null = New-DbaAgentJob @jobParams
+ # Explicitly fetch the new job to make sure results don't suffer from SMO / Agent stale data bugs
+ $output = Get-DbaAgentJob -SqlInstance $sqlInstance -SqlCredential $sqlCredential -Job $job -EnableException
+ }
+ catch {
+ $module.FailJson("Failed creating new agent job: $($_.Exception.Message)", $_)
+ }
+ $module.Result.changed = $true
+ }
+ # Job exists
+ else {
+ # Need to serialize to prevent SMO auto refreshing
+ $old = ConvertTo-SerializableObject -InputObject $existingJob -UseDefaultProperty $false
+ if ($enabled -eq $true) {
+ $jobParams.Add("Enabled", $true)
+ }
+ $output = Set-DbaAgentJob @jobParams
+ if ($null -ne $output) {
+ $compareProperty = @(
+ "Category"
+ "Enabled"
+ "Name"
+ "OwnerLoginName"
+ "HasSchedule"
+ "Description"
+ "StartStepId"
+ )
+ $diff = Compare-Object -ReferenceObject $output -DifferenceObject $old -Property $compareProperty
+ if ($diff -or $checkMode) {
+ $module.Result.changed = $true
+ }
+ }
+ }
+ }
+
+ if ($output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error configuring SQL Agent job: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job.py
new file mode 100644
index 00000000..dbd3043f
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: agent_job
+short_description: Configures a SQL Agent job
+description:
+ - Configure a SQL Agent job, including which schedules and category it belongs to.
+version_added: 0.1.0
+options:
+ job:
+ description:
+ - The name of the target SQL Agent job.
+ type: str
+ required: true
+ description:
+ description:
+ - Description for the SQL Agent job.
+ type: str
+ required: false
+ category:
+ description:
+ - Category for the target SQL Agent job. Must already exist.
+ type: str
+ required: false
+ enabled:
+ description:
+ - Whether the SQL Agent job should be enabled or disabled.
+ type: bool
+ required: false
+ default: true
+ version_added: '0.4.0'
+ owner_login:
+ description:
+ - The owning login for the database. Will default to the current user if
+ the database is being created and none supplied.
+ type: str
+ required: false
+ start_step_id:
+ description:
+ - What step number the job should begin with when run.
+ type: int
+ required: false
+ schedule:
+ description:
+ - The name of the schedule the job should be associated with. Only one schedule per job is supported.
+ type: str
+ required: false
+ force:
+ description:
+ - If I(force=true), any job categories will be created if they don't exist already.
+ type: bool
+ default: false
+author: "John McCall (@lowlydba)"
+notes:
+ - On slower hardware, stale job component data may be returned (i.e., a previous or default job category).
+ Configuring each component (schedule, step, category, etc.) individually is recommended for this reason.
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create a job
+ lowlydba.sqlserver.agent_job:
+ sql_instance: sql-01.myco.io
+ job: MyJob
+ force: true
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(New-DbaAgentJob), C(Set-DbaAgentJob), or C(Remove-DbaAgentJob) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_category.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_category.ps1
new file mode 100644
index 00000000..1e5c033a
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_category.ps1
@@ -0,0 +1,64 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ category = @{type = 'str'; required = $true }
+ category_type = @{type = 'str'; required = $false; choices = @('LocalJob', 'MultiServerJob', 'None') }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$category = $module.Params.category
+$categoryType = $module.Params.category_type
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+try {
+ $agentJobCategorySplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Category = $category
+ EnableException = $true
+ }
+ if ($null -ne $categoryType) {
+ $agentJobCategorySplat.Add("CategoryType", $categoryType)
+ }
+ $existingCategory = Get-DbaAgentJobCategory @agentJobCategorySplat
+
+ if ($state -eq "present") {
+ # Create new job category
+ if ($null -eq $existingCategory) {
+ $output = New-DbaAgentJobCategory @agentJobCategorySplat -WhatIf:$checkMode
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "absent") {
+ if ($null -ne $existingCategory) {
+ $output = $existingCategory | Remove-DbaAgentJobCategory -WhatIf:$checkMode -EnableException -Confirm:$false
+ $module.Result.changed = $true
+ }
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error configuring SQL Agent job category.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_category.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_category.py
new file mode 100644
index 00000000..ce480c4c
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_category.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: agent_job_category
+short_description: Configures a SQL Agent job category
+description:
+ - Configures a SQL Agent job category. Creates if it does not exist, else does nothing.
+version_added: 0.1.0
+options:
+ category:
+ description:
+ - Name of the category.
+ required: true
+ type: str
+ category_type:
+ description:
+ - The type of category.
+ required: false
+ type: str
+ choices: ['LocalJob', 'MultiServerJob', 'None']
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create a maintenance job category
+ lowlydba.sqlserver.agent_job_category:
+ sql_instance: sql-01.myco.io
+ category: "Index Maintenance"
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(New-DbaAgentJobCategory) or C(Remove-DbaAgentJobCategory) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_schedule.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_schedule.ps1
new file mode 100644
index 00000000..6681dcff
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_schedule.ps1
@@ -0,0 +1,164 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ schedule = @{type = 'str'; required = $true }
+ job = @{type = 'str'; required = $true }
+ enabled = @{type = 'bool'; required = $false }
+ force = @{type = 'bool'; required = $false }
+ frequency_type = @{type = 'str'; required = $false
+ choices = @('Once', 'OneTime', 'Daily', 'Weekly', 'Monthly', 'MonthlyRelative', 'AgentStart', 'AutoStart', 'IdleComputer', 'OnIdle')
+ }
+ frequency_interval = @{type = 'str'; required = $false; }
+ frequency_subday_type = @{type = 'str'; required = $false; choices = @('Time', 'Seconds', 'Minutes', 'Hours') }
+ frequency_subday_interval = @{type = 'int'; required = $false }
+ frequency_relative_interval = @{type = 'str'; required = $false; choices = @('Unused', 'First', 'Second', 'Third', 'Fourth', 'Last') }
+ frequency_recurrence_factor = @{type = 'int'; required = $false }
+ start_date = @{type = 'str'; required = $false }
+ end_date = @{type = 'str'; required = $false }
+ start_time = @{type = 'str'; required = $false }
+ end_time = @{type = 'str'; required = $false }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$schedule = $module.Params.schedule
+$job = $module.Params.job
+[nullable[bool]]$enabled = $module.Params.enabled
+$force = $module.Params.force
+$frequencyType = $module.Params.frequency_type
+$frequencyInterval = $module.Params.frequency_interval
+$frequencySubdayType = $module.Params.frequency_subday_type
+[nullable[int]]$frequencySubdayInterval = $module.Params.frequency_subday_interval
+$frequencyRelativeInterval = $module.Params.frequency_relative_interval
+[nullable[int]]$frequencyRecurrenceFactor = $module.Params.frequency_recurrence_factor
+$startDate = $module.Params.start_date
+$endDate = $module.Params.end_date
+$startTime = $module.Params.start_time
+$endTime = $module.Params.end_time
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+$scheduleParams = @{
+ SqlInstance = $SqlInstance
+ SqlCredential = $sqlCredential
+ Force = $force
+ Schedule = $schedule
+}
+
+if ($enabled -eq $false) {
+ $scheduleParams.add("Disabled", $true)
+}
+if ($null -ne $job) {
+ $scheduleParams.add("Job", $job)
+}
+if ($null -ne $startDate) {
+ $scheduleParams.add("StartDate", $startDate)
+}
+if ($null -ne $endDate) {
+ $scheduleParams.add("EndDate", $endDate)
+}
+if ($null -ne $startTime) {
+ $scheduleParams.add("StartTime", $startTime)
+}
+if ($null -ne $endTime) {
+ $scheduleParams.add("EndTime", $endTime)
+}
+if ($null -ne $frequencyType) {
+ $scheduleParams.add("FrequencyType", $frequencyType)
+}
+if ($null -ne $frequencyInterval) {
+ $scheduleParams.add("FrequencyInterval", $frequencyInterval)
+}
+if ($null -ne $frequencySubdayType) {
+ $scheduleParams.add("FrequencySubdayType", $frequencySubdayType)
+}
+if ($null -ne $frequencySubdayInterval) {
+ $scheduleParams.add("FrequencySubdayInterval", $frequencySubdayInterval)
+}
+if ($null -ne $frequencyRelativeInterval) {
+ $scheduleParams.add("FrequencyRelativeInterval", $frequencyRelativeInterval)
+}
+if ($null -ne $frequencyRecurrenceFactor) {
+ $scheduleParams.add("FrequencyRecurrenceFactor", $frequencyRecurrenceFactor)
+}
+
+try {
+ $existingSchedule = Get-DbaAgentSchedule -SqlInstance $SqlInstance -SqlCredential $sqlCredential -Schedule $schedule
+ if ($state -eq "present") {
+ if ($enabled -eq $true) {
+ $scheduleParams.Add("Enabled", $true)
+ }
+ # Update schedule
+ if ($null -ne $existingSchedule) {
+ # Need to serialize to prevent SMO auto refreshing
+ $old = ConvertTo-SerializableObject -InputObject $existingSchedule -UseDefaultProperty $false
+ $output = Set-DbaAgentSchedule @scheduleParams
+ if ($null -ne $output) {
+ $compareProperty = @(
+ "ActiveEndDate"
+ "ActiveEndTimeOfDay"
+ "ActiveEndTimeOfDay"
+ "ActiveStartTimeOfDay"
+ "Description"
+ "FrequencyInterval"
+ "FrequencyRecurrenceFactor"
+ "FrequencyRelativeIntervals"
+ "FrequencySubDayInterval"
+ "FrequencySubDayTypes"
+ "FrequencyTypes"
+ "IsEnabled"
+ "ScheduleName"
+ )
+ $diff = Compare-Object -ReferenceObject $output -DifferenceObject $old -Property $compareProperty
+
+ # # Check if schedule was actually changed
+ # $modifiedSchedule = Get-DbaAgentSchedule -SqlInstance $SqlInstance -SqlCredential $sqlCredential -Schedule $ScheduleName -EnableException
+ # $scheduleDiff = Compare-Object -ReferenceObject $existingSchedule -DifferenceObject $modifiedSchedule
+ if ($diff -or $checkMode) {
+ $module.Result.changed = $true
+ }
+ }
+ }
+ # Create schedule
+ else {
+ $output = New-DbaAgentSchedule @scheduleParams
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "absent") {
+ # Nothing to remove
+ if ($null -eq $existingSchedule) {
+ $module.ExitJson()
+ }
+ # Remove schedule
+ else {
+ $output = $existingSchedule | Remove-DbaAgentSchedule -Force
+ $module.Result.changed = $true
+ }
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error configuring SQL Agent job schedule.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_schedule.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_schedule.py
new file mode 100644
index 00000000..008efca2
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_schedule.py
@@ -0,0 +1,142 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: agent_job_schedule
+short_description: Configures a SQL Agent job schedule
+description:
+ - Configures settings for an agent schedule that can be applied to one or more agent jobs.
+version_added: 0.1.0
+options:
+ schedule:
+ description:
+ - The name of the schedule.
+ type: str
+ required: true
+ job:
+ description:
+ - The name of the job that has the schedule.
+ - Schedules and jobs can also be associated via M(lowlydba.sqlserver.agent_job).
+ - See U(https://docs.dbatools.io/New-DbaAgentSchedule) for more detailed usage.
+ type: str
+ required: true
+ enabled:
+ description:
+ - Whether the schedule is enabled or disabled.
+ type: bool
+ required: false
+ force:
+ description:
+ - The force option will ignore some errors in the options and assume defaults.
+ - It will also remove the any present schedules with the same name for the specific job.
+ type: bool
+ frequency_type:
+ description:
+ - A value indicating when a job is to be executed.
+ - If I(force=true) the default will be C(Once).
+ type: str
+ required: false
+ choices: ['Once', 'OneTime', 'Daily', 'Weekly', 'Monthly', 'MonthlyRelative', 'AgentStart', 'AutoStart', 'IdleComputer', 'OnIdle']
+ frequency_interval:
+ description:
+ - The days that a job is executed.
+ - Allowed values for I(frequency_type=Daily) - C(EveryDay) or a number between C(1) and C(365) inclusive.
+ - >-
+ Allowed values for I(frequency_type=Weekly) -
+ C(Sunday), C(Monday), C(Tuesday), C(Wednesday), C(Thursday), C(Friday), C(Saturday),
+ C(Weekdays), C(Weekend) or C(EveryDay).
+ - Allowed values for I(frequency_type=Monthly) - Numbers C(1) through C(31) for each day of the month.
+ - If C(Weekdays), C(Weekend) or C(EveryDay) is used it overwrites any other value that has been passed before.
+ - If I(force=true) the default will be C(1).
+ type: str
+ required: false
+ frequency_subday_type:
+ description:
+ - Specifies the units for the subday I(frequency_interval).
+ type: str
+ required: false
+ choices: ['Time', 'Seconds', 'Minutes', 'Hours']
+ frequency_subday_interval:
+ description:
+ - The number of subday type periods to occur between each execution of a job.
+ type: int
+ required: false
+ frequency_relative_interval:
+ description:
+ - A job's occurrence of I(frequency_interval) in each month. If I(frequency_interval=32) (C(MonthlyRelative)).
+ type: str
+ required: false
+ choices: ['Unused', 'First', 'Second', 'Third', 'Fourth', 'Last']
+ frequency_recurrence_factor:
+ description:
+ - The number of weeks or months between the scheduled execution of a job.
+ - Required if I(frequency_type=Weekly), I(frequency_type=Monthly) or I(frequency_type=MonthlyRelative).
+ type: int
+ required: false
+ start_date:
+ description:
+ - The date on which execution of a job can begin.
+ - If I(force=true)the start date will be the current day.
+ - Format is C(YYYY-MM-DD).
+ type: str
+ required: false
+ end_date:
+ description:
+ - The date on which execution of a job can stop.
+ - If I(force=true) the end date will be C(9999-12-31).
+ - Format is C(YYYY-MM-DD).
+ type: str
+ required: false
+ start_time:
+ description:
+ - The time on any day to begin execution of a job. Format C(HHMMSS) (24 hour clock).
+ - If I(force=true) the start time will be C(00:00:00).
+ type: str
+ required: false
+ end_time:
+ description:
+ - The time on any day to end execution of a job. Format C(HHMMSS) (24 hour clock).
+ - If (force=true) the start time will be C(23:59:59).
+ type: str
+ required: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create a job schedule
+ lowlydba.sqlserver.agent_job_schedule:
+ sql_instance: sql-01.myco.io
+ schedule: DailySchedule
+ force: true
+ enabled: true
+ start_date: 2020-05-25 # May 25, 2020
+ end_date: 2099-05-25 # May 25, 2099
+ start_time: 010500 # 01:05:00 AM
+ end_time: 140030 # 02:00:30 PM
+ state: present
+
+- name: Create a job with schedule
+ lowlydba.sqlserver.agent_job:
+ sql_instance: sql-01.myco.io
+ job: MyJob
+ force: true
+ schedule: DailySchedule
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(New-DbaAgentJobSchedule) or C(Remove-DbaAgentJobSchedule) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_step.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_step.ps1
new file mode 100644
index 00000000..1bbbeb2e
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_step.ps1
@@ -0,0 +1,157 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ job = @{type = 'str'; required = $true }
+ step_id = @{type = 'int'; required = $false }
+ step_name = @{type = 'str'; required = $false }
+ database = @{type = 'str'; required = $false; default = 'master' }
+ subsystem = @{type = 'str'; required = $false; default = 'TransactSql'
+ choices = @('CmdExec', 'Distribution', 'LogReader', 'Merge', 'PowerShell', 'QueueReader', 'Snapshot', 'Ssis', 'TransactSql')
+ }
+ command = @{type = 'str'; required = $false }
+ on_success_action = @{type = 'str'; required = $false; default = 'QuitWithSuccess'
+ choices = @('QuitWithSuccess', 'QuitWithFailure', 'GoToNextStep', 'GoToStep')
+ }
+ on_success_step_id = @{type = 'int'; required = $false; default = 0 }
+ on_fail_action = @{type = 'str'; required = $false; default = 'QuitWithFailure'
+ choices = @('QuitWithSuccess', 'QuitWithFailure', 'GoToNextStep', 'GoToStep')
+ }
+ on_fail_step_id = @{type = 'int'; required = $false; default = 0 }
+ retry_attempts = @{type = 'int'; required = $false; default = 0 }
+ retry_interval = @{type = 'int'; required = $false; default = 0 }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+ required_together = @(
+ , @('retry_attempts', 'retry_interval')
+ )
+ required_one_of = @(
+ , @('step_id', 'step_name')
+ )
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$job = $module.Params.job
+$stepId = $module.Params.step_id
+$stepName = $module.Params.step_name
+$database = $module.Params.database
+$subsystem = $module.Params.subsystem
+$command = $module.Params.command
+$onSuccessAction = $module.Params.on_success_action
+[nullable[int]]$onSuccessStepId = $module.Params.on_success_step_id
+$onFailAction = $module.Params.on_fail_action
+[nullable[int]]$onFailStepId = $module.Params.on_fail_step_id
+[int]$retryAttempts = $module.Params.retry_attempts
+[nullable[int]]$retryInterval = $module.Params.retry_interval
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+# Configure Agent job step
+try {
+ $existingJobSteps = Get-DbaAgentJobStep -SqlInstance $SqlInstance -SqlCredential $sqlCredential -Job $job
+ $existingJobStep = $existingJobSteps | Where-Object Name -eq $stepName
+
+ if ($state -eq "absent") {
+ if ($null -eq $existingJobStep) {
+ # try fetching name by id if we only care about removing
+ $existingJobStep = $existingJobSteps | Where-Object Id -eq $stepId
+ $stepName = $existingJobStep.Name
+ }
+ if ($existingJobStep) {
+ $removeStepSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Job = $job
+ StepName = $stepName
+ }
+ $output = Remove-DbaAgentJobStep @removeStepSplat
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "present") {
+ if (!($stepName) -or !($stepId)) {
+ $module.FailJson("Step name must be specified when state=present.")
+ }
+ $jobStepParams = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Job = $job
+ StepName = $stepName
+ Database = $database
+ SubSystem = $subsystem
+ OnSuccessAction = $onSuccessAction
+ OnSuccessStepId = $onSuccessStepId
+ OnFailAction = $onFailAction
+ OnFailStepId = $onFailStepId
+ RetryAttempts = $retryAttempts
+ RetryInterval = $retryInterval
+ WhatIf = $checkMode
+ }
+ if ($null -ne $command) {
+ $jobStepParams.Add("Command", $command)
+ }
+
+ # No existing job step
+ if ($null -eq $existingJobStep) {
+ $jobStepParams.Add("StepId", $stepId)
+ $output = New-DbaAgentJobStep @jobStepParams
+ $module.Result.changed = $true
+ }
+ # Update existing
+ else {
+ # Validate step name isn't taken already - must be unique within a job
+ if ($existingJobStep.Name -eq $StepName -and $existingJobStep.ID -ne $stepId) {
+ $module.FailJson("There is already a step named '$StepName' for this job with an ID of $($existingJobStep.ID).")
+ }
+
+ # Reference by old name in case new name differs for step id
+ $jobStepParams.StepName = $existingJobStep.Name
+ $jobStepParams.Add("NewName", $StepName)
+
+ # Need to serialize to prevent SMO auto refreshing
+ $old = ConvertTo-SerializableObject -InputObject $existingJobStep -UseDefaultProperty $false
+ $output = Set-DbaAgentJobStep @jobStepParams
+ if ($null -ne $output) {
+ $compareProperty = @(
+ "Name"
+ "DatabaseName"
+ "Command"
+ "Subsystem"
+ "OnFailAction"
+ "OnFailActionStep"
+ "OnSuccessAction"
+ "OnSuccessActionStep"
+ "RetryAttempts"
+ "RetryInterval"
+ )
+ $diff = Compare-Object -ReferenceObject $output -DifferenceObject $old -Property $compareProperty
+ }
+ if ($diff -or $checkMode) {
+ $module.Result.changed = $true
+ }
+ }
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error configuring SQL Agent job step.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_step.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_step.py
new file mode 100644
index 00000000..1e3e9891
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/agent_job_step.py
@@ -0,0 +1,118 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: agent_job_step
+short_description: Configures a SQL Agent job step
+description:
+ - Configures a step for an agent job.
+version_added: 0.1.0
+options:
+ job:
+ description:
+ - The name of the job to which to add the step.
+ required: true
+ type: str
+ step_id:
+ description:
+ - The sequence identification number for the job step. Step identification numbers start at C(1) and increment without gaps.
+ - Required if I(state=present).
+ required: false
+ type: int
+ step_name:
+ description:
+ - The name of the step. Required if I(state=present).
+ required: false
+ type: str
+ database:
+ description:
+ - The name of the database in which to execute a Transact-SQL step.
+ required: false
+ type: str
+ default: 'master'
+ subsystem:
+ description:
+ - The subsystem used by the SQL Server Agent service to execute command.
+ required: false
+ type: str
+ default: 'TransactSql'
+ choices: ['CmdExec', 'Distribution', 'LogReader', 'Merge', 'PowerShell', 'QueueReader', 'Snapshot', 'Ssis', 'TransactSql']
+ command:
+ description:
+ - The commands to be executed by SQLServerAgent service through subsystem.
+ required: false
+ type: str
+ on_success_action:
+ description:
+ - The action to perform if the step succeeds.
+ required: false
+ type: str
+ default: 'QuitWithSuccess'
+ choices: ['QuitWithSuccess', 'QuitWithFailure', 'GoToNextStep', 'GoToStep']
+ on_success_step_id:
+ description:
+ - The ID of the step in this job to execute if the step succeeds and I(on_success_action=GoToStep).
+ required: false
+ type: int
+ default: 0
+ on_fail_action:
+ description:
+ - The action to perform if the step fails.
+ required: false
+ type: str
+ default: 'QuitWithFailure'
+ choices: ['QuitWithSuccess', 'QuitWithFailure', 'GoToNextStep', 'GoToStep']
+ on_fail_step_id:
+ description:
+ - The ID of the step in this job to execute if the step fails and I(on_fail_action=GoToStep).
+ required: false
+ type: int
+ default: 0
+ retry_attempts:
+ description:
+ - The number of retry attempts to use if this step fails. The default is C(0).
+ required: false
+ type: int
+ default: 0
+ retry_interval:
+ description:
+ - The amount of time in minutes between retry attempts.
+ required: false
+ type: int
+ default: 0
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create a job
+ lowlydba.sqlserver.agent_job:
+ sql_instance: sql-01.myco.io
+ job: MyJob
+ force: true
+
+- name: Create a job step
+ lowlydba.sqlserver.agent_job_step:
+ sql_instance: sql-01.myco.io
+ job: MyJob
+ step_name: Step1
+ step_id: 1
+ command: "TRUNCATE TABLE dbo.TestData;"
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(New-DbaAgentJobStep), C(Set-DbaAgentJobStep), or C(Remove-DbaAgentJobStep) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/availability_group.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/availability_group.ps1
new file mode 100644
index 00000000..177a6d10
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/availability_group.ps1
@@ -0,0 +1,235 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ sql_instance_secondary = @{type = "str"; required = $false }
+ sql_username_secondary = @{type = 'str'; required = $false }
+ sql_password_secondary = @{type = 'str'; required = $false; no_log = $true }
+ database = @{type = "str"; required = $false; aliases = @('database_name') }
+ ag_name = @{type = "str"; required = $true }
+ all_ags = @{type = "bool"; required = $false; }
+ shared_path = @{type = "str"; required = $false; default = $null }
+ dtc_support_enabled = @{type = "bool"; required = $false; }
+ basic_availability_group = @{type = "bool"; required = $false; }
+ database_health_trigger = @{type = "bool"; required = $false; }
+ is_distributed_ag = @{type = "bool"; required = $false; }
+ use_last_backup = @{type = "bool"; required = $false; }
+ healthcheck_timeout = @{type = "int"; required = $false; }
+ availability_mode = @{
+ type = "str"
+ required = $false
+ default = "SynchronousCommit"
+ choices = @("SynchronousCommit", "AsynchronousCommit")
+ }
+ failure_condition_level = @{
+ type = "str"
+ required = $false
+ choices = @(
+ "OnAnyQualifiedFailureCondition",
+ "OnCriticalServerErrors",
+ "OnModerateServerErrors",
+ "OnServerDown",
+ "OnServerUnresponsive"
+ )
+ }
+ failover_mode = @{
+ type = "str"
+ required = $false
+ default = "Automatic"
+ choices = @("Manual", "Automatic")
+ }
+ seeding_mode = @{
+ type = "str"
+ required = $false
+ default = "Manual"
+ choices = @("Manual", "Automatic")
+ }
+ automated_backup_preference = @{
+ type = "str"
+ required = $false
+ default = "Secondary"
+ choices = @("None", "Primary", "Secondary", "SecondaryOnly")
+ }
+ cluster_type = @{
+ type = "str"
+ required = $false
+ default = "Wsfc"
+ choices = @("Wsfc", "External", "None")
+ }
+ allow_null_backup = @{type = "bool"; required = $false }
+ force = @{type = "bool"; required = $false }
+ state = @{type = "str"; required = $false; default = "present"; choices = @("present", "absent") }
+ }
+ required_together = @(
+ , @('sql_username_secondary', 'sql_password_secondary')
+ )
+}
+
+# Setup var
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$ProgressPreference = "SilentlyContinue"
+
+# Var
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$secondary = $module.Params.sql_instance_secondary
+if ($null -ne $module.Params.sql_username_secondary) {
+ [securestring]$secondarySecPassword = ConvertTo-SecureString $Module.Params.sql_password_secondary -AsPlainText -Force
+ [pscredential]$secondarySqlCredential = New-Object System.Management.Automation.PSCredential ($Module.Params.sql_username_secondary, $secondarySecPassword)
+}
+$agName = $module.Params.ag_name
+$database = $module.Params.database
+$seedingMode = $module.Params.seeding_mode
+$sharedPath = $module.Params.shared_path
+$healthCheckTimeout = $module.Params.healthcheck_timeout
+$availabilityMode = $module.Params.availability_mode
+$failureConditionLevel = $module.Params.failure_condition_level
+$failoverMode = $module.Params.failover_mode
+$automatedBackupPreference = $module.Params.automated_backup_preference
+$clusterType = $module.Params.cluster_type
+$state = $module.Params.state
+[nullable[bool]]$all_ags = $module.Params.all_ags
+[nullable[bool]]$useLastBackup = $module.Params.use_last_backup
+[nullable[bool]]$dtcSupportEnabled = $module.Params.dtc_support_enabled
+[nullable[bool]]$basicAvailabilityGroup = $module.Params.basic_availability_group
+[nullable[bool]]$databaseHealthTrigger = $module.Params.database_health_trigger
+[nullable[bool]]$isDistributedAg = $module.Params.is_distributed_ag
+[nullable[bool]]$force = $module.Params.force
+[nullable[bool]]$allowNullBackup = $module.Params.allow_null_backup
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+try {
+ $existingAG = Get-DbaAvailabilityGroup -SqlInstance $sqlInstance -SqlCredential $sqlCredential -AvailabilityGroup $agName
+
+ if ($state -eq "present") {
+ $agSplat = @{
+ Primary = $sqlInstance
+ PrimarySqlCredential = $sqlCredential
+ Name = $agName
+ SeedingMode = $seedingMode
+ FailoverMode = $failoverMode
+ AvailabilityMode = $availabilityMode
+ AutomatedBackupPreference = $automatedBackupPreference
+ ClusterType = $clusterType
+ }
+ if ($null -ne $sharedPath -and $seedingMode -eq "Manual") {
+ $agSplat.Add("SharedPath", $sharedPath)
+ }
+ if ($useLastBackup -eq $true) {
+ $agSplat.Add("UseLastBackup", $useLastBackup)
+ }
+ if ($dtcSupportEnabled -eq $true) {
+ $agSplat.Add("DtcSupport", $dtcSupportEnabled)
+ }
+ if ($basicAvailabilityGroup -eq $true) {
+ $agSplat.Add("Basic", $basicAvailabilityGroup)
+ }
+ if ($databaseHealthTrigger -eq $true) {
+ $agSplat.Add("DatabaseHealthTrigger", $databaseHealthTrigger)
+ }
+ if ($null -ne $healthCheckTimeout) {
+ $agSplat.Add("HealthCheckTimeout", $healthCheckTimeout)
+ }
+ if ($null -ne $failureConditionLevel) {
+ $agSplat.Add("FailureConditionLevel", $failureConditionLevel)
+ }
+ if ($null -ne $database) {
+ $agSplat.Add("Database", $database)
+ }
+ if ($null -ne $secondary) {
+ $agSplat.Add("Secondary", $secondary)
+ }
+ if ($null -ne $secondarySqlCredential) {
+ $agSplat.Add("SecondarySqlCredential", $secondarySqlCredential)
+ }
+ if ($force -eq $true) {
+ $agSplat.Add("Force", $force)
+ }
+
+ # Create the AG with initial replica(s)
+ if ($null -eq $existingAG) {
+ # Full backup requirement for new AG via automatic seeding
+ if ($seedingMode -eq "automatic" -and $null -ne $database) {
+ $dbBackup = Get-DbaLastBackup -SqlInstance $sqlInstance -SqlCredential $sqlCredential -Database $database
+ if ($null -eq $dbBackup.LastFullBackup -and $allowNullBackup -eq $true) {
+ $backupSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ FilePath = "NUL"
+ Type = "Full"
+ }
+ $null = Backup-DbaDatabase @backupSplat
+ }
+ }
+ $output = New-DbaAvailabilityGroup @agSplat
+ $module.Result.changed = $true
+ }
+ # Configure existing AG
+ else {
+ $setAgSplat = @{
+ AutomatedBackupPreference = $automatedBackupPreference
+ ClusterType = $clusterType
+ }
+ if ($all_ags -eq $true) {
+ $setAgSplat.Add("AllAvailabilityGroups", $all_ags)
+ }
+ if ($dtcSupportEnabled -eq $true) {
+ $setAgSplat.Add("DtcSupportEnabled", $dtcSupportEnabled)
+ }
+ if ($basicAvailabilityGroup -eq $true) {
+ $setAgSplat.Add("BasicAvailabilityGroup", $basicAvailabilityGroup)
+ }
+ if ($databaseHealthTrigger -eq $true) {
+ $setAgSplat.Add("DatabaseHealthTrigger", $databaseHealthTrigger)
+ }
+ if ($null -ne $failureConditionLevel) {
+ $setAgSplat.Add("FailureConditionLevel", $failureConditionLevel)
+ }
+ if ($null -ne $healthCheckTimeout) {
+ $setAgSplat.Add("HealthCheckTimeout", $healthCheckTimeout)
+ }
+ if ($isDistributedAg -eq $true) {
+ $setAgSplat.Add("IsDistributedAvailabilityGroup", $isDistributedAg)
+ }
+ $compareProperty = ($existingAG.Properties | Where-Object Name -in $setAgSplat.Keys).Name
+ $agDiff = Compare-Object -ReferenceObject $existingAG -DifferenceObject $setAgSplat -Property $compareProperty
+ if ($null -ne $agDiff) {
+ $output = $existingAG | Set-DbaAvailabilityGroup @setAgSplat
+ $module.Result.changed = $true
+ }
+ }
+ }
+ elseif ($state -eq "absent") {
+ if ($null -ne $existingAG) {
+ if ($all_ags -eq $true) {
+ $existingAG | Remove-DbaAvailabilityGroup -AllAvailabilityGroups
+ }
+ else {
+ $existingAG | Remove-DbaAvailabilityGroup
+ }
+ $module.Result.changed = $true
+ }
+ }
+
+ if ($output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Configuring Availability Group failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/availability_group.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/availability_group.py
new file mode 100644
index 00000000..15f78191
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/availability_group.py
@@ -0,0 +1,157 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: availability_group
+short_description: Configures availability group(s)
+description:
+ - Configures SQL Server Availability Group(s) with up to one replica.
+version_added: 0.4.0
+options:
+ sql_instance_secondary:
+ description:
+ - The secondary SQL Server instance for the new Availability Group.
+ type: str
+ required: false
+ sql_username_secondary:
+ description:
+ - Username for SQL Authentication for the secondary replica.
+ type: str
+ required: false
+ sql_password_secondary:
+ description:
+ - Password for SQL Authentication for the secondary replica.
+ type: str
+ required: false
+ database:
+ description:
+ - Name of the database to create the Availability Group for.
+ type: str
+ required: false
+ aliases:
+ - database_name
+ ag_name:
+ description:
+ - Name of the Availability Group.
+ type: str
+ required: true
+ all_ags:
+ description:
+ - Apply changes to all availability groups on the instance. Only used for configuring existing availability groups.
+ type: bool
+ required: false
+ shared_path:
+ description:
+ - The network share where the backups will be backed up and restored from.
+ type: str
+ required: false
+ dtc_support_enabled:
+ description:
+ - Enables Dtc support.
+ type: bool
+ required: false
+ basic_availability_group:
+ description:
+ - Indicates whether the availability group is Basic Availability Group.
+ type: bool
+ required: false
+ database_health_trigger:
+ description:
+ - Indicates whether the availability group triggers the database health.
+ type: bool
+ required: false
+ is_distributed_ag:
+ description:
+ - Indicates whether the availability group is distributed.
+ type: bool
+ required: false
+ healthcheck_timeout:
+ description:
+ - This setting used to specify the length of time, in milliseconds,
+ that the SQL Server resource DLL should wait for information returned by the C(sp_server_diagnostics)
+ stored procedure before reporting the Always On Failover Cluster Instance (FCI) as unresponsive.
+ - Changes that are made to the timeout settings are effective immediately and do not require a restart of the SQL Server resource.
+ type: int
+ required: false
+ failure_condition_level:
+ description:
+ - Specifies the different conditions that can trigger an automatic failover in Availability Group.
+ type: str
+ required: false
+ choices: ['OnAnyQualifiedFailureCondition', 'OnCriticalServerErrors', 'OnModerateServerErrors', 'OnServerDown', 'OnServerUnresponsive']
+ cluster_type:
+ description:
+ - Cluster type of the Availability Group. Only supported in SQL Server 2017 and above.
+ type: str
+ required: false
+ default: 'Wsfc'
+ choices: ['Wsfc', 'External', 'None']
+ failover_mode:
+ description:
+ - Whether the replica have Automatic or Manual failover.
+ type: str
+ required: false
+ default: 'Automatic'
+ choices: ['Automatic', 'Manual']
+ availability_mode:
+ description:
+ - Whether the replica should be Asynchronous or Synchronous.
+ - Only used in creating a new availability group.
+ type: str
+ required: false
+ default: 'SynchronousCommit'
+ choices: ['AsynchronousCommit', 'SynchronousCommit']
+ seeding_mode:
+ description:
+ - Default seeding mode for the replica. Should remain as the default otherwise manual setup may be required.
+ type: str
+ required: false
+ default: 'Manual'
+ choices: ['Automatic', 'Manual']
+ automated_backup_preference:
+ description:
+ - How to handle backup requests by default.
+ type: str
+ required: false
+ default: 'Secondary'
+ choices: ['None', 'Primary', 'Secondary', 'SecondaryOnly']
+ allow_null_backup:
+ description:
+ - Allow taking a full backup to C(NULL) if one does not exist and I(seeding_mode=Automatic).
+ type: bool
+ required: false
+ force:
+ description:
+ - Drop and recreate the database on remote servers using fresh backup.
+ type: bool
+ use_last_backup:
+ description:
+ - Use the last full and log backup of database. A log backup must be the last backup.
+ type: bool
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create Availability Group
+ lowlydba.sqlserver.availability_group:
+ sql_instance: sql-01.myco.io
+ ag_name: AG_MyDatabase
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(New-DbaAvailabilityGroup) or C(Set-DbaAvailabilityGroup) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/backup.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/backup.ps1
new file mode 100644
index 00000000..163d4503
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/backup.ps1
@@ -0,0 +1,138 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ database = @{type = 'str'; required = $true }
+ path = @{type = 'str'; required = $false }
+ file_path = @{type = 'str'; required = $false }
+ increment_prefix = @{type = 'bool'; required = $false; default = $false }
+ replace_in_name = @{type = 'bool'; required = $false; default = $false }
+ copy_only = @{type = 'bool'; required = $false; default = $false }
+ type = @{type = 'str'; required = $false; default = 'database'; choices = @('full', 'log', 'differential', 'diff', 'database') }
+ timestamp_format = @{type = 'str'; required = $false }
+ encryption_certificate = @{type = 'str'; required = $false }
+ encryption_algorithm = @{type = 'str'; required = $false; choices = @('AES128', 'AES192', 'AES256', 'TRIPLEDES') }
+ create_folder = @{type = 'bool'; required = $false; default = $false }
+ file_count = @{type = 'int'; required = $false; default = 0 }
+ compress = @{type = 'bool'; required = $false; default = $false }
+ checksum = @{type = 'bool'; required = $false; default = $false }
+ verify = @{type = 'bool'; required = $false; default = $false }
+ no_recovery = @{type = 'bool'; required = $false; default = $false }
+ build_path = @{type = 'bool'; required = $false; default = $false }
+ max_transfer_size = @{type = 'int'; required = $false; default = 0 }
+ with_format = @{type = 'bool'; required = $false; default = $false }
+ initialize = @{type = 'bool'; required = $false; default = $false }
+ ignore_file_checks = @{type = 'bool'; required = $false; default = $false }
+ block_size = @{type = 'str'; required = $false; choices = @('0.5kb', '1kb', '2kb', '4kb', '8kb', '16kb', '32kb', '64kb') }
+ buffer_count = @{type = 'int'; required = $false; default = 0 }
+ azure_base_url = @{type = 'str'; required = $false }
+ azure_credential = @{type = 'str'; required = $false }
+ }
+ mutually_exclusive = @(
+ , @('path', 'azure_base_url')
+ )
+ required_together = @(
+ , @('encryption_algorithm', 'encryption_certificate')
+ )
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$path = $module.Params.path
+$filePath = $module.Params.file_path
+$incrementPrefix = $module.Params.increment_prefix
+$replaceInName = $module.Params.replace_in_name
+$copyOnly = $module.Params.copy_only
+$type = $module.Params.type
+$createFolder = $module.Params.create_folder
+$fileCount = $module.Params.file_count
+$compressBackup = $module.Params.compress_backup
+$checkSum = $module.Params.checksum
+$verify = $module.Params.verify
+$maxTransferSize = $module.Params.max_transfer_size
+$blockSize = $module.Params.block_size
+$bufferCount = $module.Params.buffer_count
+$noRecovery = $module.Params.no_recovery
+$buildPath = $module.Params.build_path
+$withFormat = $module.Params.with_format
+$initialize = $module.Params.initialize
+$timestampFormat = $module.Params.timestamp_format
+$ignoreFileChecks = $module.Params.ignore_file_checks
+$encryptionAlgorithm = $module.Params.encryption_algorithm
+$encryptionCertificate = $modules.Params.encryption_certificate
+$azureBaseUrl = $modules.Params.azure_base_url
+$azureCredential = $modules.Param.azure_credential
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+try {
+ $backupSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ IncrementPrefix = $incrementPrefix
+ ReplaceInName = $replaceInName
+ CopyOnly = $copyOnly
+ Type = $type
+ CreateFolder = $createFolder
+ FileCount = $fileCount
+ CompressBackup = $compressBackup
+ Checksum = $checkSum
+ Verify = $verify
+ MaxTransferSize = $maxTransferSize
+ BufferCount = $bufferCount
+ NoRecovery = $noRecovery
+ BuildPath = $buildPath
+ WithFormat = $withFormat
+ Initialize = $initialize
+ IgnoreFileChecks = $ignoreFileChecks
+ }
+ if ($null -ne $path) {
+ $backupSplat.Add("Path", $path)
+ }
+ if ($null -ne $filePath) {
+ $backupSplat.Add("FilePath", $filePath)
+ }
+ if ($null -ne $blockSize) {
+ $backupSplat.Add("BlockSize", ($blockSize / 1))
+ }
+ if ($null -ne $timestampFormat) {
+ $backupSplat.Add("TimestampFormat", $timestampFormat)
+ }
+ if ($null -ne $encryptionAlgorithm) {
+ $backupSplat.Add("EncryptionAlgorithm", $encryptionAlgorithm)
+ }
+ if ($null -ne $encryptionCertificate) {
+ $backupSplat.Add("EncryptionCertificate", $encryptionCertificate)
+ }
+ if ($null -ne $azureBaseUrl) {
+ $backupSplat.Add("AzureBaseURL", $azureBaseUrl)
+ }
+ if ($null -ne $azureCredential) {
+ $backupSplat.Add("AzureCredential", $azureCredential)
+ }
+ $output = Backup-DbaDatabase @backupSplat
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ $module.Result.changed = $true
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error backing up database: $($_.Exception.Message).", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/backup.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/backup.py
new file mode 100644
index 00000000..962b0cfc
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/backup.py
@@ -0,0 +1,197 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: backup
+short_description: Performs a backup operation
+description:
+ - Performs any type of database backup operation.
+version_added: 0.8.0
+options:
+ database:
+ description:
+ - The database to process.
+ type: str
+ required: true
+ path:
+ description:
+ - Path in which to place the backup files.
+ - If not specified, the backups will be placed in the default backup location for SqlInstance.
+ type: str
+ required: false
+ file_path:
+ description:
+ - The name of the file to backup to.
+ - If no name is specified then the backup files will be named C(DatabaseName_yyyyMMddHHmm) (i.e. C(Database1_201714022131))
+ type: str
+ required: false
+ increment_prefix:
+ description:
+ - If set, this will prefix backup files with an incrementing integer (ie; C(1-), C(2-)).
+ - Using this has been alleged to improved restore times on some Azure based SQL Database platforms.
+ type: bool
+ required: false
+ default: false
+ replace_in_name:
+ description:
+ - If set, the following list of strings will be replaced in the FilePath and Path strings.
+ C(instancename) - will be replaced with the instance Name
+ C(servername) - will be replaced with the server name
+ C(dbname) - will be replaced with the database name
+ C(timestamp) - will be replaced with the timestamp (either the default, or the format provided)
+ C(backuptype) - will be replaced with C(Full), C(Log), or C(Differential) as appropriate
+ type: bool
+ required: false
+ default: false
+ copy_only:
+ description:
+ - The backup will be CopyOnly.
+ type: bool
+ required: false
+ default: false
+ type:
+ description:
+ - The type of backup to perform.
+ type: str
+ required: false
+ default: 'database'
+ choices: ['full', 'log', 'differential', 'diff', 'database']
+ create_folder:
+ description:
+ - If set, database is backed up to its own subfolder within the path.
+ type: bool
+ required: false
+ default: false
+ file_count:
+ description:
+ - The number of striped files to create the backup with.
+ type: int
+ required: false
+ default: 0
+ compress:
+ description:
+ - If set, use compression when creating the backup if it is supported by the version and edition.
+ type: bool
+ required: false
+ default: false
+ checksum:
+ description:
+ - If set, the backup checksum will be calculated.
+ type: bool
+ required: false
+ default: false
+ verify:
+ description:
+ - If set, the backup will be verified via C(RESTORE VERIFYONLY)
+ type: bool
+ required: false
+ default: false
+ max_transfer_size:
+ description:
+ - Sets the size of the unit of transfer. Values must be a multiple of 64kb.
+ type: int
+ required: false
+ default: 0
+ block_size:
+ description:
+ - Specifies block size to use.
+ type: str
+ required: false
+ choices: ['0.5kb','1kb','2kb','4kb','8kb','16kb','32kb','64kb']
+ buffer_count:
+ description:
+ - Number of I/O buffers to use.
+ type: int
+ required: false
+ default: 0
+ azure_base_url:
+ description:
+ - The URL to the base container of an Azure Storage account to write backups to.
+ type: str
+ required: false
+ azure_credential:
+ description:
+ - The name of the credential on the SQL instance that can write to the I(azure_base_url),
+ only needed if using Storage access keys If using SAS credentials, the command will look for a credential with a name matching the I(azure_base_url).
+ type: str
+ required: false
+ no_recovery:
+ description:
+ - If set, performs a tail log backup.
+ type: bool
+ required: false
+ default: false
+ build_path:
+ description:
+ - By default this command will not attempt to create missing paths, this switch will change the behaviour so that it will.
+ type: bool
+ required: false
+ default: false
+ with_format:
+ description:
+ - Formats the media as the first step of the backup operation.
+ type: bool
+ required: false
+ default: false
+ initialize:
+ description:
+ - Initializes the media as part of the backup operation.
+ type: bool
+ required: false
+ default: false
+ timestamp_format:
+ description:
+ - By default the command timestamps backups using the format C(yyyyMMddHHmm). Using this option this can be overridden.
+ type: str
+ required: false
+ ignore_file_checks:
+ description:
+ - If set, stops the function from checking path validity.
+ type: bool
+ required: false
+ default: false
+ encryption_algorithm:
+ description:
+ - Specifies the Encryption Algorithm to used.
+ type: str
+ required: false
+ choices: ['AES128','AES192','AES256','TRIPLEDES']
+ encryption_certificate:
+ description:
+ - The name of the certificate to be used to encrypt the backups.
+ type: str
+ required: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Create striped full database backup in default dir
+ lowlydba.sqlserver.backup:
+ sql_instance: sql-01.myco.io
+ database: LowlyDB
+ type: full
+ file_count: 8
+
+- name: Create t-log backup
+ lowlydba.sqlserver.backup:
+ sql_instance: sql-01.myco.io
+ database: LowlyDB
+ type: log
+'''
+
+RETURN = r'''
+data:
+ description: Modified output from the C(Backup-DbaDatabase) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/credential.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/credential.ps1
new file mode 100644
index 00000000..29631b11
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/credential.ps1
@@ -0,0 +1,117 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ identity = @{type = 'str'; required = $true }
+ name = @{type = 'str'; required = $false }
+ password = @{type = 'str'; required = $false; no_log = $true }
+ mapped_class_type = @{type = 'str'; required = $false; choices = @('CryptographicProvider', 'None') }
+ provider_name = @{type = 'str'; required = $false }
+ force = @{type = 'bool'; required = $false; default = $false }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$identity = $module.Params.identity
+$name = $module.Params.name
+if ($null -ne $module.Params.password) {
+ $secure_password = ConvertTo-SecureString -String $module.Params.password -AsPlainText -Force
+}
+$mapped_class_type = $module.Params.mapped_class_type
+$provider_name = $module.Params.provider_name
+$state = $module.Params.state
+$force = $module.Params.force
+$checkMode = $module.CheckMode
+
+$module.Result.changed = $false
+
+try {
+ $getCredendtialSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Identity = $identity
+ EnableException = $true
+ }
+ $existingCredential = Get-DbaCredential @getCredendtialSplat
+
+ if ($state -eq "absent") {
+ # Remove credential if it exists
+ if ($null -ne $existingCredential) {
+ try {
+ $removeCredentialSplat = @{
+ EnableException = $true
+ WhatIf = $checkMode
+ Confirm = $false
+ }
+ $output = $existingCredential | Remove-DbaCredential @removeCredentialSplat
+ $module.Result.changed = $true
+ }
+ catch {
+ $module.FailJson("Removing credential failed: $($_.Exception.Message)", $_)
+ }
+ }
+ }
+ elseif ($state -eq "present") {
+ # Create credential
+ if (($null -ne $existingCredential -and $force -eq $true) -or $null -eq $existingCredential) {
+ try {
+ $newCredentialSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Identity = $identity
+ EnableException = $true
+ WhatIf = $checkMode
+ Force = $force
+ Confirm = $false
+ }
+ if ($null -ne $name) {
+ $newCredentialSplat.Add("Name", $name)
+ }
+ if ($null -ne $secure_password) {
+ $newCredentialSplat.Add("SecurePassword", $secure_password)
+ }
+ if ($null -ne $mapped_class_type) {
+ $newCredentialSplat.Add("MappedClassType", $mapped_class_type)
+ }
+ if ($null -ne $provider_name) {
+ $newCredentialSplat.Add("ProviderName", $provider_name)
+ }
+ $output = New-DbaCredential @newCredentialSplat
+ $module.result.changed = $true
+ }
+ catch {
+ $module.FailJson("Creating credential failed: $($_.Exception.Message)", $_)
+ }
+ }
+ # Return existing credential if nothing is changed
+ elseif ($null -ne $existingCredential) {
+ $output = $existingCredential
+ }
+ }
+ try {
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+ }
+ catch {
+ $module.FailJson("Failure: $($_.Exception.Message)", $_)
+ }
+}
+catch {
+ $module.FailJson("Configuring credential failed: $($_.Exception.Message) ; $getCredendtialSplat", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/credential.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/credential.py
new file mode 100644
index 00000000..e83b8ed3
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/credential.py
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: credential
+short_description: Configures a credential on a SQL server
+description:
+ - Creates, replaces, or removes a credential on a SQL server.
+version_added: 1.3.0
+options:
+ identity:
+ description:
+ - The Credential Identity.
+ type: str
+ required: true
+ name:
+ description:
+ - The Credential name.
+ type: str
+ required: false
+ password:
+ description:
+ - Password used to authenticate the Credential Identity.
+ type: str
+ required: false
+ mapped_class_type:
+ description:
+ - Sets the class associated with the credential.
+ type: str
+ required: false
+ choices: ['CryptographicProvider','None']
+ provider_name:
+ description:
+ - Specifies the cryptographic provider name for the Enterprise Key Management Provider.
+ type: str
+ required: false
+ force:
+ description:
+ - If this switch is enabled, the existing credential will be dropped and recreated.
+ type: bool
+ default: false
+author:
+ - "Joe Krilov (@Joey40)"
+ - "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create a credential with a password
+ lowlydba.sqlserver.credential:
+ sql_instance: sql-01.myco.io
+ identity: ad\\user
+ name: MyCredential
+ password : <Password>
+
+- name: Replace an existing credential
+ lowlydba.sqlserver.credential:
+ sql_instance: sql-01.myco.io
+ identity: MyIdentity
+ force: true
+
+- name: Create a credential using a SAS token for a backup URL
+ lowlydba.sqlserver.credential:
+ sql_instance: sql-01.myco.io
+ identity: SHARED ACCESS SIGNATURE
+ name: https://<azure storage account name>.blob.core.windows.net/<blob container>
+ password : <Shared Access Token>
+
+- name: Remove a credential
+ lowlydba.sqlserver.credential:
+ sql_instance: sql-01.myco.io
+ identity: MyIdentity
+ state: absent
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(New-DbaDbCredential), C(Get-DbaDbCredential), or C(Remove-DbaDbCredential) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/database.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/database.ps1
new file mode 100644
index 00000000..4c3e3c9d
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/database.ps1
@@ -0,0 +1,242 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ database = @{type = 'str'; required = $true }
+ recovery_model = @{type = 'str'; required = $false; choices = @('Full', 'Simple', 'BulkLogged') }
+ data_file_path = @{type = 'str'; required = $false }
+ log_file_path = @{type = 'str'; required = $false }
+ owner = @{type = 'str'; required = $false; }
+ maxdop = @{type = 'int'; required = $false; }
+ secondary_maxdop = @{type = 'int'; required = $false; }
+ compatibility = @{type = 'str'; required = $false; }
+ rcsi = @{type = 'bool'; required = $false; }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$recoveryModel = $module.Params.recovery_model
+$dataFilePath = $module.Params.data_file_path
+$logFilePath = $module.Params.log_file_path
+$owner = $module.Params.owner
+$compatibility = $module.Params.compatibility
+[nullable[bool]]$rcsiEnabled = $module.Params.rcsi
+[nullable[int]]$maxDop = $module.Params.maxdop
+[nullable[int]]$secondaryMaxDop = $module.Params.secondary_maxdop
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+
+try {
+ # Get database status
+ try {
+ $server = Connect-DbaInstance -SqlInstance $sqlInstance -SqlCredential $sqlCredential
+ $getDatabaseSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ OnlyAccessible = $true
+ ExcludeSystem = $true
+ EnableException = $true
+ }
+ $existingDatabase = Get-DbaDatabase @getDatabaseSplat
+ $output = $existingDatabase
+ }
+ catch {
+ $module.FailJson("Error checking database status.", $_.Exception.Message)
+ }
+
+ if ($state -eq "absent") {
+ if ($null -ne $existingDatabase) {
+ $existingDatabase | Remove-DbaDatabase -WhatIf:$checkMode -EnableException -Confirm:$false
+ $module.Result.changed = $true
+ }
+ $module.ExitJson()
+ }
+ elseif ($state -eq "present") {
+ # Create database
+ if ($null -eq $existingDatabase) {
+ try {
+ $newDbParams = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ WhatIf = $checkMode
+ EnableException = $true
+ }
+ if ($null -ne $dataFilePath) {
+ $newDbParams.Add("DataFilePath", $dataFilePath)
+ }
+ if ($null -ne $logFilePath) {
+ $newDbParams.Add("LogFilePath", $logFilePath)
+ }
+ if ($null -ne $owner) {
+ $newDbParams.Add("Owner", $owner)
+ }
+ $output = New-DbaDatabase @newDbParams
+ $module.Result.changed = $true
+ }
+ catch {
+ $module.FailJson("Creating database [$database] failed.", $_)
+ }
+ }
+ # Set Owner
+ elseif ($null -ne $owner) {
+ try {
+ if ($existingDatabase.Owner -ne $owner) {
+ $setDbParams = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ TargetLogin = $owner
+ WhatIf = $checkMode
+ EnableException = $true
+ }
+ $null = Set-DbaDbOwner @setDbParams
+ $output = Get-DbaDatabase @getDatabaseSplat
+ $module.Result.changed = $true
+ }
+ }
+ catch {
+ $module.FailJson("Setting database owner for [$database] failed.", $_)
+ }
+ }
+
+ # Add non-standard fields to output
+ if ($null -ne $output) {
+ # Secondary MaxDop
+ [int]$existingSecondaryMaxDop = $server.Databases[$database].SecondaryMaxDop
+ $output | Add-Member -MemberType NoteProperty -Name "SecondaryMaxDop" -Value $existingSecondaryMaxDop
+ $output.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Add("SecondaryMaxDop")
+
+ # MaxDop (exists, but is not in default display)
+ $existingMaxDop = $server.Databases[$database].MaxDop
+ $output.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Add("MaxDop")
+
+ # RCSI
+ $existingRCSI = $server.Databases[$database].IsReadCommittedSnapshotOn
+ $output | Add-Member -MemberType NoteProperty -Name "RCSI" -Value $existingRCSI
+ $output.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Add("RCSI")
+ }
+
+ # Recovery Model
+ if ($null -ne $recoveryModel) {
+ try {
+ if ($recoveryModel -ne $output.RecoveryModel) {
+ $recoveryModelSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ RecoveryModel = $recoveryModel
+ WhatIf = $checkMode
+ EnableException = $true
+ Confirm = $false
+ }
+ $null = Set-DbaDbRecoveryModel @recoveryModelSplat
+ $output.RecoveryModel = $recoveryModel
+ $module.Result.changed = $true
+ }
+ }
+ catch {
+ $module.FailJson("Setting recovery model for [$database] failed.", $_)
+ }
+ }
+
+ # Compatibility Mode
+ if ($null -ne $compatibility) {
+ try {
+ $existingCompatibility = $output.Compatibility
+ if ($compatibility -ne $existingCompatibility) {
+ $compatSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ Compatibility = $compatibility
+ WhatIf = $checkMode
+ EnableException = $true
+ }
+ $null = Set-DbaDbCompatibility @compatSplat
+ $output.Compatibility = $compatibility
+ $module.Result.changed = $true
+ }
+ }
+ catch {
+ $module.FailJson("Setting Compatibility for [$database] failed.", $_)
+ }
+ }
+
+ # RCSI
+ if ($null -ne $rcsiEnabled) {
+ try {
+ if ($rcsiEnabled -ne $existingRCSI) {
+ if (-not $checkMode) {
+ $server.Databases[$database].IsReadCommittedSnapshotOn = $rcsiEnabled
+ $server.Databases[$database].Alter()
+ $output.RCSI = $rcsiEnabled
+ }
+ $module.Result.changed = $true
+ }
+ }
+ catch {
+ $module.FailJson("Setting Read Commmitted Snapshot Isolation for [$database] failed.", $_)
+ }
+ }
+
+ # Configure MAXDOPs
+ ## Database Scoped MaxDop
+ if ($null -ne $MaxDop) {
+ try {
+ if ($MaxDop -ne $existingMaxDop) {
+ if (-not $checkMode) {
+ $server.Databases[$database].MaxDop = $maxDop
+ $server.Databases[$database].Alter()
+ $output.MaxDop = $MaxDOP
+ }
+ $module.Result.changed = $true
+ }
+ }
+ catch {
+ $module.FailJson("Setting MAXDOP for [$database] failed.", $_)
+ }
+ }
+
+ ## Secondary Mode MaxDop
+ if ($null -ne $secondaryMaxDOP) {
+ try {
+ if ($secondaryMaxDop -ne $existingSecondaryMaxDop) {
+ if (-not $checkMode) {
+ $server.Databases[$database].MaxDopForSecondary = $secondaryMaxDOP
+ $server.Databases[$database].Alter()
+ $output.SecondaryMaxDop = $secondaryMaxDop
+ }
+ $module.Result.changed = $true
+ }
+ }
+ catch {
+ $module.FailJson("Setting MaxDop for secondary mode failed.", $_)
+ }
+ }
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Configuring database failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/database.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/database.py
new file mode 100644
index 00000000..97551c71
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/database.py
@@ -0,0 +1,94 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: database
+short_description: Creates and configures a database
+description:
+ - Adds a new database to an existing SQL Server instance.
+version_added: 0.1.0
+options:
+ database:
+ description:
+ - Name of the target database.
+ type: str
+ required: true
+ recovery_model:
+ description:
+ - Choose the recovery model for the database.
+ type: str
+ required: false
+ choices: ['Full', 'Simple', 'BulkLogged']
+ data_file_path:
+ description:
+ - Directory where the data files should be placed. Uses SQL Server's default if not supplied.
+ - Only used if database is being created.
+ type: str
+ required: false
+ log_file_path:
+ description:
+ - Directory where the log files should be placed. Uses SQL Server's default if not supplied.
+ - Only used if database is being created.
+ type: str
+ required: false
+ owner:
+ description:
+ - Database owner login.
+ type: str
+ required: false
+ maxdop:
+ description:
+ - MAXDOP value for the database.
+ required: false
+ type: int
+ secondary_maxdop:
+ description:
+ - MAXDOP value for the database when it is a non-primary replica in an availability group.
+ required: false
+ type: int
+ compatibility:
+ description:
+ - Compatibility mode for the database. Follows the format of C(Version90), C(Version100), and so on.
+ - String is validated by C(Set-DbaDbCompatibility).
+ required: false
+ type: str
+ rcsi:
+ description:
+ - Whether or not to enable Read Committed Snapshot Isolation.
+ required: false
+ type: bool
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create database
+ lowlydba.sqlserver.database:
+ sql_instance: sql-01.myco.io
+ database: LowlyDB
+
+- name: Create database with customizations
+ lowlydba.sqlserver.database:
+ sql_instance: sql-01.myco.io
+ database: LowlyDB
+ owner: sa
+ maxdop: 2
+ recovery_model: Simple
+'''
+
+RETURN = r'''
+data:
+ description: Modified output from the C(New-DbaDatabase), C(Set-DbaDatabase), or C(Remove-DbaDatabase) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/dba_multitool.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/dba_multitool.ps1
new file mode 100644
index 00000000..ef52bdd6
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/dba_multitool.ps1
@@ -0,0 +1,65 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ branch = @{type = 'str'; required = $false; choices = @('master', 'development') }
+ local_file = @{type = 'str'; required = $false }
+ database = @{type = 'str'; required = $true }
+ force = @{type = 'bool'; required = $false; default = $false }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$branch = $module.Params.branch
+$localFile = $module.Params.local_file
+$force = $module.Params.force
+$checkMode = $module.Checkmode
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+$multiToolSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ Force = $force
+}
+if ($null -ne $localFile) {
+ $multiToolSplat.LocalFile = $localFile
+}
+if ($null -ne $branch) {
+ $multiToolSplat.Branch = $branch
+}
+
+try {
+ $output = Install-DbaMultiTool @multiToolSplat
+ $module.Result.changed = $true
+
+ # output is an array for each stored proc,
+ # rollup output into a single result
+ $errorProcs = $output | Where-Object Status -eq "Error"
+ if ($errorProcs) {
+ $output = $errorProcs[0] | Select-Object -ExcludeProperty Name
+ }
+ else {
+ $output = $output[0] | Select-Object -ExcludeProperty Name
+ }
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Installing DBA-MultiTool failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/dba_multitool.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/dba_multitool.py
new file mode 100644
index 00000000..6daeef3d
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/dba_multitool.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: dba_multitool
+short_description: Install/update the DBA Multitool suite by John McCall
+description:
+ - A wrapper for C(Install-DbaMultiTool) to fetch the latest version of the scripts, or install from a local cached version.
+version_added: 0.7.0
+options:
+ sql_instance:
+ description:
+ - The target SQL Server instance or instances. Server version must be SQL Server version 2005 or higher.
+ type: str
+ required: true
+ local_file:
+ description:
+ - Specifies the path to a local file to install DBA MultiTool from. This should be the zip file as distributed by the maintainers.
+ - If this option is not specified, the latest version will be downloaded and installed from https://github.com/LowlyDBA/dba-multitool/.
+ type: str
+ required: false
+ branch:
+ description:
+ - Specifies an alternate branch of the DBA MultiTool to install.
+ type: str
+ required: false
+ choices: ['master', 'development']
+ database:
+ description:
+ - Name of the target database.
+ type: str
+ required: true
+ force:
+ description:
+ - If this switch is enabled, the DBA MultiTool will be downloaded from the internet even if previously cached.
+ type: bool
+ default: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Install DBA MultiTool
+ lowlydba.sqlserver.dba_multitool:
+ sql_instance: test-server.my.company.com
+ database: dba_tools
+'''
+
+RETURN = r'''
+data:
+ description: Modified output from the C(Install-DbaMultitool) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/first_responder_kit.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/first_responder_kit.ps1
new file mode 100644
index 00000000..1e19ce62
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/first_responder_kit.ps1
@@ -0,0 +1,80 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ branch = @{type = 'str'; required = $false; choices = @('main', 'dev') }
+ local_file = @{type = 'str'; required = $false }
+ only_script = @{type = 'str'; required = $false; default = 'Install-All-Scripts.sql'; choices = @('Install-All-Scripts.sql'
+ 'Install-Core-Blitz-No-Query-Store.sql'
+ 'Install-Core-Blitz-With-Query-Store.sql'
+ 'sp_Blitz.sql'
+ 'sp_BlitzFirst.sql'
+ 'sp_BlitzIndex.sql'
+ 'sp_BlitzCache.sql'
+ 'sp_BlitzWho.sql'
+ 'sp_BlitzQueryStore.sql'
+ 'sp_BlitzAnalysis.sql'
+ 'sp_BlitzBackups.sql'
+ 'sp_BlitzInMemoryOLTP.sql'
+ 'sp_BlitzLock.sql'
+ 'sp_AllNightLog.sql'
+ 'sp_AllNightLog_Setup.sql'
+ 'sp_DatabaseRestore.sql'
+ 'sp_ineachdb.sql'
+ 'SqlServerVersions.sql'
+ 'Uninstall.sql')
+ }
+ database = @{type = 'str'; required = $true }
+ force = @{type = 'bool'; required = $false; default = $false }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$branch = $module.Params.branch
+$onlyScript = $module.Params.only_script
+$localFile = $module.Params.local_file
+$force = $module.Params.force
+$checkMode = $module.Checkmode
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+$firstResponderKitSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ Force = $force
+}
+if ($localFile) {
+ $firstResponderKitSplat.Add("LocalFile", $localFile)
+}
+if ($branch) {
+ $firstResponderKitSplat.Add("Branch", $branch)
+}
+if ($onlyScript) {
+ $firstResponderKitSplat.Add("OnlyScript", $onlyScript)
+}
+
+try {
+ $output = Install-DbaFirstResponderKit @firstResponderKitSplat
+ $module.Result.changed = $true
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Installing First Responder Kit failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/first_responder_kit.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/first_responder_kit.py
new file mode 100644
index 00000000..fba6fad9
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/first_responder_kit.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: first_responder_kit
+short_description: Install/update the First Responder Kit scripts
+description:
+ - A wrapper for C(Install-DbaFirstResponderKit) to fetch the latest version of the scripts, or install from a local cached version.
+version_added: 0.10.0
+options:
+ local_file:
+ description:
+ - Specifies the path to a local file to install FRK from. This should be the zip file as distributed by the maintainers.
+ - If this option is not specified, the latest version will be downloaded and installed Github.
+ type: str
+ required: false
+ only_script:
+ description:
+ - Specifies the name(s) of the script(s) to run for installation. Wildcards are permitted.
+ - This way only part of the First Responder Kit can be installed.
+ type: str
+ required: false
+ default: 'Install-All-Scripts.sql'
+ choices: ['Install-All-Scripts.sql',
+ 'Install-Core-Blitz-No-Query-Store.sql',
+ 'Install-Core-Blitz-With-Query-Store.sql',
+ 'sp_Blitz.sql',
+ 'sp_BlitzFirst.sql',
+ 'sp_BlitzIndex.sql',
+ 'sp_BlitzCache.sql',
+ 'sp_BlitzWho.sql',
+ 'sp_BlitzQueryStore.sql',
+ 'sp_BlitzAnalysis.sql',
+ 'sp_BlitzBackups.sql',
+ 'sp_BlitzInMemoryOLTP.sql',
+ 'sp_BlitzLock.sql',
+ 'sp_AllNightLog.sql',
+ 'sp_AllNightLog_Setup.sql',
+ 'sp_DatabaseRestore.sql',
+ 'sp_ineachdb.sql',
+ 'SqlServerVersions.sql',
+ 'Uninstall.sql']
+ branch:
+ description:
+ - Specifies an alternate branch of the First Responder Kit to install.
+ type: str
+ required: false
+ choices: ['main', 'dev']
+ database:
+ description:
+ - Name of the target database.
+ type: str
+ required: true
+ force:
+ description:
+ - If this switch is enabled, the FRK will be downloaded from the internet even if previously cached.
+ type: bool
+ default: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Install FRK
+ lowlydba.sqlserver.first_responder_kit:
+ sql_instance: test-server.my.company.com
+ database: dba_tools
+'''
+
+RETURN = r'''
+data:
+ description: Modified output from the C(Install-DbaFirstResponderKit) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/hadr.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/hadr.ps1
new file mode 100644
index 00000000..473ad480
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/hadr.ps1
@@ -0,0 +1,71 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+# Get Csharp utility module
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ username = @{type = 'str'; required = $false }
+ password = @{type = 'str'; required = $false; no_log = $true }
+ enabled = @{type = 'bool'; required = $false; default = $true }
+ force = @{type = 'bool'; required = $false; default = $false }
+ }
+ required_together = @(
+ , @('username', 'password')
+ )
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+if ($null -ne $Module.Params.username) {
+ [securestring]$secPassword = ConvertTo-SecureString $Module.Params.password -AsPlainText -Force
+ [pscredential]$credential = New-Object System.Management.Automation.PSCredential ($Module.Params.username, $secPassword)
+}
+$enabled = $module.Params.enabled
+$force = $module.Params.force
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+try {
+ $server = Connect-DbaInstance -SqlInstance $sqlInstance -SqlCredential $sqlCredential
+ $existingHadr = $server | Get-DbaAgHadr -EnableException
+ $output = $existingHadr
+ if ($existingHadr.IsHadrEnabled -ne $enabled) {
+ $setHadr = @{
+ Credential = $credential
+ WhatIf = $checkMode
+ Force = $force
+ Confirm = $false
+ EnableException = $true
+ }
+ if ($enabled -eq $false) {
+ $output = $server | Disable-DbaAgHadr @setHadr
+ }
+ else {
+ $output = $server | Enable-DbaAgHadr @setHadr
+ }
+
+ if ($force -ne $true) {
+ $output | Add-Member -MemberType NoteProperty -Name "RestartRequired" -Value $true
+ }
+ $module.Result.changed = $true
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error configuring Hadr.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/hadr.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/hadr.py
new file mode 100644
index 00000000..0fc91d22
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/hadr.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: hadr
+short_description: Enable or disable HADR
+description:
+ - Enable or disable the High Availability Disaster Recovery (HADR) feature.
+version_added: 0.4.0
+options:
+ sql_instance:
+ description:
+ - The SQL Server instance to modify.
+ type: str
+ required: true
+ username:
+ description:
+ - Username for alternative credential to authenticate with Windows.
+ type: str
+ required: false
+ password:
+ description:
+ - Password for alternative credential to authenticate with Windows.
+ type: str
+ required: false
+ enabled:
+ description:
+ - Flag to enable or disable the feature.
+ type: bool
+ required: false
+ default: true
+ force:
+ description:
+ - Restart SQL Server and SQL Agent services automatically.
+ type: bool
+ required: false
+ default: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_win
+'''
+
+EXAMPLES = r'''
+- name: Enable hadr with service restart
+ lowlydba.sqlserver.hadr:
+ sql_instance: sql-01.myco.io
+ enabled: true
+ force: true
+'''
+
+RETURN = r'''
+data:
+ description:
+ - Output from the C(Enable-DbaAgHadr) or C(Disable-DbaAgHadr) function.
+ - RestartRequired returned if the setting requires a service restart to take effect.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/install_script.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/install_script.ps1
new file mode 100644
index 00000000..5c26588e
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/install_script.ps1
@@ -0,0 +1,86 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+#Requires -Modules @{ ModuleName="dbops"; ModuleVersion="0.8.0" }
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ database = @{type = 'str'; required = $true }
+ path = @{type = 'str'; required = $true }
+ deployment_method = @{type = 'str'; required = $false; default = 'NoTransaction'
+ choices = @('NoTransaction', 'SingleTransaction', 'TransactionPerScript')
+ }
+ schema_version_table = @{type = 'str'; required = $false }
+ no_log_version = @{type = 'bool'; required = $false; default = $false }
+ connection_timeout = @{type = 'int'; required = $false; default = 30 }
+ execution_timeout = @{type = 'int'; required = $false; default = 0 }
+ output_file = @{type = 'str'; required = $false }
+ create_database = @{type = 'bool'; required = $false; default = $false }
+ no_recurse = @{type = 'bool'; required = $false; default = $false }
+ match = @{type = 'str'; required = $false }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$schemaVersionTable = $module.Params.schema_version_table
+$path = $module.Params.path
+$outputFile = $module.Params.output_file
+$match = $module.Params.match
+$connectionTimeout = $module.Params.connection_timeout
+$executionTimeout = $module.Params.execution_timeout
+$createDatabase = $module.Params.create_database
+$noRecurse = $module.Params.no_recurse
+$noLogVersion = $module.Params.no_log_version
+$checkMode = $module.Checkmode
+$PSDefaultParameterValues = @{ "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+try {
+ $installSplat = @{
+ SqlInstance = $sqlInstance
+ Credential = $sqlCredential
+ Database = $database
+ Path = $path
+ ConnectionTimeout = $connectionTimeout
+ ExecutionTimeout = $executionTimeout
+ CreateDatabase = $createDatabase
+ NoRecurse = $noRecurse
+ Silent = $true
+ Type = "SqlServer"
+ }
+ if ($schemaVersionTable) {
+ $installSplat.Add("SchemaVersionTable", $schemaVersionTable)
+ }
+ if ($outputFile) {
+ $installSplat.Add("OutputFile", $outputFile)
+ }
+ if ($match) {
+ $installSplat.Add("Match", $match)
+ }
+ if ($noLogVersion) {
+ $installSplat.SchemaVersionTable = $null
+ }
+
+ $output = Install-DboScript @installSplat
+ if ($output.DeploymentLog[-1] -ne "No new scripts need to be executed - completing.") {
+ $module.Result.changed = $true
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ }
+
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Failed migration script(s) execution: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/install_script.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/install_script.py
new file mode 100644
index 00000000..4dbf78f4
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/install_script.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: install_script
+short_description: Runs migration scripts against a database
+description:
+ - Uses the module C(DBOps) to run C(Dbo-InstallScript) against a target SQL Server database.
+version_added: 0.11.0
+options:
+ database:
+ description:
+ - Name of the target database.
+ required: true
+ type: str
+ path:
+ description:
+ - Directory where targeted sql scripts are stored.
+ type: str
+ required: true
+ schema_version_table:
+ description:
+ - A table that will hold the history of script execution. This table is used to choose what scripts are going to be
+ run during the deployment, preventing the scripts from being execured twice.
+ type: str
+ required: false
+ deployment_method:
+ description:
+ - C(SingleTransaction) - wrap all the deployment scripts into a single transaction and rollback whole deployment on error.
+ - C(TransactionPerScript) - wrap each script into a separate transaction; rollback single script deployment in case of error.
+ - C(NoTransaction) - deploy as is.
+ type: str
+ required: false
+ default: 'NoTransaction'
+ choices: ['NoTransaction', 'SingleTransaction', 'TransactionPerScript']
+ no_log_version:
+ description:
+ - If set, the deployment will not be tracked in the database. That will also mean that all the scripts
+ and all the builds from the package are going to be deployed regardless of any previous deployment history.
+ type: bool
+ default: false
+ required: false
+ connection_timeout:
+ description:
+ - Database server connection timeout in seconds. Only affects connection attempts. Does not affect execution timeout.
+ type: int
+ default: 30
+ required: false
+ execution_timeout:
+ description:
+ - Script execution timeout. The script will be aborted if the execution takes more than specified number of seconds.
+ type: int
+ default: 0
+ required: false
+ output_file:
+ description:
+ - Log output into specified file.
+ type: str
+ required: false
+ create_database:
+ description:
+ - Will create an empty database if missing.
+ type: bool
+ default: false
+ required: false
+ no_recurse:
+ description:
+ - Only process the first level of the target path.
+ type: bool
+ required: false
+ default: false
+ match:
+ description:
+ - Runs a regex verification against provided file names using the provided string.
+ type: str
+ required: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+ - L(dbops,https://github.com/dataplat/dbops) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Migrate a database
+ lowlydba.sqlserver.install_script:
+ sql_instance: test-server.my.company.com
+ database: AdventureWorks
+ path: migrations
+'''
+
+RETURN = r'''
+data:
+ description: Modified output from the C(Install-DboScript) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/instance_info.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/instance_info.ps1
new file mode 100644
index 00000000..a99ea01d
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/instance_info.ps1
@@ -0,0 +1,57 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+# Get Csharp utility module
+$spec = @{
+ supports_check_mode = $true
+ options = @{}
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$module.Result.changed = $false
+
+# Fetch instance information
+try {
+ $getSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ EnableException = $true
+ }
+ $output = Get-DbaConnection @getSplat | Select-Object -Property "ComputerName", "SqlInstance", "InstanceName" -First 1
+
+ if ($null -ne $output) {
+ # Add additional fields
+ $extraProperties = @(
+ "BuildNumber"
+ "Language"
+ "VersionMajor"
+ "VersionMinor"
+ "VersionString"
+ "Collation"
+ "ProductLevel"
+ "IsClustered"
+ "LoginMode"
+ )
+ foreach ($prop in $extraProperties) {
+ $value = (Get-DbaInstanceProperty @getSplat -InstanceProperty $prop).Value
+ $output | Add-Member -MemberType NoteProperty -Name $prop -Value $value
+ }
+
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error fetching instance information: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/instance_info.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/instance_info.py
new file mode 100644
index 00000000..2bfdbf15
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/instance_info.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: instance_info
+short_description: Returns basic information for a SQL Server instance
+description:
+ - Returns basic information for a SQL Server instance.
+version_added: 0.2.0
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode_read_only
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Get basic info for an instance
+ lowlydba.sqlserver.instance_info:
+ sql_instance: sql-01.myco.io
+'''
+
+RETURN = r'''
+data:
+ description: Instance level properties of the SQL Server instance.
+ returned: always
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/login.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/login.ps1
new file mode 100644
index 00000000..d509ba79
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/login.ps1
@@ -0,0 +1,144 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ login = @{type = 'str'; required = $true }
+ password = @{type = 'str'; required = $false; no_log = $true }
+ enabled = @{type = 'bool'; required = $false; default = $true }
+ default_database = @{type = 'str'; required = $false }
+ language = @{type = 'str'; required = $false }
+ password_must_change = @{type = 'bool'; required = $false }
+ password_policy_enforced = @{type = 'bool'; required = $false }
+ password_expiration_enabled = @{type = 'bool'; required = $false }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$login = $module.Params.login
+if ($null -ne $module.Params.password) {
+ $secPassword = ConvertTo-SecureString -String $module.Params.password -AsPlainText -Force
+}
+$enabled = $module.Params.enabled
+$defaultDatabase = $module.Params.default_database
+$language = $module.Params.language
+[nullable[bool]]$passwordMustChange = $module.Params.password_must_change
+[nullable[bool]]$passwordExpirationEnabled = $module.Params.password_expiration_enabled
+[nullable[bool]]$passwordPolicyEnforced = $module.Params.password_policy_enforced
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+
+$module.Result.changed = $false
+
+try {
+ $getLoginSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Login = $login
+ ExcludeSystemLogin = $true
+ EnableException = $true
+ }
+ $existingLogin = Get-DbaLogin @getLoginSplat
+
+ if ($state -eq "absent") {
+ if ($null -ne $existingLogin) {
+ $output = $existingLogin | Remove-DbaLogin -WhatIf:$checkMode -EnableException -Force -Confirm:$false
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "present") {
+ $setLoginSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Login = $login
+ WhatIf = $checkMode
+ EnableException = $true
+ Confirm = $false
+ }
+ if ($null -ne $defaultDatabase) {
+ $setLoginSplat.add("DefaultDatabase", $defaultDatabase)
+ }
+ if ($null -ne $passwordExpirationEnabled) {
+ if ($existingLogin.PasswordExpirationEnabled -ne $passwordExpirationEnabled) {
+ $changed = $true
+ }
+ if ($passwordExpirationEnabled -eq $true) {
+ $setLoginSplat.add("PasswordExpirationEnabled", $true)
+ }
+ }
+ if ($null -ne $passwordPolicyEnforced) {
+ if ($existingLogin.PasswordPolicyEnforced -ne $passwordPolicyEnforced) {
+ $changed = $true
+ }
+ if ($passwordPolicyEnforced -eq $true) {
+ $setLoginSplat.add("PasswordPolicyEnforced", $true)
+ }
+ }
+ if ($true -eq $passwordMustChange) {
+ if ($existingLogin.PasswordMustChange -ne $passwordMustChange) {
+ $changed = $true
+ }
+ if ($passwordMustChange -eq $true) {
+ $setLoginSplat.add("PasswordMustChange", $true)
+ }
+ }
+ if ($null -ne $secPassword) {
+ $setLoginSplat.add("SecurePassword", $secPassword)
+ }
+
+ # Login already exists
+ if ($null -ne $existingLogin) {
+ if ($enabled -eq $false) {
+ $disabled = $true
+ $setLoginSplat.add("Disable", $true)
+ }
+ else {
+ $disabled = $false
+ $setLoginSplat.add("Enable", $true)
+ }
+ # Login needs to be modified
+ if (($changed -eq $true) -or ($disabled -ne $existingLogin.IsDisabled) -or ($secPassword)) {
+ $output = Set-DbaLogin @setLoginSplat
+ $module.result.changed = $true
+ }
+ }
+ # New login
+ else {
+ if ($null -ne $language) {
+ $setLoginSplat.add("Language", $language)
+ }
+ if ($enabled -eq $false) {
+ $setLoginSplat.add("Disabled", $true)
+ }
+ $output = New-DbaLogin @setLoginSplat
+ $module.result.changed = $true
+ }
+ # If not in check mode, add extra fields we can change to default display set
+ if ($null -ne $output) {
+ $output.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Add("DefaultDatabase")
+ $output.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Add("Language")
+ }
+
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Configuring login failed: $($_.Exception.Message) ; $setLoginSplat", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/login.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/login.py
new file mode 100644
index 00000000..a570d8cf
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/login.py
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: login
+short_description: Configures a login for the target SQL Server instance
+description:
+ - Creates, modifies, or removes a Windows or SQL Authentication login on a SQL Server instance.
+version_added: 0.1.0
+options:
+ login:
+ description:
+ - Name of the login to configure.
+ type: str
+ required: true
+ password:
+ description:
+ - Password for the login, if SQL Authentication login.
+ type: str
+ required: false
+ enabled:
+ description:
+ - Whether the login is enabled or disabled.
+ type: bool
+ required: false
+ default: true
+ version_added: '0.4.0'
+ default_database:
+ description:
+ - Default database for the login.
+ type: str
+ required: false
+ language:
+ description:
+ - Default language for the login. Only used when creating a new login, not when modifying an existing one.
+ type: str
+ required: false
+ password_must_change:
+ description:
+ - Enforces user must change password at next login.
+ - When specified will enforce I(password_expiration_enabled) and I(password_policy_enforced) as they are required.
+ type: bool
+ required: false
+ password_policy_enforced:
+ description:
+ - Enforces password complexity policy.
+ type: bool
+ required: false
+ password_expiration_enabled:
+ description:
+ - Enforces password expiration policy. Requires I(password_policy_enforced=true).
+ type: bool
+ required: false
+author: "John McCall (@lowlydba)"
+notes:
+ - Module will always return changed if a password is supplied.
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create a login
+ lowlydba.sqlserver.login:
+ sql_instance: sql-01.myco.io
+ login: TheIntern
+ password: ReallyComplexStuff12345!
+
+- name: Disable a login
+ lowlydba.sqlserver.login:
+ sql_instance: sql-01.myco.io
+ login: TheIntern
+ enabled: false
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(New-DbaLogin), C(Set-DbaLogin), or C(Remove-DbaLogin) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/maintenance_solution.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/maintenance_solution.ps1
new file mode 100644
index 00000000..48f9c90a
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/maintenance_solution.ps1
@@ -0,0 +1,105 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ backup_location = @{type = 'str'; required = $false }
+ cleanup_time = @{type = 'int'; required = $false; default = 0 }
+ output_file_dir = @{type = 'str'; required = $false }
+ replace_existing = @{type = 'bool'; required = $false; }
+ log_to_table = @{type = 'bool'; required = $false; default = $false }
+ solution = @{type = 'str'; required = $false; choices = @('All', 'Backup', 'IntegrityCheck', 'IndexOptimize'); default = 'All' }
+ install_jobs = @{type = 'bool'; required = $false; default = $false }
+ local_file = @{type = 'str'; required = $false }
+ database = @{type = 'str'; required = $true }
+ force = @{type = 'bool'; required = $false; default = $false }
+ install_parallel = @{type = 'bool'; required = $false; default = $false }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$backupLocation = $module.Params.backup_location
+$outputFileDirectory = $module.Params.output_file_dir
+$cleanupTime = $module.Params.cleanup_time
+$replaceExisting = $module.Params.replace_existing
+$solution = $module.Params.solution
+$installJobs = $module.Params.install_jobs
+$installParallel = $module.Params.install_parallel
+$logToTable = $module.Params.log_to_table
+$localFile = $module.Params.local_file
+$force = $module.Params.force
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+try {
+ $maintenanceSolutionSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ LogToTable = $logToTable
+ Solution = $solution
+ InstallJobs = $installJobs
+ InstallParallel = $installParallel
+ WhatIf = $checkMode
+ Force = $force
+ Confirm = $false
+ EnableException = $true
+ }
+ if ($null -ne $localFile) {
+ $maintenanceSolutionSplat.LocalFile = $localFile
+ }
+ if ($null -ne $backupLocation) {
+ $maintenanceSolutionSplat.BackupLocation = $backupLocation
+ }
+ if ($null -ne $outputFileDirectory) {
+ $maintenanceSolutionSplat.OutputFileDirectory = $outputFileDirectory
+ }
+ if ($installJobs -eq $true -and $null -ne $cleanupTime) {
+ $maintenanceSolutionSplat.CleanupTime = $cleanupTime
+ }
+ # Only pass if true, otherwise removes warning that is used to track changed=$false
+ if ($replaceExisting -eq $true) {
+ $maintenanceSolutionSplat.ReplaceExisting = $replaceExisting
+ }
+
+ try {
+ $output = Install-DbaMaintenanceSolution @maintenanceSolutionSplat
+ $module.Result.changed = $true
+ }
+ catch {
+ $errMessage = $_.Exception.Message
+ if ($errMessage -like "*Maintenance Solution already exists*") {
+ $server = Connect-DbaInstance -SqlInstance $sqlInstance -SqlCredential $sqlCredential
+ $output = [PSCustomObject]@{
+ ComputerName = $server.ComputerName
+ InstanceName = $server.ServiceName
+ SqlInstance = $server.DomainInstanceName
+ Results = "Success"
+ }
+ }
+ else {
+ Write-Error -Message $errMessage
+ }
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Installing Maintenance Solution failed.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/maintenance_solution.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/maintenance_solution.py
new file mode 100644
index 00000000..1df314ff
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/maintenance_solution.py
@@ -0,0 +1,101 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: maintenance_solution
+short_description: Install/update Maintenance Solution by Ola Hallengren
+description:
+ - A wrapper for C(Install-DbaMaintenanceSolution) to fetch the latest version of the Ola Hallengren's Maintenance Solution,
+ or install from a local cached version.
+version_added: 0.1.0
+options:
+ backup_location:
+ description:
+ - Location of the backup root directory. If this is not supplied, the default backup directory will be used.
+ type: str
+ required: false
+ cleanup_time:
+ description:
+ - Time in hours, after which backup files are deleted.
+ type: int
+ required: false
+ default: 0
+ output_file_dir:
+ description:
+ - Specify the output file directory where the Maintenance Solution will write to.
+ type: str
+ required: false
+ replace_existing:
+ description:
+ - If this switch is enabled, objects already present in the target database will be dropped and recreated.
+ type: bool
+ required: false
+ log_to_table:
+ description:
+ - If this switch is enabled, the Maintenance Solution will be configured to log commands to a table.
+ type: bool
+ required: false
+ default: false
+ solution:
+ description:
+ - Specifies which portion of the Maintenance Solution to install.
+ type: str
+ required: false
+ default: 'All'
+ choices: ['All', 'Backup', 'IntegrityCheck', 'IndexOptimize']
+ install_jobs:
+ description:
+ - If this switch is enabled, the corresponding SQL Agent Jobs will be created.
+ type: bool
+ required: false
+ default: false
+ install_parallel:
+ description:
+ - If this switch is enabled, the C(Queue) and C(QueueDatabase) tables are created, for use when C(@DatabasesInParallel = 'Y') are set in the jobs.
+ type: bool
+ required: false
+ default: false
+ local_file:
+ description:
+ - Specifies the path to a local file to install Ola's solution from. This should be the zip file as distributed by the maintainers.
+ - If this option is not specified, the latest version will be downloaded and installed
+ from the L(Maintenance Solution Github,https://github.com/olahallengren/sql-server-maintenance-solution).
+ type: str
+ required: false
+ database:
+ description:
+ - Name of the target database.
+ type: str
+ required: true
+ force:
+ description:
+ - If this switch is enabled, the Maintenance Solution will be downloaded from the internet even if previously cached.
+ type: bool
+ default: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Install/Update Maintenance Solution
+ lowlydba.sqlserver.multitool:
+ sql_instance: sql-01.myco.io
+ database: main
+ replace_existing: true
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Install-MaintenanceSolution) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/memory.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/memory.ps1
new file mode 100644
index 00000000..1b6d2bed
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/memory.ps1
@@ -0,0 +1,50 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+# Get Csharp utility module
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ max = @{type = "int"; required = $false; default = 0 }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$max = $module.Params.max
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+# Set max memory for SQL Instance
+try {
+ # Set max memory
+ $setMemorySplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Max = $max
+ }
+ $output = Set-DbaMaxMemory @setMemorySplat
+
+ if ($output.PreviousMaxValue -ne $output.MaxValue -or $checkMode) {
+ $module.Result.changed = $true
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error setting max memory.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/memory.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/memory.py
new file mode 100644
index 00000000..65b6b327
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/memory.py
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: memory
+short_description: Sets the maximum memory for a SQL Server instance
+description:
+ - Sets the maximum memory for a SQL Server instance.
+version_added: 0.1.0
+options:
+ max:
+ description:
+ - The maximum memory in MB that the SQL Server instance can utilize. C(0) will automatically calculate the ideal value.
+ type: int
+ required: false
+ default: 0
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Automatically configure SQL max memory
+ lowlydba.sqlserver.memory:
+ sql_instance: sql-01.myco.io
+
+- name: Manually configure SQL max memory
+ lowlydba.sqlserver.memory:
+ sql_instance: sql-01.myco.io
+ max: 10240
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Set-DbaMaxMemory) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/nonquery.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/nonquery.ps1
new file mode 100644
index 00000000..fdc34d17
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/nonquery.ps1
@@ -0,0 +1,51 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+# Get Csharp utility module
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ database = @{type = 'str'; required = $true }
+ nonquery = @{type = 'str'; required = $true }
+ query_timeout = @{type = 'int'; required = $false; default = 60 }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$nonquery = $module.Params.nonquery
+$queryTimeout = $module.Params.query_timeout
+$checkMode = $module.CheckMode
+
+$module.Result.changed = $false
+
+try {
+ $invokeQuerySplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ Query = $nonquery
+ QueryTimeout = $queryTimeout
+ EnableException = $true
+ }
+ if ($checkMode) {
+ $invokeQuerySplat.Add("NoExec", $true)
+ }
+ $null = Invoke-DbaQuery @invokeQuerySplat
+
+ $module.Result.changed = $true
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Executing nonquery failed.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/nonquery.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/nonquery.py
new file mode 100644
index 00000000..9f56c7bc
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/nonquery.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: nonquery
+short_description: Executes a generic nonquery
+description:
+ - Execute a nonquery against a database. Does not return a resultset. Ideal for ad-hoc configurations or DML queries.
+version_added: 0.1.0
+options:
+ database:
+ description:
+ - Name of the database to execute the nonquery in.
+ type: str
+ required: true
+ nonquery:
+ description:
+ - The nonquery to be executed.
+ type: str
+ required: true
+ query_timeout:
+ description:
+ - Number of seconds to wait before timing out the nonquery execution.
+ type: int
+ required: false
+ default: 60
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Update a table value
+ lowlydba.sqlserver.nonquery:
+ sql_instance: sql-01-myco.io
+ database: userdb
+ nonquery: "UPDATE dbo.User set IsActive = 1;"
+'''
+
+RETURN = r''' # '''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/resource_governor.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/resource_governor.ps1
new file mode 100644
index 00000000..aa0ade5e
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/resource_governor.ps1
@@ -0,0 +1,69 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ enabled = @{type = 'bool'; required = $false; default = $true }
+ classifier_function = @{type = 'str'; required = $false }
+ }
+}
+
+# Get Csharp utility module
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$enabled = $module.Params.enabled
+$classifierFunction = $module.Params.classifier_function
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+try {
+ $rg = Get-DbaResourceGovernor -SqlInstance $sqlInstance -SqlCredential $sqlCredential
+ $rgClassifierFunction = $rg.ClassifierFunction
+
+ if ($rg.Enabled -ne $enabled) {
+ $change = $true
+ }
+ if ($classifierFunction -ne "NULL" -and $rgClassifierFunction -ne $classifierFunction) {
+ $change = $true
+ }
+ if ($classifierFunction -eq "NULL" -and $null -ne $rgClassifierFunction) {
+ $change = $true
+ }
+
+ if ($change) {
+ $rgSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ ClassifierFunction = $classifierFunction
+ }
+ if ($enabled) {
+ $rgSplat.Add("Enabled", $true)
+ }
+ else {
+ $rgSplat.Add("Disabled", $true)
+ }
+ $output = Set-DbaResourceGovernor @rgSplat
+ $module.Result.changed = $true
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Setting resource governor failed.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/resource_governor.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/resource_governor.py
new file mode 100644
index 00000000..66b789d2
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/resource_governor.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: resource_governor
+short_description: Configures the resource governor on a SQL Server instance
+description:
+ - Enables or disables and optionally sets the classifier function for the resource governor feature.
+version_added: 0.1.0
+options:
+ enabled:
+ description:
+ - Whether to enable or disable resource governor.
+ type: bool
+ required: false
+ default: true
+ classifier_function:
+ description:
+ - The name of the classifier function that resource governor will use. To clear the function, use the string C(NULL).
+ type: str
+ required: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Enable resource governor
+ lowlydba.sqlserver.resource_governor:
+ sql_instance: sql-01.myco.io
+ enabled: true
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Set-DbaResourceGovernor) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/restore.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/restore.ps1
new file mode 100644
index 00000000..73c9690f
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/restore.ps1
@@ -0,0 +1,170 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ database = @{type = 'str'; required = $false }
+ path = @{type = 'str'; required = $true }
+ destination_data_directory = @{type = 'str'; required = $false }
+ destination_log_directory = @{type = 'str'; required = $false }
+ destination_filestream_directory = @{type = 'str'; required = $false }
+ restore_time = @{type = 'str'; required = $false }
+ with_replace = @{type = 'bool'; required = $false; default = $false }
+ keep_replication = @{type = 'bool'; required = $false; default = $false }
+ xp_dirtree = @{type = 'bool'; required = $false }
+ no_xp_dir_recurse = @{type = 'bool'; required = $false; default = $false }
+ verify_only = @{type = 'bool'; required = $false; default = $false }
+ maintenance_solution_backup = @{type = 'bool'; required = $false; default = $false }
+ ignore_log_backup = @{type = 'bool'; required = $false; default = $false }
+ ignore_diff_backup = @{type = 'bool'; required = $false; default = $false }
+ use_destination_default_directories = @{type = 'bool'; required = $false }
+ reuse_source_folder_structure = @{type = 'bool'; required = $false }
+ destination_file_prefix = @{type = 'str'; required = $false }
+ restored_database_name_prefix = @{type = 'str'; required = $false }
+ directory_recurse = @{type = 'bool'; required = $false; default = $false }
+ standby_directory = @{type = 'str'; required = $false }
+ replace_db_name_in_file = @{type = 'bool'; required = $false }
+ destination_file_suffix = @{type = 'str'; required = $false }
+ keep_cdc = @{type = 'bool'; required = $false }
+ stop_before = @{type = 'bool'; required = $false; default = $false }
+ stop_mark = @{type = 'str'; required = $false }
+ stop_after_date = @{type = 'str'; required = $false }
+ no_recovery = @{type = 'bool'; required = $false; default = $false }
+ max_transfer_size = @{type = 'int'; required = $false; default = 0 }
+ block_size = @{type = 'str'; required = $false; choices = @('0.5kb', '1kb', '2kb', '4kb', '8kb', '16kb', '32kb', '64kb') }
+ buffer_count = @{type = 'int'; required = $false; default = 0 }
+ azure_credential = @{type = 'str'; required = $false }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$path = $module.Params.path
+$destinationDataDirectory = $module.Params.destination_data_directory
+$destinationLogDirectory = $module.Params.destination_log_directory
+$destinationFilestreamDirectory = $module.Params.destination_filestream_directory
+$restoreTime = $module.Params.restore_time
+$withReplace = $module.Params.with_replace
+$keepReplication = $module.Params.keep_replication
+$xpDirTree = $module.Params.xp_dirtree
+$noXpDirRecurse = $module.Params.no_xp_dir_recurse
+$verifyOnly = $module.Params.verify_only
+$maintenanceSolutionBackup = $module.Params.maintenance_solution_backup
+$ignoreLogBackup = $module.Params.ignore_log_backup
+$ignoreDiffBackup = $module.Params.ignore_diff_backup
+$useDestinationDefaultDirectories = $module.Params.use_destination_default_directories
+$reuseSourceFolderStructure = $module.Params.reuse_source_folder_structure
+$destinationFilePrefix = $module.Params.destination_file_prefix
+$restoredDatabaseNamePrefix = $module.Params.restored_database_name_prefix
+$directoryRecurse = $module.Params.directory_recurse
+$standbyDirectory = $module.Params.standby_directory
+$replaceDbNameInFile = $module.Params.replace_db_name_in_file
+$destinationFileSuffix = $module.Params.destination_file_suffix
+$keepCDC = $module.Params.keep_cdc
+$stopBefore = $module.Params.stop_before
+$stopMark = $module.Params.stop_mark
+$stopAfterDate = $module.Params.stop_after_date
+$noRecovery = $module.Params.no_recovery
+$maxTransferSize = $module.Params.max_transfer_size
+$blockSize = $module.Params.block_size
+$bufferCount = $module.Params.buffer_count
+$azureCredential = $modules.Param.azure_credential
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+try {
+ $restoreSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Path = $path
+ WithReplace = $withReplace
+ KeepReplication = $keepReplication
+ NoXpDirRecurse = $noXpDirRecurse
+ VerifyOnly = $verifyOnly
+ MaintenanceSolutionBackup = $maintenanceSolutionBackup
+ IgnoreLogBackup = $ignoreLogBackup
+ IgnoreDiffBackup = $ignoreDiffBackup
+ DirectoryRecurse = $directoryRecurse
+ StopBefore = $stopBefore
+ NoRecovery = $noRecovery
+ MaxTransferSize = $maxTransferSize
+ BufferCount = $bufferCount
+ }
+ if ($null -ne $database) {
+ $restoreSplat.Add("DatabaseName", $database)
+ }
+ if ($null -ne $destinationDataDirectory) {
+ $restoreSplat.Add("DestinationDataDirectory", $destinationDataDirectory)
+ }
+ if ($null -ne $destinationLogDirectory) {
+ $restoreSplat.Add("DestinationLogDirectory", $destinationLogDirectory)
+ }
+ if ($null -ne $destinationFilestreamDirectory) {
+ $restoreSplat.Add("DestinationFilestreamDirectory", $destinationFilestreamDirectory)
+ }
+ if ($null -ne $restoreTime) {
+ $restoreSplat.Add("RestoreTime", $restoreTime)
+ }
+ if ($null -ne $destinationFilePrefix) {
+ $restoreSplat.Add("DestinationFilePrefix", $destinationFilePrefix)
+ }
+ if ($null -ne $restoredDatabaseNamePrefix) {
+ $restoreSplat.Add("RestoredDatabaseNamePrefix", $restoredDatabaseNamePrefix)
+ }
+ if ($null -ne $standbyDirectory) {
+ $restoreSplat.Add("StandbyDirectory", $standbyDirectory)
+ }
+ if ($null -ne $destinationFileSuffix) {
+ $restoreSplat.Add("DestinationFileSuffix", $destinationFileSuffix)
+ }
+ if ($null -ne $stopAfterDate) {
+ $restoreSplat.Add("StopAfterDate", $stopAfterDate)
+ }
+ if ($null -ne $stopMark) {
+ $restoreSplat.Add("StopMark", $stopMark)
+ }
+ if ($null -ne $blockSize) {
+ $restoreSplat.Add("BlockSize", ($blockSize / 1))
+ }
+ if ($null -ne $azureCredential) {
+ $restoreSplat.Add("AzureCredential", $azureCredential)
+ }
+ if ($null -ne $xpDirTree) {
+ $restoreSplat.Add("xpDirTree", $xpDirTree)
+ }
+ if ($null -ne $reuseSourceFolderStructure) {
+ $restoreSplat.Add("reuseSourceFolderStructure", $reuseSourceFolderStructure)
+ }
+ if ($null -ne $replaceDbNameInFile) {
+ $restoreSplat.Add("replaceDbNameInFile", $replaceDbNameInFile)
+ }
+ if ($null -ne $useDestinationDefaultDirectories) {
+ $restoreSplat.Add("useDestinationDefaultDirectories", $useDestinationDefaultDirectories)
+ }
+ if ($null -ne $keepCDC) {
+ $restoreSplat.Add("KeepCDC", $keepCDC)
+ }
+ $output = Restore-DbaDatabase @restoreSplat
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ $module.Result.changed = $true
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Error restoring database: $($_.Exception.Message).", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/restore.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/restore.py
new file mode 100644
index 00000000..5899ef18
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/restore.py
@@ -0,0 +1,230 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: restore
+short_description: Performs a restore operation
+description:
+ - Performs a database restore operation.
+version_added: 0.9.0
+options:
+ database:
+ description:
+ - The database to process.
+ type: str
+ required: false
+ path:
+ description:
+ - Path to SQL Server backup files.
+ - Paths passed in as strings will be scanned using the desired method, default is a recursive folder scan.
+ - Accepts multiple paths separated by C(,).
+ type: str
+ required: true
+ destination_data_directory:
+ description:
+ - Path to restore the SQL Server backups to on the target instance.
+ - If only this option is specified, then all database files (data and log) will be restored to this location
+ type: str
+ required: false
+ destination_log_directory:
+ description:
+ - Path to restore the database log files to.
+ - This option can only be specified alongside I(destination_data_directory).
+ type: str
+ required: false
+ destination_filestream_directory:
+ description:
+ - Path to restore FileStream data to.
+ - This option can only be specified alongside I(destination_data_directory).
+ type: str
+ required: false
+ restore_time:
+ description:
+ - Specify a datetime string C(HH:MM:SS MM/DD/YYYY) to which you want the database restored to.
+ - Default is to the latest point available in the specified backups.
+ type: str
+ required: false
+ with_replace:
+ description:
+ - Indicates if the restore is allowed to replace an existing database.
+ type: bool
+ required: false
+ default: false
+ keep_replication:
+ description:
+ - Indicates whether replication configuration should be restored as part of the database restore operation.
+ type: bool
+ required: false
+ default: false
+ xp_dirtree:
+ description:
+ - Switch that indicated file scanning should be performed by the SQL Server instance using C(xp_dirtree).
+ - This will scan recursively from the passed in path.
+ - You must have sysadmin role membership on the instance for this to work.
+ type: bool
+ required: false
+ no_xp_dir_recurse:
+ description:
+ - If specified, prevents the C(XpDirTree) process from recursing (its default behaviour).
+ type: bool
+ required: false
+ default: false
+ verify_only:
+ description:
+ - Indicates the restore should be verified only.
+ type: bool
+ required: false
+ default: false
+ maintenance_solution_backup:
+ description:
+ - Switch to indicate the backup files are in a folder structure as created by Ola Hallengreen's maintenance scripts.
+ - This allows for faster file parsing.
+ type: bool
+ required: false
+ default: false
+ ignore_log_backup:
+ description:
+ - Indicates to skip restoring any log backups.
+ type: bool
+ required: false
+ default: false
+ ignore_diff_backup:
+ description:
+ - Indicates to skip restoring any differential backups.
+ type: bool
+ required: false
+ default: false
+ use_destination_default_directories:
+ description:
+ - Switch that tells the restore to use the default Data and Log locations on the target server.
+ - If they don't exist, the function will try to create them.
+ type: bool
+ required: false
+ reuse_source_folder_structure:
+ description:
+ - By default, databases will be migrated to the destination Sql Server's default data and log directories.
+ - You can override this by using C(reuse_source_folder_structure).
+ type: bool
+ required: false
+ destination_file_prefix:
+ description:
+ - This value will be prefixed to B(all) restored files (log and data).
+ type: str
+ required: false
+ restored_database_name_prefix:
+ description:
+ - A string which will be prefixed to the start of the restore Database's name.
+ type: str
+ required: false
+ directory_recurse:
+ description:
+ - If specified the specified directory will be recursed into (overriding the default behaviour).
+ type: bool
+ required: false
+ default: false
+ standby_directory:
+ description:
+ - If a directory is specified the database(s) will be restored into a standby state,
+ with the standby file placed into this directory (which must exist, and be writable by the target Sql Server instance).
+ type: str
+ required: false
+ replace_db_name_in_file:
+ description:
+ - If switch set any occurrence of the original database's name in a data or log file
+ will be replace with the name specified in the I(database_name) option.
+ type: bool
+ required: false
+ destination_file_suffix:
+ description:
+ - This value will be suffixed to B(all) restored files (log and data).
+ type: str
+ required: false
+ keep_cdc:
+ description:
+ - Indicates whether CDC information should be restored as part of the database.
+ type: bool
+ required: false
+ stop_before:
+ description:
+ - Switch to indicate the restore should stop before I(stop_mark) occurs, default is to stop when mark is created.
+ type: bool
+ required: false
+ default: false
+ stop_mark:
+ description:
+ - Marked point in the transaction log to stop the restore at.
+ type: str
+ required: false
+ stop_after_date:
+ description:
+ - By default the restore will stop at the first occurence of I(stop_mark) found in the chain,
+ passing a datetime string C(HH:MM:SS MM/DD/YYYY) will cause it to stop the first I(stop_mark) after that datetime.
+ type: str
+ required: false
+ no_recovery:
+ description:
+ - Indicates if the databases should be recovered after last restore.
+ type: bool
+ required: false
+ default: false
+ max_transfer_size:
+ description:
+ - Sets the size of the unit of transfer. Values must be a multiple of 64kb.
+ type: int
+ required: false
+ default: 0
+ block_size:
+ description:
+ - Specifies block size to use.
+ type: str
+ required: false
+ choices: ['0.5kb','1kb','2kb','4kb','8kb','16kb','32kb','64kb']
+ buffer_count:
+ description:
+ - Number of I/O buffers to use.
+ type: int
+ required: false
+ default: 0
+ azure_credential:
+ description:
+ - The name of the SQL Server credential to be used if restoring from an Azure hosted backup using Storage Access Keys.
+ type: str
+ required: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Restore a Database
+ lowlydba.sqlserver.restore:
+ sql_instance: sql-01.myco.io
+ database: LowlyDB
+
+- name: Restore a Database and allow future T-Log restores
+ lowlydba.sqlserver.restore:
+ sql_instance: sql-01.myco.io
+ database: LowlyDB1
+ no_recovery: true
+
+- name: Verify backup files, no restore
+ lowlydba.sqlserver.restore:
+ sql_instance: sql-01.myco.io
+ database: LowlyDB2
+ verify_only: true
+'''
+
+RETURN = r'''
+data:
+ description: Modified output from the C(Restore-DbaDatabase) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_resource_pool.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_resource_pool.ps1
new file mode 100644
index 00000000..a6b7ff9b
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_resource_pool.ps1
@@ -0,0 +1,118 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ resource_pool = @{type = 'str'; required = $true }
+ type = @{type = 'str'; required = $false; default = 'Internal'; choices = @('Internal', 'External') }
+ max_cpu_perc = @{type = 'int'; required = $false; }
+ min_cpu_perc = @{type = 'int'; required = $false; }
+ cap_cpu_perc = @{type = 'int'; required = $false; }
+ max_mem_perc = @{type = 'int'; required = $false; }
+ min_mem_perc = @{type = 'int'; required = $false; }
+ min_iops_per_vol = @{type = 'int'; required = $false; }
+ max_iops_per_vol = @{type = 'int'; required = $false; }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$state = $module.Params.state
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$options = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ ResourcePool = $module.Params.resource_pool
+ Type = $module.Params.type
+ MaximumCpuPercentage = $module.Params.max_cpu_perc
+ MinimumCpuPercentage = $module.Params.min_cpu_perc
+ CapCpuPercentage = $module.Params.cap_cpu_perc
+ MaximumMemoryPercentage = $module.params.max_mem_perc
+ MinimumMemoryPercentage = $module.Params.min_mem_perc
+ MinimumIOPSPerVolume = $module.params.min_iops_per_vol
+ MaximumIOPSPerVolume = $module.params.max_iops_per_vol
+}
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+[System.Collections.ArrayList]$compareProperty = @(
+ 'MaximumCpuPercentage',
+ 'MinimumCpuPercentage',
+ 'CapCpuPercentage',
+ 'MinimumMemoryPercentage',
+ 'MaximumMemoryPercentage',
+ 'MinimumIOPSPerVolume',
+ 'MaximumIOPSPerVolume'
+)
+
+$optionsToRemove = @()
+foreach ($item in $options.GetEnumerator() ) {
+ if ($null -eq $item.Value) {
+ $optionsToRemove += $item.Name
+ }
+}
+foreach ($item in $optionsToRemove) {
+ $options.Remove($item)
+ $compareProperty.Remove($item)
+}
+
+try {
+ $getPoolParams = @{
+ SqlInstance = $options.SqlInstance
+ SqlCredential = $options.SqlCredential
+ Type = $options.Type
+ EnableException = $true
+ }
+ $existingResourcePool = Get-DbaRgResourcePool @getPoolParams | Where-Object Name -eq $options.ResourcePool
+
+ if ($state -eq "absent") {
+ if ($null -ne $existingResourcePool) {
+ $removePoolParams = @{
+ SqlInstance = $options.SqlInstance
+ SqlCredential = $options.SqlCredential
+ Type = $options.Type
+ ResourcePool = $options.ResourcePool
+ WhatIf = $checkMode
+ EnableException = $true
+ Confirm = $false
+ }
+ $output = Remove-DbaRgResourcePool @removePoolParams
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "present") {
+ $options.Add("WhatIf", $checkMode)
+ if ($null -ne $existingResourcePool) {
+ # Check for value parity
+ $diff = Compare-Object -ReferenceObject $options -DifferenceObject $existingResourcePool -Property $compareProperty
+ if ($null -ne $diff) {
+ # Set to new values
+ $output = Set-DbaRgResourcePool @options -EnableException
+ $module.Result.changed = $true
+ }
+ }
+ else {
+ # Create a resource pool
+ $output = New-DbaRgResourcePool @options -EnableException
+ $module.Result.changed = $true
+ }
+ }
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Configuring resource pool failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_resource_pool.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_resource_pool.py
new file mode 100644
index 00000000..08b7aef2
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_resource_pool.py
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: rg_resource_pool
+short_description: Configures a resource pool for use by the Resource Governor
+description:
+ - Creates or modifies a resource pool to be used by the Resource Governor. Default values are handled by the Powershell functions themselves.
+version_added: 0.1.0
+options:
+ resource_pool:
+ description:
+ - Name of the target resource pool.
+ type: str
+ required: true
+ type:
+ description:
+ - Specify the type of resource pool.
+ type: str
+ required: false
+ default: 'Internal'
+ choices: ['Internal', 'External']
+ max_cpu_perc:
+ description:
+ - Maximum CPU Percentage able to be used by queries in this resource pool.
+ type: int
+ required: false
+ min_cpu_perc:
+ description:
+ - Minimum CPU Percentage able to be used by queries in this resource pool.
+ type: int
+ required: false
+ cap_cpu_perc:
+ description:
+ - Cap CPU Percentage able to be used by queries in this resource pool.
+ type: int
+ required: false
+ max_mem_perc:
+ description:
+ - Maximum Memory Percentage able to be used by queries in this resource pool.
+ type: int
+ required: false
+ min_mem_perc:
+ description:
+ - Minimum Memory Percentage able to be used by queries in this resource pool.
+ type: int
+ required: false
+ max_iops_per_vol:
+ description:
+ - Maximum IOPS/volume able to be used by queries in this resource pool.
+ type: int
+ required: false
+ min_iops_per_vol:
+ description:
+ - Minimum IOPS/volume able to be used by queries in this resource pool.
+ type: int
+ required: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Enable resource governor
+ lowlydba.sqlserver.resource_governor:
+ sql_instance: sql-01.myco.io
+ enabled: true
+
+- name: Create rg resource pool
+ lowlydba.sqlserver.rg_resource_pool:
+ sql_instance: sql-01.myco.io
+ resource_pool: "rpLittle"
+ max_cpu_perc: 5
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Set-DbaRgResourcePool), C(New-DbaRgResourcePool), or C(Remove-DbaRgResourcePool) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_workload_group.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_workload_group.ps1
new file mode 100644
index 00000000..0b225fd1
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_workload_group.ps1
@@ -0,0 +1,112 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ workload_group = @{type = 'str'; required = $true; }
+ resource_pool = @{type = 'str'; required = $true; }
+ resource_pool_type = @{type = 'str'; required = $false; default = 'Internal'; choices = @('Internal', 'External') }
+ group_max_requests = @{type = 'int'; required = $false; }
+ importance = @{type = 'str'; required = $false; choices = @('Low', 'Medium', 'High') }
+ max_dop = @{type = 'int'; required = $false; }
+ request_max_cpu_time = @{type = 'int'; required = $false; }
+ request_max_mem_grant_perc = @{type = 'int'; required = $false; }
+ request_mem_grant_timeout_sec = @{type = 'int'; required = $false; }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+# Get Csharp utility module
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$options = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ WorkloadGroup = $module.Params.workload_group
+ ResourcePool = $module.Params.resource_pool
+ ResourcePoolType = $module.Params.resource_pool_type
+ GroupMaximumRequests = $module.Params.group_max_requests
+ Importance = $module.Params.importance
+ MaximumDegreeOfParallelism = $module.Params.max_dop
+ RequestMaximumCpuTimeInSeconds = $module.Params.request_max_cpu_time
+ RequestMaximumMemoryGrantPercentage = $module.Params.request_max_mem_grant_perc
+ RequestMemoryGrantTimeoutInSeconds = $module.Params.request_mem_grant_timeout_sec
+}
+$state = $module.Params.state
+$module.Result.changed = $false
+$checkMode = $module.CheckMode
+[System.Collections.ArrayList]$compareProperty = @(
+ 'GroupMaximumRequests',
+ 'Importance',
+ 'MaximumDegreeOfParallelism',
+ 'RequestMaximumCpuTimeInSeconds',
+ 'RequestMemoryGrantTimeoutInSeconds',
+ 'RequestMaximumMemoryGrantPercentage'
+)
+
+# Remove unsupplied params - the dbatools functions handle default value checks
+$optionsToRemove = @()
+foreach ($item in $options.GetEnumerator() ) {
+ if ($null -eq $item.Value) {
+ $optionsToRemove += $item.Name
+ }
+}
+foreach ($item in $optionsToRemove) {
+ $options.Remove($item)
+ $compareProperty.Remove($item)
+}
+
+try {
+ $getResourcePoolSplat = @{
+ SqlInstance = $options.SqlInstance
+ SqlCredential = $options.SqlCredential
+ Type = $options.ResourcePoolType
+ }
+ $existingResourcePool = Get-DbaRgResourcePool @getResourcePoolSplat | Where-Object Name -eq $options.ResourcePool
+ if ($null -eq $existingResourcePool) {
+ $module.FailJson("Failed to lookup parent resource pool '$($options.ResourcePool)'.", $_)
+ }
+ $existingWorkloadGroup = $existingResourcePool.WorkloadGroups | Where-Object Name -eq $options.WorkloadGroup
+
+ if ($state -eq "absent") {
+ if ($null -ne $existingResourcePool) {
+ $output = $existingWorkloadGroup | Remove-DbaRgWorkloadGroup -WhatIf:$checkMode -EnableException
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "present") {
+ if ($null -ne $existingWorkloadGroup) {
+ # Check for value parity
+ $diff = Compare-Object -ReferenceObject $existingWorkloadGroup -DifferenceObject $options -Property $compareProperty
+ # Set to new values
+ if ($null -ne $diff) {
+ $output = Set-DbaRgWorkloadGroup @options -WhatIf:$checkMode -EnableException
+ $module.Result.changed = $true
+ }
+ }
+ else {
+ # Create a new workload group
+ $output = New-DbaRgWorkloadGroup @options -WhatIf:$checkMode -EnableException
+ $module.Result.changed = $true
+ }
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Failed to configure workload group: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_workload_group.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_workload_group.py
new file mode 100644
index 00000000..21cf8261
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/rg_workload_group.py
@@ -0,0 +1,100 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: rg_workload_group
+short_description: Configures a workload group for use by the Resource Governor
+description:
+ - Creates or modifies a workload group to be used by the Resource Governor. Default values are handled by the Powershell functions themselves.
+version_added: 0.1.0
+options:
+ workload_group:
+ description:
+ - Name of the target workload group.
+ type: str
+ required: true
+ resource_pool:
+ description:
+ - Name of the resource pool for the workload group.
+ type: str
+ required: true
+ resource_pool_type:
+ description:
+ - Specify the type of resource pool.
+ type: str
+ required: false
+ default: 'Internal'
+ choices: ['Internal', 'External']
+ group_max_requests:
+ description:
+ - Specifies the maximum number of simultaneous requests that are allowed to execute in the workload group.
+ type: int
+ required: false
+ importance:
+ description:
+ - Specifies the relative importance of a request in the workload group.
+ type: str
+ required: false
+ choices: ['Low', 'Medium', 'High']
+ max_dop:
+ description:
+ - Specifies the maximum degree of parallelism (MAXDOP) for parallel query execution.
+ type: int
+ required: false
+ request_max_cpu_time:
+ description:
+ - Specifies the maximum amount of CPU time, in seconds, that a request can use.
+ type: int
+ required: false
+ request_max_mem_grant_perc:
+ description:
+ - Specifies the maximum amount of memory that a single request can take from the pool.
+ type: int
+ required: false
+ request_mem_grant_timeout_sec:
+ description:
+ - Specifies the maximum time, in seconds, that a query can wait for a memory grant (work buffer memory) to become available.
+ type: int
+ required: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Enable resource governor
+ lowlydba.sqlserver.resource_governor:
+ sql_instance: sql-01.myco.io
+ enabled: true
+
+- name: Create rg resource pool
+ lowlydba.sqlserver.rg_resource_pool:
+ sql_instance: sql-01.myco.io
+ resource_pool: "rpLittle"
+ max_cpu_perc: 5
+
+- name: Create rg workload group
+ lowlydba.sqlserver.rg_workload_group:
+ sql_instance: sql-01.myco.io
+ workload_group: rgMyGroup
+ resource_pool: rpLittle
+ resource_pool_type: Internal
+ max_dop: 2
+ state: present
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Set-DbaRgWorkloadGroup), C(New-DbaRgWorkloadGroup), or C(Remove-DbaRgWorkloadGroup) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/sa.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/sa.ps1
new file mode 100644
index 00000000..38042bc6
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/sa.ps1
@@ -0,0 +1,101 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ new_name = @{type = 'str'; required = $false; }
+ password = @{type = 'str'; required = $false; no_log = $true }
+ enabled = @{type = 'bool'; required = $false; default = $true }
+ password_must_change = @{type = 'bool'; required = $false }
+ password_policy_enforced = @{type = 'bool'; required = $false }
+ password_expiration_enabled = @{type = 'bool'; required = $false }
+ }
+}
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$newName = $module.Params.new_name
+if ($null -ne $module.Params.password) {
+ $secPassword = ConvertTo-SecureString -String $module.Params.password -AsPlainText -Force
+}
+$enabled = $module.Params.enabled
+[nullable[bool]]$passwordMustChange = $module.Params.password_must_change
+[nullable[bool]]$passwordExpirationEnabled = $module.Params.password_expiration_enabled
+[nullable[bool]]$passwordPolicyEnforced = $module.Params.password_policy_enforced
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+try {
+ $sa = Get-DbaLogin -SqlInstance $SqlInstance -SqlCredential $sqlCredential -EnableException | Where-Object ID -eq 1
+
+ $setLoginSplat = @{ }
+
+ if ($null -ne $newName) {
+ $setLoginSplat.Add("NewName", $newName)
+ if ($sa.Name -ne $newName) {
+ $changed = $true
+ }
+ }
+ if ($null -ne $passwordExpirationEnabled) {
+ if ($sa.PasswordExpirationEnabled -ne $passwordExpirationEnabled) {
+ $changed = $true
+ }
+ if ($passwordExpirationEnabled -eq $true) {
+ $setLoginSplat.add("PasswordExpirationEnabled", $true)
+ }
+ }
+ if ($null -ne $passwordPolicyEnforced) {
+ if ($sa.PasswordPolicyEnforced -ne $passwordPolicyEnforced) {
+ $changed = $true
+ }
+ if ($passwordPolicyEnforced -eq $true) {
+ $setLoginSplat.add("PasswordPolicyEnforced", $true)
+ }
+ }
+ if ($true -eq $passwordMustChange) {
+ if ($sa.PasswordMustChange -ne $passwordMustChange) {
+ $changed = $true
+ }
+ if ($passwordMustChange -eq $true) {
+ $setLoginSplat.add("PasswordMustChange", $true)
+ }
+ }
+ if ($null -ne $secPassword) {
+ $setLoginSplat.add("SecurePassword", $secPassword)
+ }
+ if ($enabled -eq $false) {
+ $disabled = $true
+ $setLoginSplat.add("Disable", $true)
+ }
+ else {
+ $disabled = $false
+ $setLoginSplat.add("Enable", $true)
+ }
+
+ # Check for changes
+ if (($changed -eq $true) -or ($disabled -ne $sa.IsDisabled) -or ($secPassword)) {
+ $output = $sa | Set-DbaLogin @setLoginSplat -WhatIf:$checkMode -EnableException
+ $module.Result.changed = $true
+ }
+ else {
+ $output = $sa
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.exitJson()
+}
+catch {
+ $module.FailJson("Configuring 'sa' login failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/sa.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/sa.py
new file mode 100644
index 00000000..6aa45fe3
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/sa.py
@@ -0,0 +1,74 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: sa
+short_description: Configure the C(sa) login for security best practices
+description:
+ - Rename, disable, and reset the password for the C(sa) login on a SQL Server instance per best practices.
+options:
+ password:
+ description:
+ - Password for the login.
+ type: str
+ required: false
+ new_name:
+ description:
+ - The new name to rename the C(sa) login to.
+ type: str
+ required: false
+ enabled:
+ description:
+ - Whether the login is enabled or disabled.
+ type: bool
+ required: false
+ default: true
+ version_added: '0.4.0'
+ password_must_change:
+ description:
+ - Enforces user must change password at next login.
+ - When specified, will enforce I(password_expiration_enabled) and I(password_policy_enforced) as they are required.
+ type: bool
+ required: false
+ password_policy_enforced:
+ description:
+ - Enforces password complexity policy.
+ type: bool
+ required: false
+ password_expiration_enabled:
+ description:
+ - Enforces password expiration policy. Requires I(password_policy_enforced=true).
+ type: bool
+ required: false
+version_added: 0.3.0
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Disable sa login
+ lowlydba.sqlserver.sa:
+ sql_instance: sql-01.myco.io
+ disable: true
+
+- name: Rename sa login
+ lowlydba.sqlserver.sa:
+ sql_instance: sql-01.myco.io
+ new_name: 'notthesayourelookingfor'
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Set-DbaLogin) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_configure.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_configure.ps1
new file mode 100644
index 00000000..f4ac80fd
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_configure.ps1
@@ -0,0 +1,59 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# (c) 2021, Sudhir Koduri (@kodurisudhir)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+# Get Csharp utility module
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ name = @{type = 'str'; required = $true }
+ value = @{type = 'int'; required = $true }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$name = $module.Params.name
+$value = $module.Params.value
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+try {
+ $existingConfig = Get-DbaSpConfigure -SqlInstance $sqlInstance -SqlCredential $sqlCredential -Name $name -EnableException
+
+ if ($existingConfig.ConfiguredValue -ne $value) {
+ $setSpConfigureSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Name = $name
+ Value = $value
+ WhatIf = $checkMode
+ EnableException = $true
+ }
+ $output = Set-DbaSpConfigure @setSpConfigureSplat
+
+ if ($existingConfig.IsDynamic -eq $false) {
+ $output | Add-Member -MemberType NoteProperty -Name "RestartRequired" -Value $true
+ }
+ $module.Result.changed = $true
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+
+catch {
+ $module.FailJson("sp_configure change failed.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_configure.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_configure.py
new file mode 100644
index 00000000..91e060e8
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_configure.py
@@ -0,0 +1,50 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# (c) 2021, Sudhir Koduri (@kodurisudhir)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: sp_configure
+short_description: Make instance level system configuration changes via C(sp_configure)
+description:
+ - Read instance level system configuration for a given configuration and update to a new value as provided.
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the configuration that will be changed.
+ type: str
+ required: true
+ value:
+ description:
+ - New value the configuration will be set to.
+ type: int
+ required: true
+author: "Sudhir Koduri (@kodurisudhir)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Enable remote DAC connection
+ lowlydba.sqlserver.sp_configure:
+ sql_instance: sql-01.myco.io
+ name: RemoteDacConnectionsEnabled
+ value: 1
+'''
+
+RETURN = r'''
+data:
+ description:
+ - Output from the C(Set-DbaSpConfigure) function.
+ - RestartRequired returned if the setting requires a service restart to take effect.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_whoisactive.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_whoisactive.ps1
new file mode 100644
index 00000000..45fc5ebd
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_whoisactive.ps1
@@ -0,0 +1,57 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+# Get Csharp utility module
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ database = @{type = 'str'; required = $true }
+ local_file = @{type = 'str'; required = $false }
+ force = @{type = 'bool'; required = $false; default = $false }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$database = $module.Params.database
+$localFile = $module.Params.local_file
+$force = $module.Params.force
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+$whoIsActiveSplat = @{
+ SqlInstance = $SqlInstance
+ SqlCredential = $SqlCredential
+ Database = $Database
+ WhatIf = $checkMode
+ Force = $force
+ Confirm = $false
+ EnableException = $true
+}
+if ($null -ne $LocalFile) {
+ $whoIsActiveSplat.LocalFile = $LocalFile
+}
+
+try {
+ $output = Install-DbaWhoIsActive @whoIsActiveSplat
+ $module.Result.changed = $true
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+
+catch {
+ $module.FailJson("Installing sp_WhoIsActive failed.", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_whoisactive.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_whoisactive.py
new file mode 100644
index 00000000..8aed1036
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/sp_whoisactive.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: sp_whoisactive
+short_description: Install/update C(sp_whoisactive) by Adam Mechanic
+description:
+ - A wrapper for C(Install-DbaWhoIsActive) to fetch the latest version of the script, or install from a local cached version.
+version_added: 0.1.0
+options:
+ local_file:
+ description:
+ - Specifies the path to a local file to install sp_WhoisActive from.
+ - This can be either the zip file as distributed by the website or the expanded SQL script.
+ - If this option is not specified, the latest version will be downloaded and installed from https://github.com/amachanic/sp_whoisactive/releases
+ type: str
+ required: false
+ database:
+ description:
+ - Name of the target database.
+ type: str
+ required: true
+ force:
+ description:
+ - If this switch is enabled, then C(sp_WhoisActive) will be downloaded from the internet even if previously cached.
+ type: bool
+ default: false
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Install/Update sp_whoisactive
+ lowlydba.sqlserver.sp_whoisactive:
+ sql_instance: sql-01.myco.io
+ database: lowlydb
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Install-DbaWhoIsActive) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/spn.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/spn.ps1
new file mode 100644
index 00000000..12c953bc
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/spn.ps1
@@ -0,0 +1,69 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# (c) 2021, Sudhir Koduri (@kodurisudhir)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ computer_username = @{ type = 'str'; required = $false }
+ computer_password = @{ type = 'str'; required = $false; no_log = $true; }
+ computer = @{ type = 'str'; required = $true }
+ service_account = @{ type = 'str'; required = $true; }
+ state = @{ type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+ required_together = @(
+ , @('computer_username', 'computer_password')
+ )
+}
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+if ($null -ne $module.Params.computer_username) {
+ [securestring]$secPassword = ConvertTo-SecureString $Module.Params.computer_password -AsPlainText -Force
+ [pscredential]$computerCredential = New-Object System.Management.Automation.PSCredential ($Module.Params.computer_username, $secPassword)
+}
+$computer = $module.Params.computer
+$serviceAccount = $module.Params.service_account
+$serviceClass = "MSSQLSvc"
+$spn = "$serviceClass\$computer"
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+try {
+ $existingSPN = Get-DbaSpn -ComputerName $computer -Credential $computerCredential -AccountName $serviceAccount | Where-Object spn -eq $spn
+
+ if ($state -eq "present") {
+ if ($null -ne $existingSPN) {
+ # SPNs can only be added and removed, not modified
+ $module.ExitJson()
+ }
+ elseif ($null -eq $existingSPN) {
+ $output = Set-DbaSpn -SPN $spn -ServiceAccount $serviceAccount -Credential $computerCredential
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($state -eq "absent") {
+ if ($null -ne $existingSPN) {
+ $output = Remove-DbaSpn -SPN $spn -ServiceAccount $serviceAccount -Credential $computerCredential
+ $module.Result.changed = $true
+ }
+ }
+
+ if ($output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Configuring SPN failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/spn.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/spn.py
new file mode 100644
index 00000000..0fabb934
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/spn.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: spn
+short_description: Configures SPNs for SQL Server
+description:
+ - Configures SPNs for SQL Server.
+version_added: 0.6.0
+options:
+ computer_username:
+ description:
+ - Username of a credential to connect to Active Directory with.
+ type: str
+ required: false
+ computer_password:
+ description:
+ - Password of a credential to connect to Active Directory with.
+ type: str
+ required: false
+ computer:
+ description:
+ - The host or alias to configure the SPN for. Can include the port in the format C(host:port).
+ type: str
+ required: true
+ service_account:
+ description:
+ - The account you want the SPN added to. Will be looked up if not provided.
+ type: str
+ required: true
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.state
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_win
+'''
+
+EXAMPLES = r'''
+- name: Add server SPN
+ lowlydba.sqlserver.spn:
+ computer: sql-01.myco.io
+ service_account: myco\sql-svc
+
+- name: Create an AG Listener
+ lowlydba.sqlserver.ag_listener:
+ sql_instance_primary: sql-01.myco.io
+ ag_name: AG_MyDatabase
+ listener_name: aglMyDatabase
+ ip_address: 10.0.20.20,10.1.77.77
+ subnet_ip: 255.255.252.0
+ subnet_mask: 255.255.255.0
+
+- name: Add SPN for new AG listener on port 1433
+ lowlydba.sqlserver.spn:
+ computer: aglMyDatabase.myco.io:1433
+ service_account: myco\sql-svc
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Set-DbaSpn) or C(Remove-DbaSpn) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/tcp_port.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/tcp_port.ps1
new file mode 100644
index 00000000..bff87bd9
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/tcp_port.ps1
@@ -0,0 +1,69 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# (c) 2021, Sudhir Koduri (@kodurisudhir)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+# Get Csharp utility module
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ username = @{type = 'str'; required = $false }
+ password = @{type = 'str'; required = $false; no_log = $true }
+ port = @{type = 'int'; required = $true }
+ ip_address = @{type = 'str'; required = $false }
+ force = @{type = 'bool'; required = $false; default = $false }
+ }
+ required_together = @(
+ , @('username', 'password')
+ )
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+if ($null -ne $module.Params.username) {
+ [securestring]$secPassword = ConvertTo-SecureString $Module.Params.password -AsPlainText -Force
+ [pscredential]$credential = New-Object System.Management.Automation.PSCredential ($Module.Params.username, $secPassword)
+}
+$port = $module.Params.port
+$ipAddress = $module.Params.ip_address
+$checkMode = $module.CheckMode
+$force = $module.Params.force
+$module.Result.changed = $false
+$PSDefaultParameterValues = @{ "*:EnableException" = $true; "*:Confirm" = $false; "*:WhatIf" = $checkMode }
+
+try {
+ $tcpPortSplat = @{
+ SqlInstance = $SqlInstance
+ Credential = $credential
+ Port = $port
+ Force = $force
+ }
+ if ($ipAddress) {
+ $tcpPortSplat.Add("IPAddress", $ipAddress)
+ }
+ $output = Set-DbaTcpPort @tcpPortSplat
+
+ if ($output.Changes.Count -gt 0 -or $checkMode) {
+ $module.Result.changed = $true
+ if ($force -ne $true) {
+ $output | Add-Member -MemberType NoteProperty -Name "RestartRequired" -Value $true
+ }
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Configuring TCP port failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/tcp_port.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/tcp_port.py
new file mode 100644
index 00000000..f97013f8
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/tcp_port.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: tcp_port
+short_description: Sets the TCP port for the instance
+description:
+ - Sets the TCP port for a SQL Server instance.
+version_added: 0.10.0
+options:
+ username:
+ description:
+ - Username for alternative credential to authenticate with Windows.
+ type: str
+ required: false
+ password:
+ description:
+ - Password for alternative credential to authenticate with Windows.
+ type: str
+ required: false
+ port:
+ description:
+ - Port for SQL Server to listen on.
+ type: int
+ required: true
+ ip_address:
+ description:
+ - IPv4 address.
+ type: str
+ required: false
+ force:
+ description:
+ - Restart SQL Server and SQL Agent services automatically.
+ type: bool
+ required: false
+ default: false
+ version_added: 1.2.0
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_win
+'''
+
+EXAMPLES = r'''
+- name: Set the default port
+ lowlydba.sqlserver.tcp_port:
+ sql_instance: sql-01.myco.io
+ port: 1433
+
+- name: Set a non-standard default port
+ lowlydba.sqlserver.tcp_port:
+ sql_instance: sql-01.myco.io
+ port: 1933
+'''
+
+RETURN = r'''
+data:
+ description:
+ - Output from the C(Set-DbaTcpPort) function.
+ - RestartRequired returned if the change requires a service restart to take effect.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/traceflag.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/traceflag.ps1
new file mode 100644
index 00000000..9e0a1434
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/traceflag.ps1
@@ -0,0 +1,67 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# (c) 2021, Sudhir Koduri (@kodurisudhir)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+# Get Csharp utility module
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ trace_flag = @{type = 'int'; required = $true }
+ enabled = @{type = 'bool'; required = $true }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$traceFlag = $module.Params.trace_flag
+$enabled = $module.Params.enabled
+$checkMode = $module.CheckMode
+$module.Result.changed = $false
+
+try {
+ $traceFlagSplat = @{
+ SqlInstance = $SqlInstance
+ SqlCredential = $sqlCredential
+ TraceFlag = $traceFlag
+ EnableException = $true
+ }
+ $existingFlag = Get-DbaTraceFlag @traceFlagSplat
+
+ if ($enabled -eq $true) {
+ if (-not $checkMode) {
+ $enabled = Enable-DbaTraceFlag @traceFlagSplat
+ $output = $enabled | Select-Object -Property InstanceName, SqlInstance, TraceFlag
+ }
+ if ($existingFlag.TraceFlag -notcontains $traceFlag) {
+ $module.Result.changed = $true
+ }
+ }
+ elseif ($enabled -eq $false) {
+
+ if (-not $checkMode) {
+ $disabled = Disable-DbaTraceFlag @traceFlagSplat
+ $output = $disabled | Select-Object -Property InstanceName, SqlInstance, TraceFlag
+ }
+ if ($existingFlag.TraceFlag -contains $traceFlag) {
+ $module.Result.changed = $true
+ }
+ }
+
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Configuring trace flag failed: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/traceflag.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/traceflag.py
new file mode 100644
index 00000000..c8139e51
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/traceflag.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# (c) 2021, Sudhir Koduri (@kodurisudhir)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: traceflag
+short_description: Enable or disable global trace flags on a SQL Server instance
+description:
+ - Enable\Disable global trace flag on a SQL Instance. This trace flag takes affect immediately and does not require SQL Instance restart.
+ - This setting does not persist after restart.
+version_added: 0.1.0
+options:
+ trace_flag:
+ description:
+ - Trace Flag number.
+ type: int
+ required: true
+ enabled:
+ description:
+ - Flag to enable or disable the trace flag.
+ type: bool
+ required: true
+author: "Sudhir Koduri (@kodurisudhir)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+'''
+
+EXAMPLES = r'''
+- name: Eliminate successful backup information from SQL Error Log
+ lowlydba.sqlserver.traceflag:
+ sql_instance: sql-01.myco.io
+ trace_flag: 3226
+ enabled: true
+
+- name: Disable trace flag
+ lowlydba.sqlserver.traceflag:
+ sql_instance: sql-01.myco.io
+ trace_flag: 3226
+ enabled: false
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(Enable-DbaTraceFlag) or C(Disable-DbaTraceFlag) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/user.ps1 b/ansible_collections/lowlydba/sqlserver/plugins/modules/user.ps1
new file mode 100644
index 00000000..29bbd69b
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/user.ps1
@@ -0,0 +1,142 @@
+#!powershell
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -PowerShell ansible_collections.lowlydba.sqlserver.plugins.module_utils._SqlServerUtils
+#Requires -Modules @{ ModuleName="dbatools"; ModuleVersion="1.1.112" }
+
+$ErrorActionPreference = "Stop"
+
+$spec = @{
+ supports_check_mode = $true
+ options = @{
+ login = @{type = 'str'; required = $true }
+ database = @{type = 'str'; required = $true }
+ username = @{type = 'str'; required = $true }
+ default_schema = @{type = 'str'; required = $false ; default = 'dbo' }
+ external_provider = @{type = 'bool'; required = $false }
+ state = @{type = 'str'; required = $false; default = 'present'; choices = @('present', 'absent') }
+ }
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec, @(Get-LowlyDbaSqlServerAuthSpec))
+$sqlInstance, $sqlCredential = Get-SqlCredential -Module $module
+$login = $module.Params.login
+$username = $module.Params.username
+$database = $module.Params.database
+$defaultSchema = $module.Params.default_schema
+[nullable[bool]]$externalProvider = $module.Params.external_provider
+$state = $module.Params.state
+$checkMode = $module.CheckMode
+
+$module.Result.changed = $false
+
+$getUserSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ User = $username
+ Login = $login
+ Database = $database
+ EnableException = $true
+}
+$existingUser = Get-DbaDbUser @getUserSplat
+
+if ($state -eq "absent") {
+ if ($null -ne $existingUser) {
+ try {
+ $removeUserSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ User = $username
+ Database = $database
+ EnableException = $true
+ WhatIf = $checkMode
+ Force = $true
+ Confirm = $false
+ }
+ $output = Remove-DbaDbUser @removeUserSplat
+ $module.Result.changed = $true
+ }
+ catch {
+ $module.FailJson("Removing user failed: $($_.Exception.Message)", $_)
+ }
+ }
+}
+elseif ($state -eq "present") {
+ # User exists
+ if ($null -ne $existingUser) {
+ if ($defaultSchema -ne $existingUser.DefaultSchema) {
+ try {
+ # No Set-DbaDbUser command exists, use SMO
+ $getSchemaSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Database = $database
+ Schema = $defaultSchema
+ IncludeSystemDatabases = $true
+ IncludeSystemSchemas = $true
+ EnableException = $true
+ }
+ $existingSchema = Get-DbaDbSchema @getSchemaSplat
+
+ if ($null -ne $existingSchema) {
+ # do schema change
+ if (-not($checkMode)) {
+ $existingUser.DefaultSchema = $defaultSchema
+ $existingUser.Alter()
+ $output = $existingUser
+ }
+ $module.result.changed = $true
+ }
+ else {
+ $module.FailJson("Schema '$defaultSchema' not found in [$database].")
+ }
+ }
+ catch {
+ $module.FailJson("Configuring user failed: $($_.Exception.Message)", $_)
+ }
+ }
+ }
+ # New User
+ else {
+ try {
+ $newUserSplat = @{
+ SqlInstance = $sqlInstance
+ SqlCredential = $sqlCredential
+ Username = $username
+ Login = $login
+ Database = $database
+ DefaultSchema = $defaultSchema
+ EnableException = $true
+ WhatIf = $checkMode
+ Force = $true
+ Confirm = $false
+ }
+ if ($externalProvider -eq $true) {
+ $newUserSplat.add("ExternalProvider", $true)
+ }
+ $output = New-DbaDbUser @newUserSplat
+ $module.result.changed = $true
+ }
+ catch {
+ $module.FailJson("Creating user failed: $($_.Exception.Message)", $_)
+ }
+ }
+ # If not in check mode, add extra fields we can change to default display set
+ if ($null -ne $output) {
+ $output.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Add("DefaultSchema")
+ }
+}
+try {
+ if ($null -ne $output) {
+ $resultData = ConvertTo-SerializableObject -InputObject $output
+ $module.Result.data = $resultData
+ }
+ $module.ExitJson()
+}
+catch {
+ $module.FailJson("Failure: $($_.Exception.Message)", $_)
+}
diff --git a/ansible_collections/lowlydba/sqlserver/plugins/modules/user.py b/ansible_collections/lowlydba/sqlserver/plugins/modules/user.py
new file mode 100644
index 00000000..b9c36d06
--- /dev/null
+++ b/ansible_collections/lowlydba/sqlserver/plugins/modules/user.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2022, John McCall (@lowlydba)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r'''
+---
+module: user
+short_description: Configures a user within a database
+description:
+ - Creates, modifies, or removes a user in a database.
+version_added: 1.1.0
+options:
+ login:
+ description:
+ - Name of the login that the user is mapped to.
+ type: str
+ required: true
+ database:
+ description:
+ - Database for the user.
+ type: str
+ required: true
+ username:
+ description:
+ - Name of the user.
+ type: str
+ required: true
+ external_provider:
+ description:
+ - Specifies that the user is for Azure AD Authentication. Only used when creating a new user, this cannot be modified for an existing user.
+ type: bool
+ required: false
+ default_schema:
+ description:
+ - The default database schema for the user.
+ type: str
+ required: false
+ default: "dbo"
+author: "John McCall (@lowlydba)"
+requirements:
+ - L(dbatools,https://www.powershellgallery.com/packages/dbatools/) PowerShell module
+extends_documentation_fragment:
+ - lowlydba.sqlserver.sql_credentials
+ - lowlydba.sqlserver.attributes.check_mode
+ - lowlydba.sqlserver.attributes.platform_all
+ - lowlydba.sqlserver.state
+'''
+
+EXAMPLES = r'''
+- name: Create a user
+ lowlydba.sqlserver.user:
+ sql_instance: sql-01.myco.io
+ login: TheIntern
+ username: TheIntern
+ database: InternProject1
+
+- name: Change user's schema
+ lowlydba.sqlserver.login:
+ sql_instance: sql-01.myco.io
+ login: TheIntern
+ username: TheIntern
+ database: InternProject1
+ default_schema: dev
+
+- name: Remove a user
+ lowlydba.sqlserver.login:
+ sql_instance: sql-01.myco.io
+ login: TheIntern
+ username: TheIntern
+ database: InternProject1
+ state: absent
+'''
+
+RETURN = r'''
+data:
+ description: Output from the C(New-DbaDbUser), C(Get-DbaDbUser), or C(Remove-DbaDbUser) function.
+ returned: success, but not in check_mode.
+ type: dict
+'''