From cfe957f3ffb96f4788250b91369b39067bfd00c1 Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Tue, 21 Jun 2016 23:16:36 -0400 Subject: [PATCH 01/11] Added xSQLServerScript resource --- .../MSFT_xSQLServerScript.Schema.mof | 14 ++ .../MSFT_xSQLServerScript.psm1 | 158 ++++++++++++++++++ Examples/SQLServerScript.ps1 | 28 ++++ README.md | 13 ++ Tests/Unit/MSFT_xSQLServerScript.Test.ps1 | 136 +++++++++++++++ 5 files changed, 349 insertions(+) create mode 100644 DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.Schema.mof create mode 100644 DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 create mode 100644 Examples/SQLServerScript.ps1 create mode 100644 Tests/Unit/MSFT_xSQLServerScript.Test.ps1 diff --git a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.Schema.mof b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.Schema.mof new file mode 100644 index 000000000..6ef00995f --- /dev/null +++ b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.Schema.mof @@ -0,0 +1,14 @@ + +[ClassVersion("1.0.0.0"), FriendlyName("xSQLServerScript")] +class MSFT_xSQLServerScript : OMI_BaseResource +{ + [Required, Description("The name of an instance of the Database Engine. For default instances, only specify the computer name. For named instances, use the format ComputerName\\InstanceName")] String ServerInstance; + [Key, Description("Path to SQL file that will perform Set action.")] String SetFilePath; + [Key, Description("Path to SQL file that will perform Get action.")] String GetFilePath; + [Key, Description("Path to SQL file that will perform Test action.")] String TestFilePath; + [Write, Description("Specifies the login ID for making a SQL Server Authentication connection to an instance of the Database Engine.")] String Username; + [Write, Description("Specifies the password for the SQL Server Authentication login ID that was specified in -Username.")] String Password; + [Write, Description("Creates a sqlcmd scripting variable for use in the sqlcmd script, and sets a value for the variable.")] String Variable[]; + [Read, Description("Result of Get action.")] String GetResult[]; +}; + diff --git a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 new file mode 100644 index 000000000..fab464641 --- /dev/null +++ b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 @@ -0,0 +1,158 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [parameter(Mandatory = $true)] + [System.String] + $ServerInstance, + + [parameter(Mandatory = $true)] + [System.String] + $SetFilePath, + + [parameter(Mandatory = $true)] + [System.String] + $GetFilePath, + + [parameter(Mandatory = $true)] + [System.String] + $TestFilePath, + + [System.String] + $Username, + + [System.String] + $Password, + + [System.String[]] + $Variable + ) + + Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop + + $null = $PSBoundParameters.Remove("SetFilePath") + $null = $PSBoundParameters.Remove("GetFilePath") + $null = $PSBoundParameters.Remove("TestFilePath") + + $result = Invoke-Sqlcmd -InputFile $getFilePath @PSBoundParameters -ErrorAction Stop + + $getResult = Out-String -InputObject $result + + $returnValue = @{ + ServerInstance = [System.String]$ServerInstance + SetFilePath = [System.String]$SetFilePath + GetFilePath = [System.String]$GetFilePath + TestFilePath = [System.String]$TestFilePath + Username = [System.String]$Username + Password = [System.String]$Password + Variable = [System.String[]]$Variable + GetResult = [System.String[]]$getresult + } + + $returnValue +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [parameter(Mandatory = $true)] + [System.String] + $ServerInstance, + + [parameter(Mandatory = $true)] + [System.String] + $SetFilePath, + + [parameter(Mandatory = $true)] + [System.String] + $GetFilePath, + + [parameter(Mandatory = $true)] + [System.String] + $TestFilePath, + + [System.String] + $Username, + + [System.String] + $Password, + + [System.String[]] + $Variable + ) + + Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop + + $null = $PSBoundParameters.Remove("SetFilePath") + $null = $PSBoundParameters.Remove("GetFilePath") + $null = $PSBoundParameters.Remove("TestFilePath") + + Invoke-Sqlcmd -InputFile $setFilePath @PSBoundParameters -ErrorAction Stop +} + + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [parameter(Mandatory = $true)] + [System.String] + $ServerInstance, + + [parameter(Mandatory = $true)] + [System.String] + $SetFilePath, + + [parameter(Mandatory = $true)] + [System.String] + $GetFilePath, + + [parameter(Mandatory = $true)] + [System.String] + $TestFilePath, + + [System.String] + $Username, + + [System.String] + $Password, + + [System.String[]] + $Variable + ) + + Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop + + try + { + $null = $PSBoundParameters.Remove("SetFilePath") + $null = $PSBoundParameters.Remove("GetFilePath") + $null = $PSBoundParameters.Remove("TestFilePath") + + $result = Invoke-Sqlcmd -InputFile $testFilePath @PSBoundParameters -ErrorAction stop + + if($result -eq $null) + { + return $true + } + else + { + return $false + } + } + catch + { + Write-Verbose $_ + return $false + } +} + + +Export-ModuleMember -Function *-TargetResource + diff --git a/Examples/SQLServerScript.ps1 b/Examples/SQLServerScript.ps1 new file mode 100644 index 000000000..922470347 --- /dev/null +++ b/Examples/SQLServerScript.ps1 @@ -0,0 +1,28 @@ +configuration SQLSettings +{ + Import-DscResource -ModuleName 'xSQLServer' + + Node 'localhost' + { + xSQLServerScript SqlSettings + { + ServerInstance = "$env:COMPUTERNAME\SMA" + SetFilePath = "C:\temp\Set-SQlsettings.sql" + TestFilePath = "C:\temp\Test-SQlsettings.sql" + GetFilePath = "C:\temp\Get-SQlsettings.sql" + Variable = @("FilePath=C:\temp\log\AuditFiles") + } + } +} + +$configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + } + ) +} + +SQLSettings -ConfigurationData $configData + +Start-DscConfiguration -Path .\SQLSettings -Wait -Force -Verbose diff --git a/README.md b/README.md index b6aaadd02..84139f193 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **xSQLServerMaxDop** resource to manage MaxDegree of Parallism for SQL Server * **xSQLServerMemory** resource to manage Memory for SQL Server * **xSQLServerPowerPlan** resource to manage windows powerplan on SQL Server +* **xSQLServerScript** resource to extend DSCs Get/Set/Test functionality to T-SQL ### xSQLServerSetup @@ -209,10 +210,22 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **TCPPort**: Custom TCP port. * **RestartService**: If true will restart SQL Service instance service after update. Default false. +###xSQLServerScript +* **ServerInstance**: (Required) The name of an instance of the Database Engine. For default instances, only specify the computer name. For named instances, use the format ComputerName\\InstanceName. +* **SetFilePath**: (Key) Path to SQL file that will perform Set action. +* **GetFilePath**: (Key) Path to SQL file that will perform Get action. SQL Queries returned by this function are returned by the Get-DscConfiguration cmdlet with the GetResult parameter. +* **TestFilePath**: (Key) Path to SQL file that will perform Test action. Any Script that does not throw an error and returns null is evaluated to true. Invoke-SqlCmd treats SQL Print statements as verbose text, this will not cause a the Test to return false. +* **Username**: Specifies the login ID for making a SQL Server Authentication connection to an instance of the Database Engine. +* **Password**: Specifies the password for the SQL Server Authentication login ID that was specified in Username. +* **Variable**: Creates a sqlcmd scripting variable for use in the sqlcmd script, and sets a value for the variable. +* **GetResult**: Result of Get action. + ## Versions ### Unreleased +* Added xSQLServerScript resource + ### 1.4.0.0 * Resources Added diff --git a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 new file mode 100644 index 000000000..d75ede1e5 --- /dev/null +++ b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 @@ -0,0 +1,136 @@ +<# +.Synopsis + Automated unit test for RPS_TSQL DSC Resource +#> + + +# TODO: Customize these parameters... +$Global:DSCModuleName = 'MSFT_xSQLServerScript' # Example xNetworking +$Global:DSCResourceName = 'MSFT_xSQLServerScript' # Example MSFT_xFirewall +# /TODO + +#region HEADER +# Unit Test Template Version: 1.1.0 +[String] $moduleRoot = Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $Script:MyInvocation.MyCommand.Path)) +if ( (-not (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` + (-not (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) +{ + & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $moduleRoot -ChildPath '\DSCResource.Tests\')) +} + +Import-Module (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force +$TestEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $Global:DSCModuleName ` + -DSCResourceName $Global:DSCResourceName ` + -TestType Unit +#endregion HEADER + +# Begin Testing +try +{ + InModuleScope $Global:DSCResourceName { + #region Pester Test Initialization + Function GLobal:Invoke-SqlCmd {} + #endregion Pester Test Initialization + + #region Function Get-TargetResource + Describe "$($Global:DSCResourceName)\Get-TargetResource" { + It "Should throw if SQLPS module cannot be found" { + $throwMessage = "Failed to find module" + + Mock -CommandName Import-Module -MockWith { Throw $throwMessage } + + { Get-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage + } + + It "Should throw if Invoke-SqlCmd throws" { + $throwMessage = "Failed to run SQL Script" + + Mock -CommandName Import-Module -MockWith {} + Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } + + { Get-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage + } + + It "Should return a hashtable if the Get SQL script returns" { + Mock -CommandName Import-Module -MockWith {} + Mock -CommandName Invoke-SqlCmd -MockWith { "" } + + $result = Get-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" + + $result.ServerInstance | should be $env:COMPUTERNAME + $result.SetFilePath | should be "set.sql" + $result.GetFilePath | should be "get.sql" + $result.TestFilePath | should be "test.sql" + $result.GetType() | should be "hashtable" + } + } + #endregion Function Get-TargetResource + + + #region Function Test-TargetResource + Describe "$($Global:DSCResourceName)\Test-TargetResource" { + It "Should throw if SQLPS module cannot be found" { + $throwMessage = "Failed to find module" + + Mock -CommandName Import-Module -MockWith { Throw $throwMessage } + + { Test-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage + } + + It "Should return false if Invoke-SqlCmd throws" { + $throwMessage = "Failed to run SQL Script" + + Mock -CommandName Import-Module -MockWith {} + Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } + + Test-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" | should be $false + } + + It "Should return true if Invoke-SqlCmd returns null" { + Mock -CommandName Import-Module -MockWith {} + Mock -CommandName Invoke-SqlCmd -MockWith {} + + Test-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" | should be $true + } + } + #endregion Function Test-TargetResource + + + #region Function Set-TargetResource + Describe "$($Global:DSCResourceName)\Set-TargetResource" { + It "Should throw if SQLPS module cannot be found" { + $throwMessage = "Failed to find module" + + Mock -CommandName Import-Module -MockWith { Throw $throwMessage } + + { Set-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage + } + + It "Should throw if Invoke-SqlCmd throws" { + $throwMessage = "Failed to run SQL Script" + + Mock -CommandName Import-Module -MockWith {} + Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } + + { Set-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage + } + + It "Should always attempt to execute Invoke-SqlCmd" { + Mock -CommandName Import-Module -MockWith {} + Mock -CommandName Invoke-SqlCmd -MockWith {} -Verifiable + + $result = Set-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" + + Assert-MockCalled -CommandName Invoke-SqlCmd -Times 1 + } + } + #endregion Function Set-TargetResource + } +} +finally +{ + #region FOOTER + Restore-TestEnvironment -TestEnvironment $TestEnvironment + #endregion +} From f8a8f927757137e77dfbbf845ed5705b148e8b60 Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Tue, 21 Jun 2016 23:43:08 -0400 Subject: [PATCH 02/11] README merged this time --- README.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 116 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 84139f193..e6171c105 100644 --- a/README.md +++ b/README.md @@ -20,19 +20,26 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **xSQLServerDatabasePermissions** resource to manage SQL database permissions * **xSQLServerDatabaseOwner** resource to manage SQL database owners * **xSQLDatabaseRecoveryModel** resource to manage database recovery model -* **xSQLServerMaxDop** resource to manage MaxDegree of Parallism for SQL Server +* **xSQLServerMaxDop** resource to manage MaxDegree of Parallelism for SQL Server * **xSQLServerMemory** resource to manage Memory for SQL Server * **xSQLServerPowerPlan** resource to manage windows powerplan on SQL Server +* **xSQLServerNetwork** resource to manage SQL Server Network Protocols +* **xSQLServerDatabase** resource to manage ensure database is present or absent +* **xSQLAOGroupEnsure** resource to ensure availability group is present or absent +* **xSQLAOGroupJoin** resource to join a replica to an existing availability group +* **xSQLServerAlwaysOnService** resource to enable always on on a SQL Server +* **xSQLServerEndpoint** resource to ensure database endpoint is present or absent +* **xWaitForAvailabilityGroup** resource to wait till availability group is created on primary server +* **xSQLServerConfiguration** resource to manage [SQL Server Configuration Options](https://msdn.microsoft.com/en-us/library/ms189631.aspx) * **xSQLServerScript** resource to extend DSCs Get/Set/Test functionality to T-SQL - ### xSQLServerSetup * **SourcePath**: (Required) UNC path to the root of the source files for installation. * **SourceFolder**: Folder within the source path containing the source files for installation. * **SetupCredential**: (Required) Credential to be used to perform the installation. * **SourceCredential**: Credential used to access SourcePath -* **SuppressReboot**: Supresses reboot +* **SuppressReboot**: Suppresses reboot * **ForceReboot**: Forces Reboot * **Features**: (Key) SQL features to be installed. * **InstanceName**: (Key) SQL instance to be installed. @@ -63,7 +70,7 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **FTSvcAccountUsername**: Output username for the Full Text service. * **RSSvcAccount**: Service account for Reporting Services service. * **RSSvcAccountUsername**: Output username for the Reporting Services service. -* **ASSvcAccount**: Service account for Analysus Services service. +* **ASSvcAccount**: Service account for Analysis Services service. * **ASSvcAccountUsername**: Output username for the Analysis Services service. * **ASCollation**: Collation for Analysis Services. * **ASSysAdminAccounts**: Array of accounts to be made Analysis Services admins. @@ -101,7 +108,7 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **SourceFolder**: Folder within the source path containing the source files for installation. * **SetupCredential**: (Required) Credential to be used to perform the installation. * **SourceCredential**: Credential to be used to access SourcePath -* **SuppressReboot**: Supresses reboot +* **SuppressReboot**: Suppresses reboot * **ForceReboot**: Forces Reboot * **Features**: (Required) SQL features to be installed. * **InstanceName**: (Key) SQL instance to be installed. @@ -210,6 +217,56 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **TCPPort**: Custom TCP port. * **RestartService**: If true will restart SQL Service instance service after update. Default false. +###xSQLServerDatabase +* **Database**: (key) Database to be created or dropped +* **Ensure**: An enumerated value that describes if Database is to be present or absent. +* **SQLServer**: The SQL Server for the database +* **SQLInstance**: The SQL instance for the database + +###xSQLAOGroupEnsure +* **Ensure**: (key) An enumerated value that describes if Availability Group is to be present or absent. +* **AvailabilityGroupName** (key) Name for availability group +* **AvailabilityGroupNameListener** Listener name for availability group +* **AvailabilityGroupNameIP** List of IP addresses associated with listener +* **AvailabilityGroupSubMask** Network subnetmask for listener +* **AvailabilityGroupPort** Port availability group should listen on +* **ReadableSecondary** Mode secondaries should operate under (None, ReadOnly, ReadIntent) +* **AutoBackupPreference** Where backups should be backed up from (Primary,Secondary) +* **SQLServer**: The SQL Server for the database +* **SQLInstance**: The SQL instance for the database +* **SetupCredential**: (Required) Credential to be used to Grant Permissions on SQL Server + +###xSQLServerAOJoin +* **Ensure**: (key) An enumerated value that describes if Replica is to be present or absent from availability group +* **AvailabilityGroupName** (key) Name for availability group +* **SQLServer**: The SQL Server for the database +* **SQLInstance**: The SQL instance for the database +* **SetupCredential**: (Required) Credential to be used to Grant Permissions on SQL Server + +###xSQLServerAlwaysOnService +* **Ensure**: (key) An enumerated value that describes if SQL server should have AlwaysOn property present or absent. +* **SQLServer**: The SQL Server for the database +* **SQLInstance**: The SQL instance for the database + +###xSQLServerEndpoint +* **EndPointName**: Name for endpoint to be created on SQL Server +* **Ensure**: (key) An enumerated value that describes if endpoint is to be present or absent on SQL Server +* **Port**: Port Endpoint should listen on +* **AuthorizedUser**: User who should have connect ability to endpoint +* **SQLServer**: The SQL Server for the database +* **SQLInstance**: The SQL instance for the database + +###xWaitforAvailabilityGroup +* **Name**: (key) Name for availability group +* **RetryIntervalSec**: Interval to check for availability group +* **RetryCount**: Maximum number of retries to check availability group creation + +###xSQLServerConfiguration +* **InstanceName**: (Key) name of SQL Server instance for which configuration options will be configured. +* **OptionName**: (Key) SQL Server option name. For all possible values reference [MSDN](https://msdn.microsoft.com/en-us/library/ms189631.aspx) or run sp_configure. +* **OptionValue**: (Required) SQL Server option value to be set. +* **RestartService**: Default false. If true will restart SQL Service instance service after update. + ###xSQLServerScript * **ServerInstance**: (Required) The name of an instance of the Database Engine. For default instances, only specify the computer name. For named instances, use the format ComputerName\\InstanceName. * **SetFilePath**: (Key) Path to SQL file that will perform Set action. @@ -223,13 +280,57 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ## Versions ### Unreleased +* Resources Added + - xSQLServerConfiguration + - xSQLServerScript + +### 1.6.0.0 -* Added xSQLServerScript resource +* Resources Added + - xSQLAOGroupEnsure + - xSQLAOGroupJoin + - xWaitForAvailabilityGroup + - xSQLServerEndPoint + - xSQLServerAlwaysOnService +* xSQLServerHelper + - added functions + - Connect-SQL + - New-VerboseMessage + - Grant-ServerPerms + - Grant-CNOPerms + - New-ListenerADObject +* xSQLDatabaseRecoveryModel + - Updated Verbose statements to use new function New-VerboseMessage +* xSQLServerDatabase + - Updated Verbose statements to use new function New-VerboseMessage + - Removed ConnectSQL function and replaced with new Connect-SQL function +* xSQLServerDatabaseOwner + - Removed ConnectSQL function and replaced with new Connect-SQL function +* xSQLServerDatabasePermissions + - Removed ConnectSQL function and replaced with new Connect-SQL function +* xSQLServerDatabaseRole + - Removed ConnectSQL function and replaced with new Connect-SQL function +* xSQLServerLogin + - Removed ConnectSQL function and replaced with new Connect-SQL function +* xSQLServerMaxDop + - Updated Verbose statements to use new function New-VerboseMessage + - Removed ConnectSQL function and replaced with new Connect-SQL function +* xSQLServerMemory + - Updated Verbose statements to use new function New-VerboseMessage + - Removed ConnectSQL function and replaced with new Connect-SQL function +* xSQLServerPowerPlan + - Updated Verbose statements to use new function New-VerboseMessage +* Examples + - Added xSQLServerConfiguration resource example + +### 1.5.0.0 + +* Added new resource xSQLServerDatabase that allows adding an empty database to a server ### 1.4.0.0 * Resources Added - - xSQLDatabaseReoveryModeAdded + - xSQLDatabaseRecoveryModeAdded - xSQLServerDatabaseOwner - xSQLServerDatabasePermissions - xSQLServerDatabaseRole @@ -237,16 +338,18 @@ Please check out common DSC Resources [contributing guidelines](https://github.c - xSQLServerMaxDop - xSQLServerMemory - xSQLServerPowerPlan + - xSQLServerDatabase * xSQLServerSetup: - Corrected bug in GetFirstItemPropertyValue to correctly handle registry keys with only one value. - - Added support for SQL Server 2008 R2 installation + - Added support for SQL Server + - 2008 R2 installation - Removed default values for parameters, to avoid compatibility issues and setup errors - Added Replication sub feature detection - Added setup parameter BrowserSvcStartupType - Change SourceFolder to Source to allow for multiversion Support - Add Source Credential for accessing source files - - Add Paramaters for SQL Server configuration - - Add Paramaters to SuppressReboot or ForceReboot + - Add Parameters for SQL Server configuration + - Add Parameters to SuppressReboot or ForceReboot * xSQLServerFirewall - Removed default values for parameters, to avoid compatibility issues - Updated firewall rule name to not use 2012 version, since package supports 2008, 2012 and 2014 versions @@ -259,12 +362,11 @@ Please check out common DSC Resources [contributing guidelines](https://github.c - Allows to set custom or dynamic port values * xSQLServerRSSecureConnectionLevel - Additional of SQLHelper Function and error handling -* xSQLServerRSConfig - - Additional of SQLHelper Function and error handling +* xSqlServerRSConfig * xSQLServerFailoverClusterSetup - Additional of SQLHelper Function and error handling - Change SourceFolder to Source to allow for multiversion Support - - Add Paramaters to SuppressReboot or ForceReboot + - Add Parameters to SuppressReboot or ForceReboot * Examples - Updated example files to use correct DebugMode parameter value ForceModuleImport, this is not boolean in WMF 5.0 RTM - Added xSQLServerNetwork example @@ -294,3 +396,4 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ## Examples Examples for use of this resource can be found with the System Center resources, such as **xSCVMM**, **xSCSMA**, and **xSCOM**. + From ab4de07ea4e683fae0b2776a8ef9d444ce1f898c Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Thu, 28 Jul 2016 20:49:54 -0700 Subject: [PATCH 03/11] Updated xSqlServerScript to use PSCredential object --- .../MSFT_xSQLServerScript.Schema.mof | 3 +- .../MSFT_xSQLServerScript.psm1 | 47 ++++++++++++------- README.md | 2 + 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.Schema.mof b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.Schema.mof index 6ef00995f..e7c9ab6af 100644 --- a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.Schema.mof +++ b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.Schema.mof @@ -6,8 +6,7 @@ class MSFT_xSQLServerScript : OMI_BaseResource [Key, Description("Path to SQL file that will perform Set action.")] String SetFilePath; [Key, Description("Path to SQL file that will perform Get action.")] String GetFilePath; [Key, Description("Path to SQL file that will perform Test action.")] String TestFilePath; - [Write, Description("Specifies the login ID for making a SQL Server Authentication connection to an instance of the Database Engine.")] String Username; - [Write, Description("Specifies the password for the SQL Server Authentication login ID that was specified in -Username.")] String Password; + [Write, EmbeddedInstance("MSFT_Credential"), Description("Credential to be used to run SQL scripts.")] String Credential; [Write, Description("Creates a sqlcmd scripting variable for use in the sqlcmd script, and sets a value for the variable.")] String Variable[]; [Read, Description("Result of Get action.")] String GetResult[]; }; diff --git a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 index fab464641..0b00d9d3a 100644 --- a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 +++ b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 @@ -20,11 +20,8 @@ [System.String] $TestFilePath, - [System.String] - $Username, - - [System.String] - $Password, + [System.Management.Automation.PSCredential] + $Credential, [System.String[]] $Variable @@ -32,6 +29,14 @@ Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop + if($null -ne $Credential) + { + $null = $PSBoundParameters.Add("Username", $Credential.UserName) + $null = $PSBoundParameters.Add("Password", $Credential.GetNetworkCredential().password) + + $null = $PSBoundParameters.Remove("Credential") + } + $null = $PSBoundParameters.Remove("SetFilePath") $null = $PSBoundParameters.Remove("GetFilePath") $null = $PSBoundParameters.Remove("TestFilePath") @@ -75,11 +80,8 @@ function Set-TargetResource [System.String] $TestFilePath, - [System.String] - $Username, - - [System.String] - $Password, + [System.Management.Automation.PSCredential] + $Credential, [System.String[]] $Variable @@ -87,6 +89,14 @@ function Set-TargetResource Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop + if($null -ne $Credential) + { + $null = $PSBoundParameters.Add("Username", $Credential.UserName) + $null = $PSBoundParameters.Add("Password", $Credential.GetNetworkCredential().password) + + $null = $PSBoundParameters.Remove("Credential") + } + $null = $PSBoundParameters.Remove("SetFilePath") $null = $PSBoundParameters.Remove("GetFilePath") $null = $PSBoundParameters.Remove("TestFilePath") @@ -117,11 +127,8 @@ function Test-TargetResource [System.String] $TestFilePath, - [System.String] - $Username, - - [System.String] - $Password, + [System.Management.Automation.PSCredential] + $Credential, [System.String[]] $Variable @@ -130,7 +137,15 @@ function Test-TargetResource Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop try - { + { + if($null -ne $Credential) + { + $null = $PSBoundParameters.Add("Username", $Credential.UserName) + $null = $PSBoundParameters.Add("Password", $Credential.GetNetworkCredential().password) + + $null = $PSBoundParameters.Remove("Credential") + } + $null = $PSBoundParameters.Remove("SetFilePath") $null = $PSBoundParameters.Remove("GetFilePath") $null = $PSBoundParameters.Remove("TestFilePath") diff --git a/README.md b/README.md index d5b1378c1..8ebf1e287 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,8 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ### Unreleased * Converted appveyor.yml to install Pester from PSGallery instead of from Chocolatey. * Added Support for SQL Server 2016 +* Resources Added + - xSQLServerScript ### 1.7.0.0 * Resources Added From 6480aab35f92db63b8aeb1ac00643cb6e49fa88a Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Thu, 28 Jul 2016 20:54:59 -0700 Subject: [PATCH 04/11] Removing xSQLServerScript documentation addition from wrong version --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ebf1e287..5cb245b0d 100644 --- a/README.md +++ b/README.md @@ -292,8 +292,7 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ### 1.7.0.0 * Resources Added - xSQLServerConfiguration - - xSQLServerScript - + ### 1.6.0.0 * Resources Added From 7743f61cb9ff82dae61e485036ad5181ebfc170c Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Thu, 28 Jul 2016 20:57:59 -0700 Subject: [PATCH 05/11] Updating xSqlServerScripts parameter list in readme.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 5cb245b0d..6a3f87bd7 100644 --- a/README.md +++ b/README.md @@ -276,8 +276,7 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **SetFilePath**: (Key) Path to SQL file that will perform Set action. * **GetFilePath**: (Key) Path to SQL file that will perform Get action. SQL Queries returned by this function are returned by the Get-DscConfiguration cmdlet with the GetResult parameter. * **TestFilePath**: (Key) Path to SQL file that will perform Test action. Any Script that does not throw an error and returns null is evaluated to true. Invoke-SqlCmd treats SQL Print statements as verbose text, this will not cause a the Test to return false. -* **Username**: Specifies the login ID for making a SQL Server Authentication connection to an instance of the Database Engine. -* **Password**: Specifies the password for the SQL Server Authentication login ID that was specified in Username. +* **Credential**: Specifies the credentials for making a SQL Server Authentication connection to an instance of the Database Engine. * **Variable**: Creates a sqlcmd scripting variable for use in the sqlcmd script, and sets a value for the variable. * **GetResult**: Result of Get action. From 3a124e3e6de13b7337a7369ed5bd4bf4254317c8 Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Tue, 2 Aug 2016 23:53:38 -0400 Subject: [PATCH 06/11] Fixed ReadMe typo and updated unit test cases Unit test cases had variable global scope removed, removed completed Todo comments. --- README.md | 2 +- Tests/Unit/MSFT_xSQLServerScript.Test.ps1 | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 6a3f87bd7..8f196b555 100644 --- a/README.md +++ b/README.md @@ -275,7 +275,7 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **ServerInstance**: (Required) The name of an instance of the Database Engine. For default instances, only specify the computer name. For named instances, use the format ComputerName\\InstanceName. * **SetFilePath**: (Key) Path to SQL file that will perform Set action. * **GetFilePath**: (Key) Path to SQL file that will perform Get action. SQL Queries returned by this function are returned by the Get-DscConfiguration cmdlet with the GetResult parameter. -* **TestFilePath**: (Key) Path to SQL file that will perform Test action. Any Script that does not throw an error and returns null is evaluated to true. Invoke-SqlCmd treats SQL Print statements as verbose text, this will not cause a the Test to return false. +* **TestFilePath**: (Key) Path to SQL file that will perform Test action. Any Script that does not throw an error and returns null is evaluated to true. Invoke-SqlCmd treats SQL Print statements as verbose text, this will not cause a Test to return false. * **Credential**: Specifies the credentials for making a SQL Server Authentication connection to an instance of the Database Engine. * **Variable**: Creates a sqlcmd scripting variable for use in the sqlcmd script, and sets a value for the variable. * **GetResult**: Result of Get action. diff --git a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 index d75ede1e5..a64463fb6 100644 --- a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 +++ b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 @@ -1,13 +1,11 @@ <# .Synopsis - Automated unit test for RPS_TSQL DSC Resource + Automated unit test for MSFT_xSQLServerScript DSC Resource #> -# TODO: Customize these parameters... -$Global:DSCModuleName = 'MSFT_xSQLServerScript' # Example xNetworking -$Global:DSCResourceName = 'MSFT_xSQLServerScript' # Example MSFT_xFirewall -# /TODO +$Script:DSCModuleName = 'MSFT_xSQLServerScript' +$Script:DSCResourceName = 'MSFT_xSQLServerScript' #region HEADER # Unit Test Template Version: 1.1.0 @@ -20,21 +18,21 @@ if ( (-not (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath 'DSCResource Import-Module (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force $TestEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $Global:DSCModuleName ` - -DSCResourceName $Global:DSCResourceName ` + -DSCModuleName $DSCModuleName ` + -DSCResourceName $DSCResourceName ` -TestType Unit #endregion HEADER # Begin Testing try { - InModuleScope $Global:DSCResourceName { + InModuleScope $DSCResourceName { #region Pester Test Initialization - Function GLobal:Invoke-SqlCmd {} + Function script:Invoke-SqlCmd {} #endregion Pester Test Initialization #region Function Get-TargetResource - Describe "$($Global:DSCResourceName)\Get-TargetResource" { + Describe "$($DSCResourceName)\Get-TargetResource" { It "Should throw if SQLPS module cannot be found" { $throwMessage = "Failed to find module" @@ -69,7 +67,7 @@ try #region Function Test-TargetResource - Describe "$($Global:DSCResourceName)\Test-TargetResource" { + Describe "$($DSCResourceName)\Test-TargetResource" { It "Should throw if SQLPS module cannot be found" { $throwMessage = "Failed to find module" @@ -98,7 +96,7 @@ try #region Function Set-TargetResource - Describe "$($Global:DSCResourceName)\Set-TargetResource" { + Describe "$($DSCResourceName)\Set-TargetResource" { It "Should throw if SQLPS module cannot be found" { $throwMessage = "Failed to find module" From b633137533fcff0e9ee99d0d288f2ccd69906045 Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Wed, 3 Aug 2016 00:14:36 -0400 Subject: [PATCH 07/11] Updated readme for merge with PowerShell/Dev --- README.md | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 0164bb45e..561ff86bf 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,11 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **xSQLServerEndpoint** resource to ensure database endpoint is present or absent * **xWaitForAvailabilityGroup** resource to wait till availability group is created on primary server * **xSQLServerConfiguration** resource to manage [SQL Server Configuration Options](https://msdn.microsoft.com/en-us/library/ms189631.aspx) -<<<<<<< HEAD -* **xSQLServerScript** resource to extend DSCs Get/Set/Test functionality to T-SQL -======= * **xSQLServerPermission** Grant or revoke permission on the SQL Server. * **xSQLServerEndpointState** Change state of the endpoint. * **xSQLServerEndpointPermission** Grant or revoke permission on the endpoint. * **xSQLServerAvailabilityGroupListener** Create or remove an availability group listener. ->>>>>>> refs/remotes/PowerShell/dev +* **xSQLServerScript** resource to extend DSCs Get/Set/Test functionality to T-SQL ### xSQLServerSetup @@ -279,16 +276,6 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **OptionValue**: (Required) SQL Server option value to be set. * **RestartService**: Default false. If true will restart SQL Service instance service after update. -<<<<<<< HEAD -###xSQLServerScript -* **ServerInstance**: (Required) The name of an instance of the Database Engine. For default instances, only specify the computer name. For named instances, use the format ComputerName\\InstanceName. -* **SetFilePath**: (Key) Path to SQL file that will perform Set action. -* **GetFilePath**: (Key) Path to SQL file that will perform Get action. SQL Queries returned by this function are returned by the Get-DscConfiguration cmdlet with the GetResult parameter. -* **TestFilePath**: (Key) Path to SQL file that will perform Test action. Any Script that does not throw an error and returns null is evaluated to true. Invoke-SqlCmd treats SQL Print statements as verbose text, this will not cause a Test to return false. -* **Credential**: Specifies the credentials for making a SQL Server Authentication connection to an instance of the Database Engine. -* **Variable**: Creates a sqlcmd scripting variable for use in the sqlcmd script, and sets a value for the variable. -* **GetResult**: Result of Get action. -======= ### xSQLServerPermission * **InstanceName** The SQL Server instance name. * **NodeName** The host name or FQDN. @@ -320,17 +307,22 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **IpAddress** The IP address used for the availability group listener, in the format 192.168.10.45/255.255.252.0. If using DCHP, set to the first IP-address of the DHCP subnet, in the format 192.168.8.1/255.255.252.0. Must be valid in the cluster-allowed IP range. * **Port** The port used for the availability group listener. * **DHCP** If DHCP should be used for the availability group listener instead of static IP address. ->>>>>>> refs/remotes/PowerShell/dev + +###xSQLServerScript +* **ServerInstance**: (Required) The name of an instance of the Database Engine. For default instances, only specify the computer name. For named instances, use the format ComputerName\\InstanceName. +* **SetFilePath**: (Key) Path to SQL file that will perform Set action. +* **GetFilePath**: (Key) Path to SQL file that will perform Get action. SQL Queries returned by this function are returned by the Get-DscConfiguration cmdlet with the GetResult parameter. +* **TestFilePath**: (Key) Path to SQL file that will perform Test action. Any Script that does not throw an error and returns null is evaluated to true. Invoke-SqlCmd treats SQL Print statements as verbose text, this will not cause a Test to return false. +* **Credential**: Specifies the credentials for making a SQL Server Authentication connection to an instance of the Database Engine. +* **Variable**: Creates a sqlcmd scripting variable for use in the sqlcmd script, and sets a value for the variable. +* **GetResult**: Result of Get action. ## Versions ### Unreleased + * Converted appveyor.yml to install Pester from PSGallery instead of from Chocolatey. * Added Support for SQL Server 2016 -<<<<<<< HEAD -* Resources Added - - xSQLServerScript -======= * xSQLAOGroupEnsure - Fixed spelling mistake in AutoBackupPreference property - Added BackupPriority property @@ -339,6 +331,7 @@ Please check out common DSC Resources [contributing guidelines](https://github.c - xSQLServerEndpointState - xSQLServerEndpointPermission - xSQLServerAvailabilityGroupListener + - xSQLServerScript * xSQLServerHelper - added functions - Import-SQLPSModule @@ -347,9 +340,9 @@ Please check out common DSC Resources [contributing guidelines](https://github.c - Get-SQLAlwaysOnEndpoint - modified functions - New-TerminatingError - *added optional parameter `InnerException` to be able to give the user more information in the returned message* ->>>>>>> refs/remotes/PowerShell/dev ### 1.7.0.0 + * Resources Added - xSQLServerConfiguration @@ -467,3 +460,4 @@ Please check out common DSC Resources [contributing guidelines](https://github.c Examples for use of this resource can be found with the System Center resources, such as **xSCVMM**, **xSCSMA**, and **xSCOM**. + From 81247c2f316d635c8ee611123a409f8c28347060 Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Fri, 5 Aug 2016 18:07:36 -0700 Subject: [PATCH 08/11] Updated MSFT_xSQLServerScript.Test.ps1 to use current unit test template --- Tests/Unit/MSFT_xSQLServerScript.Test.ps1 | 218 ++++++++++++++-------- 1 file changed, 143 insertions(+), 75 deletions(-) diff --git a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 index a64463fb6..5705ce535 100644 --- a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 +++ b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 @@ -8,127 +8,195 @@ $Script:DSCModuleName = 'MSFT_xSQLServerScript' $Script:DSCResourceName = 'MSFT_xSQLServerScript' #region HEADER + # Unit Test Template Version: 1.1.0 -[String] $moduleRoot = Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $Script:MyInvocation.MyCommand.Path)) -if ( (-not (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` - (-not (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) +[String] $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { - & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $moduleRoot -ChildPath '\DSCResource.Tests\')) + & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) } -Import-Module (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force $TestEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $DSCModuleName ` - -DSCResourceName $DSCResourceName ` + -DSCModuleName $script:DSCModuleName ` + -DSCResourceName $script:DSCResourceName ` -TestType Unit + #endregion HEADER # Begin Testing try { - InModuleScope $DSCResourceName { - #region Pester Test Initialization - Function script:Invoke-SqlCmd {} - #endregion Pester Test Initialization + #region Pester Test Initialization + Function script:Invoke-SqlCmd {} + #endregion Pester Test Initialization + + #region Test Sql script throws an error + Describe 'Test Sql script throws an error' { + Mock -CommandName Import-Module -MockWith {} + + $testParameters = @{ + ServerInstance = $env:COMPUTERNAME + SetFilePath = "set.sql" + GetFilePath = "get.sql" + TestFilePath = "test.sql" + } - #region Function Get-TargetResource - Describe "$($DSCResourceName)\Get-TargetResource" { - It "Should throw if SQLPS module cannot be found" { - $throwMessage = "Failed to find module" + It 'Get method returns successfully' { + Mock -CommandName Invoke-SqlCmd -MockWith { "" } - Mock -CommandName Import-Module -MockWith { Throw $throwMessage } + $result = Get-TargetResource @testParameters - { Get-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage - } + $result.ServerInstance | should be $testParameters.ServerInstance + $result.SetFilePath | should be $testParameters.SetFilePath + $result.GetFilePath | should be $testParameters.GetFilePath + $result.TestFilePath | should be $testParameters.TestFilePath + $result.GetType() | should be "hashtable" + } - It "Should throw if Invoke-SqlCmd throws" { - $throwMessage = "Failed to run SQL Script" + It 'Test method returns false' { + $throwMessage = "Failed to run SQL Script" - Mock -CommandName Import-Module -MockWith {} - Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } + Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } - { Get-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage - } - - It "Should return a hashtable if the Get SQL script returns" { - Mock -CommandName Import-Module -MockWith {} - Mock -CommandName Invoke-SqlCmd -MockWith { "" } + Test-TargetResource @testParameters | should be $false + } - $result = Get-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" + It 'Set method calls Invoke-SqlCmd' { + Mock -CommandName Invoke-SqlCmd -MockWith { "" } -Verifiable - $result.ServerInstance | should be $env:COMPUTERNAME - $result.SetFilePath | should be "set.sql" - $result.GetFilePath | should be "get.sql" - $result.TestFilePath | should be "test.sql" - $result.GetType() | should be "hashtable" - } + $result = Set-TargetResource @testParameters + + Assert-MockCalled -CommandName Invoke-SqlCmd -Times 1 + } + } + #endregion Test Sql script throws an error + + #region Test Sql script returns null + Describe 'Test Sql script returns null' { + Mock -CommandName Import-Module -MockWith {} + Mock -CommandName Invoke-SqlCmd -MockWith { $null } + + $testParameters = @{ + ServerInstance = $env:COMPUTERNAME + SetFilePath = "set.sql" + GetFilePath = "get.sql" + TestFilePath = "test.sql" } - #endregion Function Get-TargetResource + It 'Get method returns successfully' { + $result = Get-TargetResource @testParameters - #region Function Test-TargetResource - Describe "$($DSCResourceName)\Test-TargetResource" { - It "Should throw if SQLPS module cannot be found" { - $throwMessage = "Failed to find module" + $result.ServerInstance | should be $testParameters.ServerInstance + $result.SetFilePath | should be $testParameters.SetFilePath + $result.GetFilePath | should be $testParameters.GetFilePath + $result.TestFilePath | should be $testParameters.TestFilePath + $result.GetType() | should be "hashtable" + } - Mock -CommandName Import-Module -MockWith { Throw $throwMessage } + It 'Test method returns true' { + Test-TargetResource @testParameters | should be $true + } + } + #endregion Test Sql script returns null - { Test-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage - } + #region Get SQl script throws and error + Describe 'Get SQl script throws and error' { + Mock -CommandName Import-Module -MockWith {} + + $testParameters = @{ + ServerInstance = $env:COMPUTERNAME + SetFilePath = "set.sql" + GetFilePath = "get.sql" + TestFilePath = "test.sql" + } - It "Should return false if Invoke-SqlCmd throws" { - $throwMessage = "Failed to run SQL Script" + It 'Get throws when get sql script throws' { + $throwMessage = "Failed to run SQL Script" - Mock -CommandName Import-Module -MockWith {} - Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } + Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } - Test-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" | should be $false - } + { Get-TargetResource @testParameters } | should throw $throwMessage + } - It "Should return true if Invoke-SqlCmd returns null" { - Mock -CommandName Import-Module -MockWith {} - Mock -CommandName Invoke-SqlCmd -MockWith {} + It 'Test method returns true' { + Mock -CommandName Invoke-SqlCmd -MockWith { $null } - Test-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" | should be $true - } + Test-TargetResource @testParameters | should be $true } - #endregion Function Test-TargetResource + } + #endregion + #region Set-TargetResource throws when Set Sql script throws + Describe 'Set-TargetResource throws when Set Sql script throws' { + Mock -CommandName Import-Module -MockWith {} + Mock -CommandName Invoke-SqlCmd -MockWith { $null } - #region Function Set-TargetResource - Describe "$($DSCResourceName)\Set-TargetResource" { - It "Should throw if SQLPS module cannot be found" { - $throwMessage = "Failed to find module" + $testParameters = @{ + ServerInstance = $env:COMPUTERNAME + SetFilePath = "set.sql" + GetFilePath = "get.sql" + TestFilePath = "test.sql" + } - Mock -CommandName Import-Module -MockWith { Throw $throwMessage } + It 'Get method returns successfully' { + $result = Get-TargetResource @testParameters - { Set-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage - } + $result.ServerInstance | should be $testParameters.ServerInstance + $result.SetFilePath | should be $testParameters.SetFilePath + $result.GetFilePath | should be $testParameters.GetFilePath + $result.TestFilePath | should be $testParameters.TestFilePath + $result.GetType() | should be "hashtable" + } + + It 'Test method returns true' { + Test-TargetResource @testParameters | should be $true + } + + It 'Set method throws' { + $throwMessage = "Failed to execute set Sql script" + + Mock -CommandName Invoke-SqlCmd -MockWith { throw $throwMessage } + + { Set-TargetResource @testParameters } | should throw $throwMessage + } + } + #endregion - It "Should throw if Invoke-SqlCmd throws" { - $throwMessage = "Failed to run SQL Script" + #region Failed to import SQLPS module + Describe 'Failed to import SQLPS module' { + $throwMessage = "Failed to import module SQLPS" - Mock -CommandName Import-Module -MockWith {} - Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } + Mock -CommandName Import-Module -MockWith { throw $throwMessage } - { Set-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" } | should throw $throwMessage - } + $testParameters = @{ + ServerInstance = $env:COMPUTERNAME + SetFilePath = "set.sql" + GetFilePath = "get.sql" + TestFilePath = "test.sql" + } - It "Should always attempt to execute Invoke-SqlCmd" { - Mock -CommandName Import-Module -MockWith {} - Mock -CommandName Invoke-SqlCmd -MockWith {} -Verifiable + It 'Get method throws' { + { $result = Get-TargetResource @testParameters } | should throw $throwMessage + } - $result = Set-TargetResource -ServerInstance $env:COMPUTERNAME -SetFilePath "set.sql" -GetFilePath "get.sql" -TestFilePath "test.sql" + It 'Test method throws' { + { Test-TargetResource @testParameters } | should throw $throwMessage + } - Assert-MockCalled -CommandName Invoke-SqlCmd -Times 1 - } + It 'Set method throws' { + { Set-TargetResource @testParameters} | should throw $throwMessage } - #endregion Function Set-TargetResource } + #endregion + } finally { #region FOOTER + Restore-TestEnvironment -TestEnvironment $TestEnvironment + #endregion } From 3a512489bcc3dad95af5fd549a17d7367ee03fb5 Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Wed, 10 Aug 2016 16:54:27 -0700 Subject: [PATCH 09/11] Updated MSFT_xSQLServerScript style per peer review --- .../MSFT_xSQLServerScript.psm1 | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 index 0b00d9d3a..5853cd530 100644 --- a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 +++ b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 @@ -4,19 +4,19 @@ [OutputType([System.Collections.Hashtable])] param ( - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $ServerInstance, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $SetFilePath, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $GetFilePath, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $TestFilePath, @@ -46,14 +46,13 @@ $getResult = Out-String -InputObject $result $returnValue = @{ - ServerInstance = [System.String]$ServerInstance - SetFilePath = [System.String]$SetFilePath - GetFilePath = [System.String]$GetFilePath - TestFilePath = [System.String]$TestFilePath - Username = [System.String]$Username - Password = [System.String]$Password - Variable = [System.String[]]$Variable - GetResult = [System.String[]]$getresult + ServerInstance = [System.String] $ServerInstance + SetFilePath = [System.String] $SetFilePath + GetFilePath = [System.String] $GetFilePath + TestFilePath = [System.String] $TestFilePath + Username = [System.Management.Automation.PSCredential] $Credential + Variable = [System.String[]] $Variable + GetResult = [System.String[]] $getresult } $returnValue @@ -64,19 +63,19 @@ function Set-TargetResource [CmdletBinding()] param ( - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $ServerInstance, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $SetFilePath, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $GetFilePath, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $TestFilePath, @@ -111,19 +110,19 @@ function Test-TargetResource [OutputType([System.Boolean])] param ( - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $ServerInstance, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $SetFilePath, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $GetFilePath, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $TestFilePath, From 38fc5f28ca8e26bedf3e53d328379e21503a41be Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Wed, 10 Aug 2016 17:55:49 -0700 Subject: [PATCH 10/11] Added function Invoke-SqlScript to reduce redundancy --- .../MSFT_xSQLServerScript.psm1 | 94 +++++++++---------- Tests/Unit/MSFT_xSQLServerScript.Test.ps1 | 2 +- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 index 5853cd530..24ac063c5 100644 --- a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 +++ b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 @@ -1,4 +1,11 @@ -function Get-TargetResource +$currentPath = Split-Path -Parent $MyInvocation.MyCommand.Path +Write-Verbose -Message "CurrentPath: $currentPath" + +# Load Common Code +Import-Module $currentPath\..\..\xSQLServerHelper.psm1 -Verbose:$false -ErrorAction Stop + + +function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] @@ -25,23 +32,10 @@ [System.String[]] $Variable - ) - - Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop - - if($null -ne $Credential) - { - $null = $PSBoundParameters.Add("Username", $Credential.UserName) - $null = $PSBoundParameters.Add("Password", $Credential.GetNetworkCredential().password) - - $null = $PSBoundParameters.Remove("Credential") - } - - $null = $PSBoundParameters.Remove("SetFilePath") - $null = $PSBoundParameters.Remove("GetFilePath") - $null = $PSBoundParameters.Remove("TestFilePath") + ) - $result = Invoke-Sqlcmd -InputFile $getFilePath @PSBoundParameters -ErrorAction Stop + $result = Invoke-SqlScript -ServerInstance $ServerInstance -SqlScriptPath $GetFilePath ` + -Credential $Credential -Variable $Variable -ErrorAction Stop $getResult = Out-String -InputObject $result @@ -86,21 +80,8 @@ function Set-TargetResource $Variable ) - Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop - - if($null -ne $Credential) - { - $null = $PSBoundParameters.Add("Username", $Credential.UserName) - $null = $PSBoundParameters.Add("Password", $Credential.GetNetworkCredential().password) - - $null = $PSBoundParameters.Remove("Credential") - } - - $null = $PSBoundParameters.Remove("SetFilePath") - $null = $PSBoundParameters.Remove("GetFilePath") - $null = $PSBoundParameters.Remove("TestFilePath") - - Invoke-Sqlcmd -InputFile $setFilePath @PSBoundParameters -ErrorAction Stop + Invoke-SqlScript -ServerInstance $ServerInstance -SqlScriptPath $SetFilePath ` + -Credential $Credential -Variable $Variable -ErrorAction Stop } @@ -133,23 +114,10 @@ function Test-TargetResource $Variable ) - Import-Module -Name SQLPS -WarningAction SilentlyContinue -ErrorAction Stop - try { - if($null -ne $Credential) - { - $null = $PSBoundParameters.Add("Username", $Credential.UserName) - $null = $PSBoundParameters.Add("Password", $Credential.GetNetworkCredential().password) - - $null = $PSBoundParameters.Remove("Credential") - } - - $null = $PSBoundParameters.Remove("SetFilePath") - $null = $PSBoundParameters.Remove("GetFilePath") - $null = $PSBoundParameters.Remove("TestFilePath") - - $result = Invoke-Sqlcmd -InputFile $testFilePath @PSBoundParameters -ErrorAction stop + $result = Invoke-SqlScript -ServerInstance $ServerInstance -SqlScriptPath $TestFilePath ` + -Credential $Credential -Variable $Variable -ErrorAction Stop if($result -eq $null) { @@ -167,6 +135,38 @@ function Test-TargetResource } } +function Invoke-SqlScript +{ + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $ServerInstance, + + [Parameter(Mandatory = $true)] + [System.String] + $SqlScriptPath, + + [System.Management.Automation.PSCredential] + $Credential, + + [System.String[]] + $Variable + ) + + Import-SQLPSModule + + if($null -ne $Credential) + { + $null = $PSBoundParameters.Add("Username", $Credential.UserName) + $null = $PSBoundParameters.Add("Password", $Credential.GetNetworkCredential().password) + } + + $null = $PSBoundParameters.Remove("Credential") + $null = $PSBoundParameters.Remove("SqlScriptPath") + + Invoke-Sqlcmd -InputFile $SqlScriptPath @PSBoundParameters +} Export-ModuleMember -Function *-TargetResource diff --git a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 index 5705ce535..29bc8f0d3 100644 --- a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 +++ b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 @@ -182,7 +182,7 @@ try } It 'Test method throws' { - { Test-TargetResource @testParameters } | should throw $throwMessage + Test-TargetResource @testParameters | should be $false } It 'Set method throws' { From dba7ab8c4485618dc48e6b0f95adfa3c5e06f686 Mon Sep 17 00:00:00 2001 From: David Reynolds Date: Sat, 20 Aug 2016 21:36:33 -0700 Subject: [PATCH 11/11] Updated Test function to only catch SQL execution exceptions --- .../MSFT_xSQLServerScript.psm1 | 2 +- Tests/Unit/MSFT_xSQLServerScript.Test.ps1 | 24 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 index 24ac063c5..9026f0e88 100644 --- a/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 +++ b/DSCResources/MSFT_xSQLServerScript/MSFT_xSQLServerScript.psm1 @@ -128,7 +128,7 @@ function Test-TargetResource return $false } } - catch + catch [Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException] { Write-Verbose $_ return $false diff --git a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 index 29bc8f0d3..66f132305 100644 --- a/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 +++ b/Tests/Unit/MSFT_xSQLServerScript.Test.ps1 @@ -1,6 +1,6 @@ <# -.Synopsis - Automated unit test for MSFT_xSQLServerScript DSC Resource + .SYNOPSIS + Automated unit test for MSFT_xSQLServerScript DSC Resource #> @@ -25,6 +25,18 @@ $TestEnvironment = Initialize-TestEnvironment ` #endregion HEADER +Add-Type -ErrorAction SilentlyContinue -TypeDefinition @' +namespace Microsoft.SqlServer.Management.PowerShell +{ + public class SqlPowerShellSqlExecutionException : System.Exception + { + public SqlPowerShellSqlExecutionException() + { + } + } +} +'@ + # Begin Testing try { @@ -56,11 +68,9 @@ try } It 'Test method returns false' { - $throwMessage = "Failed to run SQL Script" - - Mock -CommandName Invoke-SqlCmd -MockWith { Throw $throwMessage } + Mock -CommandName Invoke-SqlCmd -MockWith { throw New-Object Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException} - Test-TargetResource @testParameters | should be $false + Test-TargetResource @testParameters | should be $false } It 'Set method calls Invoke-SqlCmd' { @@ -182,7 +192,7 @@ try } It 'Test method throws' { - Test-TargetResource @testParameters | should be $false + { Test-TargetResource @testParameters } | should throw $throwMessage } It 'Set method throws' {