Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invoke-query updated to allow smo object #1380

Merged
merged 6 commits into from
Jun 30, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Unreleased

- Changes to common module: Invoke-Query
- Fixes issues in [issue #1355](https://github.com/PowerShell/SqlServerDsc/issues/1355)
- Works together with Connect-SQL now
- Parameters and Aliases now match that of Connect-SQL
- Can now pass in credentials
- Can now pass in 'Microsoft.SqlServer.Management.Smo.Server' object
- Can also pipe in 'Microsoft.SqlServer.Management.Smo.Server' object
- Can pipe Connect-SQL | Invoke-Query
- Added default vaules to Invoke-Query

## 13.0.0.0

- Changes to SqlServerDsc
Expand Down
89 changes: 72 additions & 17 deletions Modules/SqlServerDsc.Common/SqlServerDsc.Common.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -1569,47 +1569,69 @@ function Restart-ReportingServicesService
}
}


<#
.SYNOPSIS
Executes a query on the specified database.
Executes a query on the specified database.

.PARAMETER SQLServer
The hostname of the server that hosts the SQL instance.
The hostname of the server that hosts the SQL instance.

.PARAMETER SQLInstanceName
The name of the SQL instance that hosts the database.
The name of the SQL instance that hosts the database.

.PARAMETER Database
Specify the name of the database to execute the query on.
Specify the name of the database to execute the query on.

.PARAMETER Query
The query string to execute.
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 allowing you to use connect-sql | invoke-query if you wish.

.PARAMETER WithResults
Specifies if the query should return results.
Specifies if the query should return results.

.PARAMETER StatementTimeout
Set the query StatementTimeout in seconds. Default 600 seconds (10mins).
Set the query StatementTimeout in seconds. Default 600 seconds (10mins).

.EXAMPLE
Invoke-Query -SQLServer Server1 -SQLInstanceName MSSQLSERVER -Database master `
-Query 'SELECT name FROM sys.databases' -WithResults

.EXAMPLE
Invoke-Query -SQLServer Server1 -SQLInstanceName MSSQLSERVER -Database master -Query 'SELECT name FROM sys.databases' -WithResults
Invoke-Query -SQLServer Server1 -SQLInstanceName MSSQLSERVER -Database master `
-Query 'RESTORE DATABASE [NorthWinds] WITH RECOVERY'

