Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added public command `Invoke-SqlDscScalarQuery` to execute scalar queries using
`Server.ConnectionContext.ExecuteScalar()`. Server-level, lightweight execution
that does not require any database to be online
([issue #2423](https://github.com/dsccommunity/SqlServerDsc/issues/2423)).
- Added public command `Get-SqlDscDateTime` to retrieve current date and time from
SQL Server instance. Supports multiple T-SQL date/time functions to eliminate
clock-skew and timezone issues between client and server
([issue #2423](https://github.com/dsccommunity/SqlServerDsc/issues/2423)).
Comment thread
johlju marked this conversation as resolved.
- Added public command `Backup-SqlDscDatabase` to perform database backups using
SMO's `Microsoft.SqlServer.Management.Smo.Backup` class. Supports full,
differential, and transaction log backups with options for compression,
Expand Down
2 changes: 2 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ stages:
'tests/Integration/Commands/Connect-SqlDscDatabaseEngine.Integration.Tests.ps1'
'tests/Integration/Commands/Disconnect-SqlDscDatabaseEngine.Integration.Tests.ps1'
'tests/Integration/Commands/Invoke-SqlDscQuery.Integration.Tests.ps1'
'tests/Integration/Commands/Invoke-SqlDscScalarQuery.Integration.Tests.ps1'
'tests/Integration/Commands/Get-SqlDscDateTime.Integration.Tests.ps1'
# Group 4
'tests/Integration/Commands/Assert-SqlDscLogin.Integration.Tests.ps1'
'tests/Integration/Commands/New-SqlDscLogin.Integration.Tests.ps1'
Expand Down
126 changes: 126 additions & 0 deletions source/Public/Get-SqlDscDateTime.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<#
.SYNOPSIS
Retrieves the current date and time from a SQL Server instance.

.DESCRIPTION
Retrieves the current date and time from a SQL Server instance using the
specified T-SQL date/time function. This command helps eliminate clock-skew
and timezone issues when coordinating time-sensitive operations between the
client and SQL Server.

The command queries SQL Server using the server connection context, which
does not require any database to be online.

.PARAMETER ServerObject
Specifies current server connection object.

.PARAMETER DateTimeFunction
Specifies which T-SQL date/time function to use for retrieving the date and time.
Valid values are:
- `SYSDATETIME` (default): Returns datetime2(7) with server local time
- `SYSDATETIMEOFFSET`: Returns datetimeoffset(7) with server local time and timezone offset
- `SYSUTCDATETIME`: Returns datetime2(7) with UTC time
- `GETDATE`: Returns datetime with server local time
- `GETUTCDATE`: Returns datetime with UTC time

.PARAMETER StatementTimeout
Specifies the query StatementTimeout in seconds. Default 600 seconds (10 minutes).

.INPUTS
`Microsoft.SqlServer.Management.Smo.Server`

Accepts input via the pipeline.

.OUTPUTS
`System.DateTime`

Returns the current date and time from the SQL Server instance.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine
Get-SqlDscDateTime -ServerObject $serverObject

Connects to the default instance and retrieves the current date and time
using the default SYSDATETIME function.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine
$serverObject | Get-SqlDscDateTime -DateTimeFunction 'SYSUTCDATETIME'

Connects to the default instance and retrieves the current UTC date and time
from the SQL Server instance.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine
$serverTime = Get-SqlDscDateTime -ServerObject $serverObject
Restore-SqlDscDatabase -ServerObject $serverObject -Name 'MyDatabase' -StopAt $serverTime.AddHours(-1)

Demonstrates using the server's clock for a point-in-time restore operation,
avoiding clock skew issues between client and server.
#>
function Get-SqlDscDateTime
{
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when a parameter 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.')]
[OutputType([System.DateTime])]
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[Microsoft.SqlServer.Management.Smo.Server]
$ServerObject,

[Parameter()]
[ValidateSet('SYSDATETIME', 'SYSDATETIMEOFFSET', 'SYSUTCDATETIME', 'GETDATE', 'GETUTCDATE')]
[System.String]
$DateTimeFunction = 'SYSDATETIME',

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

process
{
Write-Verbose -Message (
$script:localizedData.Get_SqlDscDateTime_RetrievingDateTime -f $DateTimeFunction
)

$query = "SELECT $DateTimeFunction()"

$invokeSqlDscScalarQueryParameters = @{
ServerObject = $ServerObject
Query = $query
StatementTimeout = $StatementTimeout
ErrorAction = 'Stop'
Verbose = $VerbosePreference
}

try
{
$result = Invoke-SqlDscScalarQuery @invokeSqlDscScalarQueryParameters

# Convert the result to DateTime if it's a DateTimeOffset
if ($result -is [System.DateTimeOffset])
{
$result = $result.DateTime
}

return $result
}
catch
{
$writeErrorParameters = @{
Message = $script:localizedData.Get_SqlDscDateTime_FailedToRetrieve -f $DateTimeFunction, $_.Exception.Message
Category = 'InvalidOperation'
ErrorId = 'GSDD0001' # cSpell: disable-line
TargetObject = $DateTimeFunction
Exception = $_.Exception
}

Write-Error @writeErrorParameters

return
}
}
}
134 changes: 134 additions & 0 deletions source/Public/Invoke-SqlDscScalarQuery.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<#
.SYNOPSIS
Executes a scalar query on the specified server.

.DESCRIPTION
Executes a scalar query on the specified server using the server connection
context. This command is designed for queries that return a single value,
such as `SELECT @@VERSION` or `SELECT SYSDATETIME()`.

The command uses `Server.ConnectionContext.ExecuteScalar()` which is
server-level and does not require any database to be online.

.PARAMETER ServerObject
Specifies current server connection object.

.PARAMETER Query
Specifies the scalar query string to execute.

.PARAMETER StatementTimeout
Specifies the query StatementTimeout in seconds. Default 600 seconds (10 minutes).

.PARAMETER RedactText
Specifies one or more text strings to redact from the query when verbose messages
are written to the console. Strings will be escaped so they will not
be interpreted as regular expressions (RegEx).

.INPUTS
`Microsoft.SqlServer.Management.Smo.Server`

Accepts input via the pipeline.

.OUTPUTS
`System.Object`

Returns the scalar value returned by the query.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine
Invoke-SqlDscScalarQuery -ServerObject $serverObject -Query 'SELECT @@VERSION'

Connects to the default instance and then runs a query to return the SQL Server version.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine
$serverObject | Invoke-SqlDscScalarQuery -Query 'SELECT SYSDATETIME()'

Connects to the default instance and then runs the query to return the current
date and time from the SQL Server instance.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine
Invoke-SqlDscScalarQuery -ServerObject $serverObject -Query "SELECT name FROM sys.databases WHERE name = 'MyPassword123'" -RedactText @('MyPassword123') -Verbose

Shows how to redact sensitive information in the query when the query string
is output as verbose information when the parameter Verbose is used.
#>
function Invoke-SqlDscScalarQuery
{
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when a parameter 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.')]
[OutputType([System.Object])]
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[Microsoft.SqlServer.Management.Smo.Server]
$ServerObject,

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

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

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

process
{
$redactedQuery = $Query

if ($PSBoundParameters.ContainsKey('RedactText'))
{
$redactedQuery = ConvertTo-RedactedText -Text $Query -RedactPhrase $RedactText
}

Write-Verbose -Message (
$script:localizedData.Invoke_SqlDscScalarQuery_ExecutingQuery -f $redactedQuery
)

$previousStatementTimeout = $null

if ($PSBoundParameters.ContainsKey('StatementTimeout'))
{
# Make sure we can return the StatementTimeout before exiting.
$previousStatementTimeout = $ServerObject.ConnectionContext.StatementTimeout

$ServerObject.ConnectionContext.StatementTimeout = $StatementTimeout
}

try
{
$result = $ServerObject.ConnectionContext.ExecuteScalar($Query)

return $result
}
catch
{
$writeErrorParameters = @{
Message = $script:localizedData.Invoke_SqlDscScalarQuery_FailedToExecute -f $_.Exception.Message
Category = 'InvalidOperation'
ErrorId = 'ISDSQ0002' # cSpell: disable-line
TargetObject = $redactedQuery
Exception = $_.Exception
}

Write-Error @writeErrorParameters

return
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
finally
{
if ($null -ne $previousStatementTimeout)
{
$ServerObject.ConnectionContext.StatementTimeout = $previousStatementTimeout
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
8 changes: 8 additions & 0 deletions source/en-US/SqlServerDsc.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -632,4 +632,12 @@ ConvertFrom-StringData @'
Get_SqlDscSetupLog_Header = ==== SQL Server Setup {0} (from {1}) ==== (GSDSL0004)
Get_SqlDscSetupLog_Footer = ==== End of {0} ==== (GSDSL0005)
Get_SqlDscSetupLog_PathNotFound = Path '{0}' does not exist. (GSDSL0006)

## Invoke-SqlDscScalarQuery
Invoke_SqlDscScalarQuery_ExecutingQuery = Executing the scalar query `{0}`. (ISDSQ0001)
Invoke_SqlDscScalarQuery_FailedToExecute = Failed to execute scalar query: {0} (ISDSQ0002)

## Get-SqlDscDateTime
Get_SqlDscDateTime_RetrievingDateTime = Retrieving date and time using {0}(). (GSDD0001)
Get_SqlDscDateTime_FailedToRetrieve = Failed to retrieve date and time using {0}(): {1} (GSDD0002)
'@
Loading
Loading