Skip to content

Commit

Permalink
SqlServerDsc.Common: Removed the function Invoke-Query (#1906)
Browse files Browse the repository at this point in the history
- SqlServerDsc.Common
  - Removed the function `Invoke-Query`. It is replaced by the command
    `Invoke-SqlDscQuery` (issue #1902).
- SqlServerDsc
  - New public command:
    - `Disconnect-SqlDscDatabaseEngine` - Disconnects from a SQL Server instance
      that was previously connected to using `Connect-SqlDscDatabaseEngine`.
  - New private command:
    - `ConvertTo-RedactedText` - Used to redact sensitive information from
      text that then can be used in console output like verbose messages.
  • Loading branch information
johlju authored Apr 12, 2023
1 parent a7e634e commit 2ea2c07
Show file tree
Hide file tree
Showing 28 changed files with 1,045 additions and 795 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Remove

- SqlServerDsc.Common
- Removed the function `Invoke-Query`. It is replaced by the command
`Invoke-SqlDscQuery` ([issue #1902](https://github.com/dsccommunity/SqlServerDsc/issues/1902)).

### Added

- SqlServerDsc
- New public command:
- `Disconnect-SqlDscDatabaseEngine` - Disconnects from a SQL Server instance
that was previously connected to using `Connect-SqlDscDatabaseEngine`.
- New private command:
- `ConvertTo-RedactedText` - Used to redact sensitive information from
text that then can be used in console output like verbose messages.

## [16.2.0] - 2023-04-10

### Added
Expand Down
6 changes: 3 additions & 3 deletions source/DSCResources/DSC_SqlAGDatabase/DSC_SqlAGDatabase.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ function Set-TargetResource
foreach ( $databaseFileDirectory in $databaseFileDirectories )
{
$fileExistsQuery = "EXEC master.dbo.xp_fileexist '$databaseFileDirectory'"
$fileExistsResult = Invoke-Query -ServerName $currentAvailabilityGroupReplicaServerObject.NetName -InstanceName $currentAvailabilityGroupReplicaServerObject.ServiceName -Database master -Query $fileExistsQuery -WithResults
$fileExistsResult = Invoke-SqlDscQuery -ServerName $currentAvailabilityGroupReplicaServerObject.NetName -InstanceName $currentAvailabilityGroupReplicaServerObject.ServiceName -DatabaseName 'master' -Query $fileExistsQuery -PassThru

if ( $fileExistsResult.Tables.Rows.'File is a Directory' -ne 1 )
{
Expand Down Expand Up @@ -600,8 +600,8 @@ function Set-TargetResource
if ( $availabilityGroupReplica.SeedingMode -eq 'MANUAL')
{
# Restore the database
Invoke-Query -ServerName $currentAvailabilityGroupReplicaServerObject.NetName -InstanceName $currentAvailabilityGroupReplicaServerObject.ServiceName -Database master -Query $restoreDatabaseQueryString -StatementTimeout $StatementTimeout
Invoke-Query -ServerName $currentAvailabilityGroupReplicaServerObject.NetName -InstanceName $currentAvailabilityGroupReplicaServerObject.ServiceName -Database master -Query $restoreLogQueryString -StatementTimeout $StatementTimeout
Invoke-SqlDscQuery -ServerName $currentAvailabilityGroupReplicaServerObject.NetName -InstanceName $currentAvailabilityGroupReplicaServerObject.ServiceName -DatabaseName 'master' -Query $restoreDatabaseQueryString -StatementTimeout $StatementTimeout
Invoke-SqlDscQuery -ServerName $currentAvailabilityGroupReplicaServerObject.NetName -InstanceName $currentAvailabilityGroupReplicaServerObject.ServiceName -DatabaseName 'master' -Query $restoreLogQueryString -StatementTimeout $StatementTimeout
}

# Add the database to the Availability Group
Expand Down
22 changes: 11 additions & 11 deletions source/DSCResources/DSC_SqlDatabaseUser/DSC_SqlDatabaseUser.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,11 @@ function Set-TargetResource
# Get-TargetResource will also help us to test if the database exist.
$getTargetResourceResult = Get-TargetResource @getTargetResourceParameters

# Default parameters for the cmdlet Invoke-Query used throughout.
$invokeQueryParameters = @{
ServerName = $ServerName
InstanceName = $InstanceName
Database = $DatabaseName
# Default parameters for the cmdlet Invoke-SqlDscQuery used throughout.
$invokeSqlDscQueryParameters = @{
ServerName = $ServerName
InstanceName = $InstanceName
DatabaseName = $DatabaseName
}

$recreateDatabaseUser = $false
Expand Down Expand Up @@ -262,7 +262,7 @@ function Set-TargetResource
See remarks section in this article:
https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-user-transact-sql#remarks
#>
Invoke-Query @invokeQueryParameters -Query (
Invoke-SqlDscQuery @invokeSqlDscQueryParameters -Query (
'ALTER USER [{0}] WITH NAME = [{1}], LOGIN = [{2}];' -f $Name, $Name, $LoginName
)
}
Expand Down Expand Up @@ -338,7 +338,7 @@ function Set-TargetResource
$script:localizedData.DropDatabaseUser -f $Name, $DatabaseName
)

Invoke-Query @invokeQueryParameters -Query (
Invoke-SqlDscQuery @invokeSqlDscQueryParameters -Query (
'DROP USER [{0}];' -f $Name
)
}
Expand Down Expand Up @@ -376,14 +376,14 @@ function Set-TargetResource
# Assert that the login exist.
Assert-SqlLogin @assertSqlLoginParameters

Invoke-Query @invokeQueryParameters -Query (
Invoke-SqlDscQuery @invokeSqlDscQueryParameters -Query (
'CREATE USER [{0}] FOR LOGIN [{1}];' -f $Name, $LoginName
)
}

'NoLogin'
{
Invoke-Query @invokeQueryParameters -Query (
Invoke-SqlDscQuery @invokeSqlDscQueryParameters -Query (
'CREATE USER [{0}] WITHOUT LOGIN;' -f $Name
)
}
Expand All @@ -393,7 +393,7 @@ function Set-TargetResource
# Assert that the asymmetric key exist.
Assert-DatabaseAsymmetricKey @PSBoundParameters

Invoke-Query @invokeQueryParameters -Query (
Invoke-SqlDscQuery @invokeSqlDscQueryParameters -Query (
'CREATE USER [{0}] FOR ASYMMETRIC KEY [{1}];' -f $Name, $AsymmetricKeyName
)
}
Expand All @@ -403,7 +403,7 @@ function Set-TargetResource
# Assert that the certificate exist.
Assert-DatabaseCertificate @PSBoundParameters

Invoke-Query @invokeQueryParameters -Query (
Invoke-SqlDscQuery @invokeSqlDscQueryParameters -Query (
'CREATE USER [{0}] FOR CERTIFICATE [{1}];' -f $Name, $CertificateName
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
'Get-SqlInstanceMajorVersion'
'Restart-SqlService'
'Restart-ReportingServicesService'
'Invoke-Query'
'Update-AvailabilityGroupReplica'
'Test-LoginEffectivePermissions'
'Test-AvailabilityReplicaSeedingModeAutomatic'
Expand Down
207 changes: 8 additions & 199 deletions source/Modules/SqlServerDsc.Common/SqlServerDsc.Common.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -1266,197 +1266,6 @@ function Restart-ReportingServicesService
}
}


<#
.SYNOPSIS
Executes a query on the specified database.
.PARAMETER ServerName
The hostname of the server that hosts the SQL instance.
.PARAMETER InstanceName
The name of the SQL instance that hosts the database.
.PARAMETER Database
Specify the name of the database to execute the query on.
.PARAMETER Query
The query string to execute.
.PARAMETER DatabaseCredential
PSCredential object with the credentials to use to impersonate a user
when connecting. If this is not provided then the current user will be
used to connect to the SQL Server Database Engine instance.
.PARAMETER LoginType
Specifies which type of logon credential should be used. The valid types are
Integrated, WindowsUser, and SqlLogin. If WindowsUser or SqlLogin are specified
then the SetupCredential needs to be specified as well.
.PARAMETER SqlServerObject
You can pass in an object type of 'Microsoft.SqlServer.Management.Smo.Server'.
This can also be passed in through the pipeline. See examples.
.PARAMETER WithResults
Specifies if the query should return results.
.PARAMETER StatementTimeout
Set the query StatementTimeout in seconds. Default 600 seconds (10mins).
.PARAMETER RedactText
One or more strings to redact from the query when verbose messages are
written to the console. Strings here will be escaped so they will not
be interpreted as regular expressions (RegEx).
.EXAMPLE
Invoke-Query -ServerName Server1 -InstanceName MSSQLSERVER -Database master `
-Query 'SELECT name FROM sys.databases' -WithResults
.EXAMPLE
Invoke-Query -ServerName Server1 -InstanceName MSSQLSERVER -Database master `
-Query 'RESTORE DATABASE [NorthWinds] WITH RECOVERY'
.EXAMPLE
Connect-SQL @sqlConnectionParameters | Invoke-Query -Database master `
-Query 'SELECT name FROM sys.databases' -WithResults
.EXAMPLE
Invoke-Query -ServerName Server1 -InstanceName MSSQLSERVER -Database MyDatabase `
-Query "select * from MyTable where password = 'PlaceholderPa\ssw0rd1' and password = 'placeholder secret passphrase'" `
-WithResults -RedactText @('PlaceholderPa\sSw0rd1','Placeholder Secret PassPhrase') -Verbose
.NOTES
The script analyzer rule UseSyntacticallyCorrectExamples will fail in VS Code
on this function unless the SMO types are loaded (either the real ones or the
stubs). When the rule is run in the pipeline the test will load the SMO stub
classes for proper testing of the rule.
#>
function Invoke-Query
{
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when the output type is not available. The ScriptAnalyzer rule UseSyntacticallyCorrectExamples will always error in the editor due to https://github.com/indented-automation/Indented.ScriptAnalyzerRules/issues/8.')]
[CmdletBinding(DefaultParameterSetName = 'SqlServer')]
param
(
[Parameter(ParameterSetName = 'SqlServer')]
[ValidateNotNullOrEmpty()]
[System.String]
$ServerName = (Get-ComputerName),

[Parameter(ParameterSetName = 'SqlServer')]
[System.String]
$InstanceName = 'MSSQLSERVER',

[Parameter(Mandatory = $true)]
[System.String]
$Database,

[Parameter(Mandatory = $true)]
[System.String]
$Query,

[Parameter()]
[Alias('SetupCredential')]
[System.Management.Automation.PSCredential]
$DatabaseCredential,

[Parameter()]
[ValidateSet('Integrated', 'WindowsUser', 'SqlLogin')]
[System.String]
$LoginType = 'Integrated',

[Parameter(ValueFromPipeline, ParameterSetName = 'SqlObject', Mandatory = $true)]
[ValidateNotNull()]
[Microsoft.SqlServer.Management.Smo.Server]
$SqlServerObject,

[Parameter()]
[Switch]
$WithResults,

[Parameter()]
[ValidateNotNull()]
[System.Int32]
$StatementTimeout = 600,

[Parameter()]
[System.String[]]
$RedactText
)

if ($PSCmdlet.ParameterSetName -eq 'SqlObject')
{
$serverObject = $SqlServerObject
}
elseif ($PSCmdlet.ParameterSetName -eq 'SqlServer')
{
$connectSQLParameters = @{
ServerName = $ServerName
InstanceName = $InstanceName
StatementTimeout = $StatementTimeout
}

if ($LoginType -ne 'Integrated')
{
$connectSQLParameters['LoginType'] = $LoginType
}

if ($PSBoundParameters.ContainsKey('DatabaseCredential'))
{
$connectSQLParameters.SetupCredential = $DatabaseCredential
}

$serverObject = Connect-SQL @connectSQLParameters -ErrorAction 'Stop'
}

$redactedQuery = $Query

foreach ($redactString in $RedactText)
{
<#
Escaping the string to handle strings which could look like
regular expressions, like passwords.
#>
$escapedRedactedString = [System.Text.RegularExpressions.Regex]::Escape($redactString)

$redactedQuery = $redactedQuery -ireplace $escapedRedactedString, '*******'
}

if ($WithResults)
{
try
{
Write-Verbose -Message (
$script:localizedData.ExecuteQueryWithResults -f $redactedQuery
) -Verbose

$result = $serverObject.Databases[$Database].ExecuteWithResults($Query)
}
catch
{
$errorMessage = $script:localizedData.ExecuteQueryWithResultsFailed -f $Database
New-InvalidOperationException -Message $errorMessage -ErrorRecord $_
}
}
else
{
try
{
Write-Verbose -Message (
$script:localizedData.ExecuteNonQuery -f $redactedQuery
) -Verbose

$serverObject.Databases[$Database].ExecuteNonQuery($Query)
}
catch
{
$errorMessage = $script:localizedData.ExecuteNonQueryFailed -f $Database
New-InvalidOperationException -Message $errorMessage -ErrorRecord $_
}
}

return $result
}

<#
.SYNOPSIS
Executes the alter method on an Availability Group Replica object.
Expand Down Expand Up @@ -1564,11 +1373,11 @@ function Test-LoginEffectivePermissions
# Assume the permissions are not present
$permissionsPresent = $false

$invokeQueryParameters = @{
$invokeSqlDscQueryParameters = @{
ServerName = $ServerName
InstanceName = $InstanceName
Database = 'master'
WithResults = $true
DatabaseName = 'master'
PassThru = $true
}

if ( [System.String]::IsNullOrEmpty($SecurableName) )
Expand All @@ -1592,7 +1401,7 @@ function Test-LoginEffectivePermissions

Write-Verbose -Message ($script:localizedData.GetEffectivePermissionForLogin -f $LoginName, $InstanceName) -Verbose

$loginEffectivePermissionsResult = Invoke-Query @invokeQueryParameters -Query $queryToGetEffectivePermissionsForLogin
$loginEffectivePermissionsResult = Invoke-SqlDscQuery @invokeSqlDscQueryParameters -Query $queryToGetEffectivePermissionsForLogin
$loginEffectivePermissions = $loginEffectivePermissionsResult.Tables.Rows.permission_name

if ( $null -ne $loginEffectivePermissions )
Expand Down Expand Up @@ -1658,11 +1467,11 @@ function Test-AvailabilityReplicaSeedingModeAutomatic
# Only check the seeding mode if this is SQL 2016 or newer
if ( $serverObject.Version -ge 13 )
{
$invokeQueryParams = @{
$invokeSqlDscQueryParameters = @{
ServerName = $ServerName
InstanceName = $InstanceName
Database = 'master'
WithResults = $true
DatabaseName = 'master'
PassThru = $true
}

$queryToGetSeedingMode = "
Expand All @@ -1672,7 +1481,7 @@ function Test-AvailabilityReplicaSeedingModeAutomatic
WHERE ag.name = '$AvailabilityGroupName'
AND ar.replica_server_name = '$AvailabilityReplicaName'
"
$seedingModeResults = Invoke-Query @invokeQueryParams -Query $queryToGetSeedingMode
$seedingModeResults = Invoke-SqlDscQuery @invokeSqlDscQueryParameters -Query $queryToGetSeedingMode
$seedingMode = $seedingModeResults.Tables.Rows.seeding_mode_desc

if ( $seedingMode -eq 'Automatic' )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ ConvertFrom-StringData @'
StartingDependentService = Starting service '{0}'. (SQLCOMMON0042)
WaitingInstanceTimeout = Waiting for instance {0}\\{1} to report status online, with a timeout value of {2} seconds. (SQLCOMMON0043)
FailedToConnectToInstanceTimeout = Failed to connect to the instance {0}\\{1} within the timeout period of {2} seconds. (SQLCOMMON0044)
ExecuteQueryWithResultsFailed = Executing query with results failed on database '{0}'. (SQLCOMMON0045)
ExecuteNonQueryFailed = Executing non-query failed on database '{0}'. (SQLCOMMON0046)
AlterAvailabilityGroupReplicaFailed = Failed to alter the availability group replica '{0}'. (SQLCOMMON0047)
GetEffectivePermissionForLogin = Getting the effective permissions for the login '{0}' on '{1}'. (SQLCOMMON0048)
ClusterPermissionsMissing = The cluster does not have permissions to manage the Availability Group on '{0}\\{1}'. Grant 'Connect SQL', 'Alter Any Availability Group', and 'View Server State' to either 'NT SERVICE\\ClusSvc' or 'NT AUTHORITY\\SYSTEM'. (SQLCOMMON0049)
Expand All @@ -40,8 +38,6 @@ ConvertFrom-StringData @'
ClusterLoginPermissionsPresent = The cluster login '{0}' has the required permissions. (SQLCOMMON0053)
ConnectingUsingIntegrated = Connecting as current user '{0}' using integrated security. (SQLCOMMON0054)
ConnectingUsingImpersonation = Impersonate credential '{0}' with login type '{1}'. (SQLCOMMON0056)
ExecuteQueryWithResults = Returning the results of the query `{0}`. (SQLCOMMON0057)
ExecuteNonQuery = Executing the query `{0}`. (SQLCOMMON0058)
ClusterResourceNotFoundOrOffline = The SQL Server cluster resource '{0}' was not found or the resource has been taken offline. (SQLCOMMON0066)
NotOwnerOfClusterResource = The node '{0}' is not the owner of the cluster resource '{1}'. The owner is '{2}' so no restart is needed. (SQLCOMMON0067)
LoadedAssembly = Loaded the assembly '{0}'. (SQLCOMMON0068)
Expand Down
Loading

0 comments on commit 2ea2c07

Please sign in to comment.