diff --git a/CHANGELOG.md b/CHANGELOG.md index 4578c75cd..12f3bc14c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 other values that the default values. - Now updates GitHub Actions automatically by allowing dependabot sending in pull requests. + - New public command: + - `Get-SqlDscPreferredModule` - Returns the name of the first available + preferred module ([issue #1879](https://github.com/dsccommunity/SqlServerDsc/issues/1879)). - `SqlSecureConnection` - Added new parameter `ServerName` that will be used as the host name when restarting the SQL Server instance. The specified value should be the same @@ -51,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Now imports the preferred module into the global scope so that MOF-based resources (that is in another module scope) can use the imported module. - Some code cleanup ([issue #1881](https://github.com/dsccommunity/SqlServerDsc/issues/1881)). + - Refactor to re-use the command `Get-SqlDscPreferredModule`. - SqlServerDsc.Common - `Restart-SqlService` no longer silently ignores errors that prevents the instance to go online. If the instance has not gone online during diff --git a/source/Public/Get-SqlDscPreferredModule.ps1 b/source/Public/Get-SqlDscPreferredModule.ps1 new file mode 100644 index 000000000..98408fb64 --- /dev/null +++ b/source/Public/Get-SqlDscPreferredModule.ps1 @@ -0,0 +1,175 @@ +<# + .SYNOPSIS + Get the first available (preferred) module that is installed. + + .DESCRIPTION + Get the first available (preferred) module that is installed. + + .PARAMETER Name + Specifies the list of the (preferred) modules to search for, in order. + Defaults to 'SqlServer' and then 'SQLPS'. + + .PARAMETER Refresh + Specifies if the session environment variable PSModulePath should be refresh + with the paths from other environment variable targets (Machine and User). + + .EXAMPLE + Get-SqlDscPreferredModule + + Returns the module name SqlServer if it is installed, otherwise it will + return SQLPS if is is installed. If neither is installed `$null` is + returned. + + .EXAMPLE + Get-SqlDscPreferredModule -Refresh + + Updated the session environment variable PSModulePath and then returns the + module name SqlServer if it is installed, otherwise it will return SQLPS + if is is installed. If neither is installed `$null` is returned. + + .EXAMPLE + Get-SqlDscPreferredModule -Name @('MyModule', 'SQLPS') + + Returns the module name MyModule if it is installed, otherwise it will + return SQLPS if is is installed. If neither is installed `$null` is + returned. + + .NOTES + If the module SQLPS is specified (default value) the path is returned as + the module name. This is because importing 'SQLPS' using simply the name + could make the wrong version to be imported when several different version + of SQL Server is installed on the same node. To make sure the correct + (latest) version is imported the path to the latest version of SQLPS is + returned. The returned path can be passed directly to the parameter Name + of the command Import-Module. +#> +function Get-SqlDscPreferredModule +{ + [OutputType([System.String])] + [CmdletBinding()] + param + ( + [Parameter()] + [System.String[]] + $Name = @('SqlServer', 'SQLPS'), + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Refresh + ) + + if ($Refresh.IsPresent) + { + # Only run on Windows that has Machine state. + if (-not ($IsLinux -or $IsMacOS)) + { + <# + After installing SQL Server the current PowerShell session doesn't know + about the new path that was added for the SQLPS module. This reloads + PowerShell session environment variable PSModulePath to make sure it + contains all paths. + #> + + <# + TODO: This should be replaced by Get-PSModulePath that is in + PR https://github.com/dsccommunity/DscResource.Common/pull/104. + #> + + <# + Get the environment variables from all targets session, user and machine. + Casts the value to System.String to convert $null values to empty string. + #> + $modulePathSession = [System.String] [System.Environment]::GetEnvironmentVariable('PSModulePath') + $modulePathUser = [System.String] [System.Environment]::GetEnvironmentVariable('PSModulePath', 'User') + $modulePathMachine = [System.String] [System.Environment]::GetEnvironmentVariable('PSModulePath', 'Machine') + + $modulePath = $modulePathSession, $modulePathUser, $modulePathMachine -join ';' + + $modulePathArray = $modulePath -split ';' | + Where-Object -FilterScript { + -not [System.String]::IsNullOrEmpty($_) + } | + Sort-Object -Unique + + $modulePath = $modulePathArray -join ';' + + Set-PSModulePath -Path $modulePath + } + } + + $availableModuleName = $null + + $availableModule = Get-Module -FullyQualifiedName $Name -ListAvailable | + Select-Object -Property @( + 'Name', + 'Path', + @{ + Name = 'Version' + Expression = { + if ($_.Name -eq 'SQLPS') + { + <# + Parse the build version number '120', '130' from the Path. + Older version of SQLPS did not have correct versioning. + #> + (Select-String -InputObject $_.Path -Pattern '\\([0-9]{3})\\' -List).Matches.Groups[1].Value + } + else + { + $versionToReturn = $_.Version + + if ($_.ContainsKey('PrivateData') -and $_.PrivateData.ContainsKey('PSData') -and $_.PrivateData.PSData.ContainsKey('Prerelease')) + { + if (-not [System.String]::IsNullOrEmpty($_.PrivateData.PSData.Prerelease)) + { + $versionToReturn = '{0}-{1}' -f $_.Version, $_.PrivateData.PSData.Prerelease + } + } + + $versionToReturn + } + } + } + ) + + foreach ($preferredModuleName in $Name) + { + $preferredModule = $availableModule | + Where-Object -Property 'Name' -EQ -Value $preferredModuleName + + if ($preferredModule) + { + if ($preferredModule.Name -eq 'SQLPS') + { + # Get the latest version if available. + $preferredModule = $preferredModule | + Sort-Object -Property 'Version' -Descending | + Select-Object -First 1 + + <# + For SQLPS the path to the module need to be returned as the + module name to be absolutely sure the latest version is used. + #> + $availableModuleName = Split-Path -Path $preferredModule.Path -Parent + } + else + { + $availableModuleName = ($preferredModule | Select-Object -First 1).Name + } + + Write-Verbose -Message ($script:localizedData.PreferredModule_ModuleFound -f $availableModuleName) + + break + } + } + + if (-not $availableModuleName) + { + $errorMessage = $script:localizedData.PreferredModule_ModuleNotFound + + # cSpell: disable-next + Write-Error -Message $errorMessage -Category 'ObjectNotFound' -ErrorId 'GSDPM0001' -TargetObject ($Name -join ', ') + } + + return $availableModuleName +} diff --git a/source/Public/Import-SqlDscPreferredModule.ps1 b/source/Public/Import-SqlDscPreferredModule.ps1 index cf75f2707..156c478b5 100644 --- a/source/Public/Import-SqlDscPreferredModule.ps1 +++ b/source/Public/Import-SqlDscPreferredModule.ps1 @@ -75,72 +75,7 @@ function Import-SqlDscPreferredModule } } - $availableModuleName = $null - - # Get the newest SqlServer module if more than one exist - $availableModule = Get-Module -FullyQualifiedName $PreferredModule -ListAvailable | - Sort-Object -Property 'Version' -Descending | - Select-Object -First 1 -Property 'Name', 'Path', 'Version' - - if ($availableModule) - { - $availableModuleName = $availableModule.Name - - Write-Verbose -Message ($script:localizedData.PreferredModule_ModuleFound -f $availableModuleName) - } - else - { - Write-Verbose -Message ($script:localizedData.PreferredModule_ModuleNotFound) - - # Only run on Windows that has Machine state. - if (-not ($IsLinux -or $IsMacOS)) - { - <# - After installing SQL Server the current PowerShell session doesn't know - about the new path that was added for the SQLPS module. This reloads - PowerShell session environment variable PSModulePath to make sure it - contains all paths. - #> - - <# - Get the environment variables from all targets session, user and machine. - Casts the value to System.String to convert $null values to empty string. - #> - $modulePathSession = [System.String] [System.Environment]::GetEnvironmentVariable('PSModulePath') - $modulePathUser = [System.String] [System.Environment]::GetEnvironmentVariable('PSModulePath', 'User') - $modulePathMachine = [System.String] [System.Environment]::GetEnvironmentVariable('PSModulePath', 'Machine') - - $modulePath = $modulePathSession, $modulePathUser, $modulePathMachine -join ';' - - $modulePathArray = $modulePath -split ';' | - Where-Object -FilterScript { - -not [System.String]::IsNullOrEmpty($_) - } | - Sort-Object -Unique - - $modulePath = $modulePathArray -join ';' - - Set-PSModulePath -Path $modulePath - } - - # Get the newest SQLPS module if more than one exist. - $availableModule = Get-Module -FullyQualifiedName 'SQLPS' -ListAvailable | - Select-Object -Property Name, Path, @{ - Name = 'Version' - Expression = { - # Parse the build version number '120', '130' from the Path. - (Select-String -InputObject $_.Path -Pattern '\\([0-9]{3})\\' -List).Matches.Groups[1].Value - } - } | - Sort-Object -Property 'Version' -Descending | - Select-Object -First 1 - - if ($availableModule) - { - # This sets $availableModuleName to the Path of the module to be loaded. - $availableModuleName = Split-Path -Path $availableModule.Path -Parent - } - } + $availableModuleName = Get-SqlDscPreferredModule -Name @($PreferredModule, 'SQLPS') -Refresh if ($availableModuleName) { diff --git a/source/en-US/SqlServerDsc.strings.psd1 b/source/en-US/SqlServerDsc.strings.psd1 index 55ad73254..08c714f31 100644 --- a/source/en-US/SqlServerDsc.strings.psd1 +++ b/source/en-US/SqlServerDsc.strings.psd1 @@ -147,9 +147,11 @@ ConvertFrom-StringData @' TraceFlag_Remove_ShouldProcessCaption = Remove trace flag from instance TraceFlag_Remove_NoCurrentTraceFlags = There are no current trace flags on instance. Nothing to remove. - ## Import-SqlDscPreferredModule + ## Get-SqlDscPreferredModule PreferredModule_ModuleFound = Preferred module {0} found. - PreferredModule_ModuleNotFound = Information: No preferred PowerShell module was found, trying to use the SQLPS module. + PreferredModule_ModuleNotFound = No preferred PowerShell module was found. + + ## Import-SqlDscPreferredModule PreferredModule_ImportedModule = Imported PowerShell module '{0}' with version '{1}' from path '{2}'. PreferredModule_AlreadyImported = Found PowerShell module {0} already imported in the session. PreferredModule_ForceRemoval = Forcibly removed the SQL PowerShell module from the session to import it fresh again. diff --git a/tests/Unit/Public/Get-SqlDscPreferredModule.Tests.ps1 b/tests/Unit/Public/Get-SqlDscPreferredModule.Tests.ps1 new file mode 100644 index 000000000..0b590b070 --- /dev/null +++ b/tests/Unit/Public/Get-SqlDscPreferredModule.Tests.ps1 @@ -0,0 +1,422 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'because ConvertTo-SecureString is used to simplify the tests.')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:dscModuleName = 'SqlServerDsc' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:dscModuleName + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Get-SqlDscPreferredModule' -Tag 'Public' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + MockParameterSetName = '__AllParameterSets' + # cSpell: disable-next + MockExpectedParameters = '[[-Name] ] [-Refresh] []' + } + ) { + $result = (Get-Command -Name 'Get-SqlDscPreferredModule').ParameterSets | + Where-Object -FilterScript { + $_.Name -eq $mockParameterSetName + } | + Select-Object -Property @( + @{ + Name = 'ParameterSetName' + Expression = { $_.Name } + }, + @{ + Name = 'ParameterListAsString' + Expression = { $_.ToString() } + } + ) + + $result.ParameterSetName | Should -Be $MockParameterSetName + $result.ParameterListAsString | Should -Be $MockExpectedParameters + } + + Context 'When no parameters are specified' { + Context 'When none of the default preferred modules are installed' { + Context 'When ErrorAction is set to SilentlyContinue' { + BeforeAll { + Mock -CommandName Get-Module + } + + It 'Should return $null' { + Get-SqlDscPreferredModule -ErrorAction 'SilentlyContinue' -ErrorVariable mockError | Should -BeNullOrEmpty + + $mockError | Should -HaveCount 1 + } + } + + Context 'When ErrorAction is set to Ignore' { + BeforeAll { + Mock -CommandName Get-Module + } + + It 'Should return $null' { + Get-SqlDscPreferredModule -ErrorAction 'Ignore' -ErrorVariable mockError | Should -BeNullOrEmpty + + $mockError | Should -BeNullOrEmpty + } + } + + Context 'When ErrorAction is set to Stop' { + BeforeAll { + Mock -CommandName Get-Module + } + + It 'Should throw the correct error' { + $errorMessage = InModuleScope -ScriptBlock { + $script:localizedData.PreferredModule_ModuleNotFound + } + + { Get-SqlDscPreferredModule -ErrorAction 'Stop' } | Should -Throw -ExpectedMessage $errorMessage + } + } + } + + Context 'When only first default preferred module is installed' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @{ + Name = 'SqlServer' + } + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule | Should -Be 'SqlServer' + } + } + + Context 'When only second default preferred module is installed' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule | Should -Be 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS' + } + } + + Context 'When both default preferred modules are installed' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @( + @{ + Name = 'SqlServer' + } + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + ) + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule | Should -Be 'SqlServer' + } + } + + Context 'When there are several installed versions of all default preferred modules' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @( + @{ + Name = 'SqlServer' + Version = '1.0.0' + } + @{ + Name = 'SqlServer' + Version = '2.0.0' + } + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\160\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + ) + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule | Should -Be 'SqlServer' + } + } + + Context 'When there are several installed versions of the first default preferred module' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @( + @{ + Name = 'SqlServer' + Version = '1.0.0' + } + @{ + Name = 'SqlServer' + Version = '2.0.0' + } + ) + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule | Should -Be 'SqlServer' + } + } + + Context 'When there are several installed versions of the second default preferred module' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @( + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\160\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + ) + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule | Should -Be 'C:\Program Files (x86)\Microsoft SQL Server\160\Tools\PowerShell\Modules\SQLPS' + } + } + } + + Context 'When specifying preferred module' { + Context 'When none of the preferred modules are installed' { + Context 'When ErrorAction is set to SilentlyContinue' { + BeforeAll { + Mock -CommandName Get-Module + } + + It 'Should return $null' { + Get-SqlDscPreferredModule -Name 'SqlServer' -ErrorAction 'SilentlyContinue' -ErrorVariable mockError | Should -BeNullOrEmpty + + $mockError | Should -HaveCount 1 + } + } + + Context 'When ErrorAction is set to Ignore' { + BeforeAll { + Mock -CommandName Get-Module + } + + It 'Should return $null' { + Get-SqlDscPreferredModule -Name 'SqlServer' -ErrorAction 'Ignore' -ErrorVariable mockError | Should -BeNullOrEmpty + + $mockError | Should -BeNullOrEmpty + } + } + + Context 'When ErrorAction is set to Stop' { + BeforeAll { + Mock -CommandName Get-Module + } + + It 'Should throw the correct error' { + $errorMessage = InModuleScope -ScriptBlock { + $script:localizedData.PreferredModule_ModuleNotFound + } + + { Get-SqlDscPreferredModule -Name 'SqlServer' -ErrorAction 'Stop' } | Should -Throw -ExpectedMessage $errorMessage + } + } + } + + Context 'When only first preferred module is installed' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @{ + Name = 'SqlServer' + } + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule -Name 'SqlServer' | Should -Be 'SqlServer' + } + } + + Context 'When only second preferred module is installed' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule -Name @('SqlServer', 'SQLPS') | Should -Be 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS' + } + } + + Context 'When both preferred modules are installed' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @( + @{ + Name = 'SqlServer' + } + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + ) + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule -Name @('SqlServer', 'SQLPS') | Should -Be 'SqlServer' + } + } + + Context 'When there are several installed versions of all preferred modules' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @( + @{ + Name = 'SqlServer' + Version = '1.0.0' + } + @{ + Name = 'SqlServer' + Version = '2.0.0' + PrivateData = @{ + PSData = @{ + PreRelease = 'preview1' + } + } + } + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\160\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + ) + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule -Name @('SqlServer', 'SQLPS') | Should -Be 'SqlServer' + } + } + + Context 'When there are several installed versions of the first preferred module' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @( + @{ + Name = 'SqlServer' + Version = '1.0.0' + } + @{ + Name = 'SqlServer' + Version = '2.0.0' + } + ) + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule -Name @('SqlServer', 'SQLPS') | Should -Be 'SqlServer' + } + } + + Context 'When there are several installed versions of the second preferred module' { + BeforeAll { + Mock -CommandName Get-Module -MockWith { + return @( + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + @{ + Name = 'SQLPS' + Path = 'C:\Program Files (x86)\Microsoft SQL Server\160\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' + } + ) + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule -Name @('SqlServer', 'SQLPS') | Should -Be 'C:\Program Files (x86)\Microsoft SQL Server\160\Tools\PowerShell\Modules\SQLPS' + } + } + } + + Context 'When specifying the parameter Refresh' { + BeforeAll { + Mock -CommandName Set-PSModulePath + Mock -CommandName Get-Module -MockWith { + return @{ + Name = 'SqlServer' + } + } + } + + It 'Should return the correct module name' { + Get-SqlDscPreferredModule -Refresh | Should -Be 'SqlServer' + + Should -Invoke -CommandName Set-PSModulePath -Exactly -Times 1 -Scope It + } + } +} diff --git a/tests/Unit/Public/Import-SqlDscPreferredModule.Tests.ps1 b/tests/Unit/Public/Import-SqlDscPreferredModule.Tests.ps1 index 9a4596230..1d8210322 100644 --- a/tests/Unit/Public/Import-SqlDscPreferredModule.Tests.ps1 +++ b/tests/Unit/Public/Import-SqlDscPreferredModule.Tests.ps1 @@ -134,22 +134,6 @@ Describe 'Import-SqlDscPreferredModule' -Tag 'Public' { return $importModuleResult } - $mockGetModuleSqlServer = { - # Return an array to test so that the latest version is only imported. - return @( - [PSCustomObject] @{ - Name = 'SqlServer' - Version = [Version] '1.0' - } - - [PSCustomObject] @{ - Name = 'SqlServer' - Version = [Version] '2.0' - } - ) - } - - Mock -CommandName Set-PSModulePath Mock -CommandName Push-Location Mock -CommandName Pop-Location } @@ -191,12 +175,9 @@ Describe 'Import-SqlDscPreferredModule' -Tag 'Public' { Context 'When module SqlServer exists, but not loaded into the session' { BeforeAll { Mock -CommandName Import-Module -MockWith $mockImportModule - Mock -CommandName Get-Module -ParameterFilter { - $PesterBoundParameters.ContainsKey('Name') - } - - Mock -CommandName Get-Module -MockWith $mockGetModuleSqlServer -ParameterFilter { - $FullyQualifiedName.Name -eq 'SqlServer' -and $ListAvailable -eq $true + Mock -CommandName Get-Module + Mock -CommandName Get-SqlDscPreferredModule -MockWith { + return 'SqlServer' } $mockExpectedModuleNameToImport = 'SqlServer' @@ -205,9 +186,7 @@ Describe 'Import-SqlDscPreferredModule' -Tag 'Public' { It 'Should import the SqlServer module without throwing' { { Import-SqlDscPreferredModule } | Should -Not -Throw - Should -Invoke -CommandName Get-Module -ParameterFilter { - $FullyQualifiedName.Name -eq 'SqlServer' -and $ListAvailable -eq $true - } -Exactly -Times 1 -Scope It + Should -Invoke -CommandName Get-SqlDscPreferredModule -Exactly -Times 1 -Scope It Should -Invoke -CommandName Push-Location -Exactly -Times 1 -Scope It Should -Invoke -CommandName Pop-Location -Exactly -Times 1 -Scope It Should -Invoke -CommandName Import-Module -Exactly -Times 1 -Scope It @@ -218,48 +197,17 @@ Describe 'Import-SqlDscPreferredModule' -Tag 'Public' { BeforeAll { Mock -CommandName Import-Module -MockWith $mockImportModule Mock -CommandName Remove-Module - Mock -CommandName Get-Module -ParameterFilter { - $PesterBoundParameters.ContainsKey('Name') + Mock -CommandName Get-SqlDscPreferredModule -MockWith { + return $sqlPsExpectedModulePath } $mockExpectedModuleNameToImport = $sqlPsExpectedModulePath - - Mock -CommandName Get-Module -MockWith { - # Return an array to test so that the latest version is only imported. - return @( - [PSCustomObject] @{ - Name = 'SQLPS' - # This is a path to an older version of SQL PS than $sqlPsLatestModulePath. - Path = 'C:\Program Files (x86)\Microsoft SQL Server\120\Tools\PowerShell\Modules\SQLPS\Sqlps.ps1' - } - - [PSCustomObject] @{ - Name = 'SQLPS' - Path = $sqlPsLatestModulePath - } - ) - } -ParameterFilter { - $FullyQualifiedName.Name -eq 'SQLPS' -and $ListAvailable -eq $true - } - - Mock -CommandName Get-Module -MockWith { - return $null - } -ParameterFilter { - $FullyQualifiedName.Name -eq 'SqlServer' -and $ListAvailable -eq $true - } } It 'Should import the SqlServer module without throwing' { { Import-SqlDscPreferredModule -Force } | Should -Not -Throw - Should -Invoke -CommandName Get-Module -ParameterFilter { - $FullyQualifiedName.Name -eq 'SqlServer' -and $ListAvailable -eq $true - } -Exactly -Times 1 -Scope It - - Should -Invoke -CommandName Get-Module -ParameterFilter { - $FullyQualifiedName.Name -eq 'SQLPS' -and $ListAvailable -eq $true - } -Exactly -Times 1 -Scope It - + Should -Invoke -CommandName Get-SqlDscPreferredModule -Exactly -Times 1 -Scope It Should -Invoke -CommandName Push-Location -Exactly -Times 1 -Scope It Should -Invoke -CommandName Pop-Location -Exactly -Times 1 -Scope It Should -Invoke -CommandName Remove-Module -Exactly -Times 1 -Scope It @@ -270,10 +218,10 @@ Describe 'Import-SqlDscPreferredModule' -Tag 'Public' { Context 'When neither SqlServer or SQLPS exists' { BeforeAll { Mock -CommandName Import-Module + Mock -CommandName Get-Module + Mock -CommandName Get-SqlDscPreferredModule $mockExpectedModuleNameToImport = $sqlPsExpectedModulePath - - Mock -CommandName Get-Module } It 'Should throw the correct error message' { @@ -283,14 +231,8 @@ Describe 'Import-SqlDscPreferredModule' -Tag 'Public' { { Import-SqlDscPreferredModule } | Should -Throw -ExpectedMessage $mockLocalizedString - Should -Invoke -CommandName Get-Module -ParameterFilter { - $FullyQualifiedName.Name -eq 'SqlServer' -and $ListAvailable -eq $true - } -Exactly -Times 1 -Scope It - - Should -Invoke -CommandName Get-Module -ParameterFilter { - $FullyQualifiedName.Name -eq 'SQLPS' -and $ListAvailable -eq $true - } -Exactly -Times 1 -Scope It - + Should -Invoke -CommandName Get-Module -Exactly -Times 1 -Scope It + Should -Invoke -CommandName Get-SqlDscPreferredModule -Exactly -Times 1 -Scope It Should -Invoke -CommandName Push-Location -Exactly -Times 0 -Scope It Should -Invoke -CommandName Pop-Location -Exactly -Times 0 -Scope It Should -Invoke -CommandName Import-Module -Exactly -Times 0 -Scope It