.EXAMPLE
Invoke-Query -SQLServer Server1 -SQLInstanceName MSSQLSERVER -Database master -Query 'RESTORE DATABASE [NorthWinds] WITH RECOVERY'
Connect-SQL @sqlConnectionParameters | Invoke-Query -Database master `
-Query 'SELECT name FROM sys.databases' -WithResults
#>
function Invoke-Query
{
[CmdletBinding()]
[CmdletBinding(DefaultParameterSetName='SqlServer')]
param
(
[Parameter(Mandatory = $true)]
[Alias("ServerName")]
[Parameter(ParameterSetName='SqlServer')]
[ValidateNotNullOrEmpty()]
[System.String]
$SQLServer,
$SQLServer = $env:COMPUTERNAME,

[Parameter(Mandatory = $true)]
[Alias("InstanceName")]
[Parameter(ParameterSetName='SqlServer')]
[System.String]
$SQLInstanceName,
$SQLInstanceName = 'MSSQLSERVER',

[Parameter(Mandatory = $true)]
[System.String]
Expand All @@ -1619,19 +1641,52 @@ function Invoke-Query
[System.String]
$Query,

[Alias("SetupCredential")]
[Parameter()]
[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
)

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

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

$serverObject = Connect-SQL @connectSQLParameters
}

if ( $WithResults )
if ($WithResults)
{
try
{
Expand Down
177 changes: 132 additions & 45 deletions Tests/Unit/SqlServerDsc.Common.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1390,46 +1390,55 @@ InModuleScope 'SqlServerDsc.Common' {
BeforeAll {
$mockExpectedQuery = ''

$mockConnectSql = {
return @(
(
New-Object -TypeName PSObject -Property @{
Databases = @{
'master' = (
New-Object -TypeName PSObject -Property @{ Name = 'master' } |
Add-Member -MemberType ScriptMethod -Name ExecuteNonQuery -Value {
param
(
[Parameter()]
[System.String]
$sqlCommand
)

if ( $sqlCommand -ne $mockExpectedQuery )
{
throw
}
} -PassThru |
Add-Member -MemberType ScriptMethod -Name ExecuteWithResults -Value {
param
(
[Parameter()]
[System.String]
$sqlCommand
)

if ( $sqlCommand -ne $mockExpectedQuery )
{
throw
}

return New-Object -TypeName System.Data.DataSet
} -PassThru
)
}
}
)
$mockSetupCredentialUserName = 'TestUserName12345'
$mockSetupCredentialPassword = 'StrongOne7.'
$mockSetupCredentialSecurePassword = ConvertTo-SecureString -String $mockSetupCredentialPassword -AsPlainText -Force
$mockSetupCredential = New-Object -TypeName PSCredential -ArgumentList ($mockSetupCredentialUserName, $mockSetupCredentialSecurePassword)

$masterDatabaseObject = New-Object -TypeName PSObject
$masterDatabaseObject | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'master'
$masterDatabaseObject | Add-Member -MemberType ScriptMethod -Name 'ExecuteNonQuery' -Value {
param
(
[Parameter()]
[System.String]
$sqlCommand
)

if ( $sqlCommand -ne $mockExpectedQuery )
{
throw
}
}

$masterDatabaseObject | Add-Member -MemberType ScriptMethod -Name 'ExecuteWithResults' -Value {
param
(
[Parameter()]
[System.String]
$sqlCommand
)

if ( $sqlCommand -ne $mockExpectedQuery )
{
throw
}

return New-Object -TypeName System.Data.DataSet
}

$databasesObject = New-Object -TypeName PSObject
$databasesObject | Add-Member -MemberType NoteProperty -Name 'Databases' -Value @{
'master' = $masterDatabaseObject
}

$mockSMOServer = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server'
$mockSMOServer | Add-Member -MemberType NoteProperty -Name 'Databases' -Value @{
'master' = $masterDatabaseObject
} -Force

$mockConnectSql = {
return @($databasesObject)
}

$mockThrowLocalizedMessage = {
Expand All @@ -1443,10 +1452,17 @@ InModuleScope 'SqlServerDsc.Common' {
}

$queryParams = @{
SQLServer = 'Server1'
SQLInstanceName = 'MSSQLSERVER'
Database = 'master'
Query = ''
SQLServer = 'Server1'
SQLInstanceName = 'MSSQLSERVER'
Database = 'master'
Query = ''
DatabaseCredential = $mockSetupCredential
}

$queryParametersWithSMO = @{
Query = ''
SqlServerObject = $mockSMOServer
Database = 'master'
}

Context 'Execute a query with no results' {
Expand All @@ -1462,7 +1478,9 @@ InModuleScope 'SqlServerDsc.Common' {
It 'Should throw the correct error, ExecuteNonQueryFailed, when executing the query fails' {
$queryParams.Query = 'BadQuery'

{ Invoke-Query @queryParams } | Should -Throw ($script:localizedData.ExecuteNonQueryFailed -f $queryParams.Database)
{ Invoke-Query @queryParams } | Should -Throw (
$script:localizedData.ExecuteNonQueryFailed -f $queryParams.Database
)

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
}
Expand All @@ -1481,11 +1499,80 @@ InModuleScope 'SqlServerDsc.Common' {
It 'Should throw the correct error, ExecuteQueryWithResultsFailed, when executing the query fails' {
$queryParams.Query = 'BadQuery'

{ Invoke-Query @queryParams -WithResults } | Should -Throw ($script:localizedData.ExecuteQueryWithResultsFailed -f $queryParams.Database)
{ Invoke-Query @queryParams -WithResults } | Should -Throw (
$script:localizedData.ExecuteQueryWithResultsFailed -f $queryParams.Database
)

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
}
}

Context 'Pass in an SMO Server Object' {
Context 'Execute a query with no results' {
It 'Should execute the query silently' {
$queryParametersWithSMO.Query = "EXEC sp_configure 'show advanced option', '1'"
$mockExpectedQuery = $queryParametersWithSMO.Query.Clone()

{ Invoke-Query @queryParametersWithSMO } | Should -Not -Throw

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 0 -Exactly
}

It 'Should throw the correct error, ExecuteNonQueryFailed, when executing the query fails' {
$queryParametersWithSMO.Query = 'BadQuery'

{ Invoke-Query @queryParametersWithSMO } | Should -Throw (
$script:localizedData.ExecuteNonQueryFailed -f $queryParams.Database
)

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 0 -Exactly
}
}

Context 'Execute a query with results' {
It 'Should execute the query and return a result set' {
$queryParametersWithSMO.Query = 'SELECT name FROM sys.databases'
$mockExpectedQuery = $queryParametersWithSMO.Query.Clone()

Invoke-Query @queryParametersWithSMO -WithResults | Should -Not -BeNullOrEmpty

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 0 -Exactly
}

It 'Should throw the correct error, ExecuteQueryWithResultsFailed, when executing the query fails' {
$queryParametersWithSMO.Query = 'BadQuery'

{ Invoke-Query @queryParametersWithSMO -WithResults } | Should -Throw (
$script:localizedData.ExecuteQueryWithResultsFailed -f $queryParams.Database
)

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 0 -Exactly
}
}

Context 'Execute a query with piped SMO server object' {
It 'Should execute the query and return a result set' {
$mockQuery = 'SELECT name FROM sys.databases'
$mockExpectedQuery = $mockQuery

$mockSMOServer | Invoke-Query -Query $mockQuery -Database master -WithResults |
Should -Not -BeNullOrEmpty

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 0 -Exactly
}

It 'Should throw the correct error, ExecuteQueryWithResultsFailed, when executing the query fails' {
$mockQuery = 'BadQuery'

{ $mockSMOServer | Invoke-Query -Query $mockQuery -Database master -WithResults } |
Should -Throw (
$script:localizedData.ExecuteQueryWithResultsFailed -f $queryParams.Database
)

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 0 -Exactly
}
}
}
}

Describe 'SqlServerDsc.Common\Update-AvailabilityGroupReplica' -Tag 'UpdateAvailabilityGroupReplica' {
Expand Down