Skip to content

Get-SqlDscPreferredModule: Optionally specify which version of the SQL module is imported #1966

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

Merged
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
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- SqlServerDsc
- Updated pipeline files to support ModuleFast.
- `Get-SqlDscPreferredModule`
- Optionally specify what version of the the SQL preferred module to be imported using the SMODefaultModuleVersion environment variable ([issue #1965](https://github.com/dsccommunity/SqlServerDsc/issues/1965)).
- New private command:
- Get-SMOModuleCalculatedVersion - Returns the version of the SMO module as a string. SQLPS version 120 and 130 do not have the correct version set, so the file path is used to calculate the version.
- SqlSetup
- Added the parameter `SqlVersion` that can be used to set the SQL Server
version to be installed instead of it looking for version in the setup
Expand Down Expand Up @@ -41,6 +45,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated integration tests to use xPSDesiredStateConfiguration instead of PSDScResources.
- SqlWindowsFirewall
- Updated integration tests to use xPSDesiredStateConfiguration instead of PSDScResources.
- SqlServerDsc
- `Get-SqlDscPreferredModule`
- Now returns a PSModuleInfo object instead of just the module name.
- `Import-SqlDscPreferredModule`
- Handles PSModuleInfo objects from `Get-SqlDscPreferredModule` instead of strings.
- Sets -ErrorAction 'Stop' on Get-SqlDscPreferredModule to throw an error if no SQL module is found. The script-terminating error is caught and made into a statement-terminating error.

### Remove

- SqlServerDsc
- Removed PreferredModule_ModuleFound string in favor for more verbose PreferredModule_ModuleVersionFound.

## [16.4.0] - 2023-08-22

Expand Down
63 changes: 63 additions & 0 deletions source/Private/Get-SMOModuleCalculatedVersion.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<#
.SYNOPSIS
Returns the calculated version of an SMO PowerShell module.

.DESCRIPTION
Returns the calculated version of an SMO PowerShell module.

For SQLServer, the version is calculated using the System.Version
field with '-preview' appended for pre-release versions . For
example: 21.1.1 or 22.0.49-preview

For SQLPS, the version is calculated using the path of the module. For
example:
C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules
returns 130

.PARAMETER PSModuleInfo
Specifies the PSModuleInfo object for which to return the calculated version.

.EXAMPLE
Get-SMOModuleCalculatedVersion -PSModuleInfo (Get-Module -Name 'sqlps')

Returns the calculated version as a string.

.OUTPUTS
[System.String]
#>
function Get-SMOModuleCalculatedVersion
{
[OutputType([System.String])]
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[System.Management.Automation.PSModuleInfo]
$PSModuleInfo
)

process
{
$version = $null

if ($PSModuleInfo.Name -eq 'SQLPS')
{
<#
Parse the build version number '120', '130' from the Path.
Older version of SQLPS did not have correct versioning.
#>
$version = (Select-String -InputObject $PSModuleInfo.Path -Pattern '\\([0-9]{3})\\' -List).Matches.Groups[1].Value
}
else
{
$version = $PSModuleInfo.Version.ToString()

if ($PSModuleInfo.PrivateData.PSData.Prerelease)
{
$version = '{0}-{1}' -f $PSModuleInfo.Version, $PSModuleInfo.PrivateData.PSData.Prerelease
}
}

return $version
}
}
113 changes: 46 additions & 67 deletions source/Public/Get-SqlDscPreferredModule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,45 @@
that name will be used as the preferred module name instead of the default
module 'SqlServer'.

If the envrionment variable `SMODefaultModuleVersion` is set, then that
specific version of the preferred module will be searched for.

.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
Specifies if the session environment variable PSModulePath should be refreshed
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.
Returns the SqlServer PSModuleInfo object if it is installed, otherwise it
will return SQLPS PSModuleInfo object 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.
Updates the session environment variable PSModulePath and then returns the
SqlServer PSModuleInfo object if it is installed, otherwise it will return SQLPS
PSModuleInfo object 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.
Returns the MyModule PSModuleInfo object if it is installed, otherwise it will
return SQLPS PSModuleInfo object 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])]
[OutputType([PSModuleInfo])]
[CmdletBinding()]
param
(
Expand Down Expand Up @@ -92,79 +90,60 @@ function Get-SqlDscPreferredModule
}
}

$availableModuleName = $null
$availableModule = $null

$availableModule = Get-Module -FullyQualifiedName $Name -ListAvailable |
Select-Object -Property @(
'Name',
'Path',
$availableModules = Get-Module -Name $Name -ListAvailable |
ForEach-Object -Process {
@{
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
}
}
PSModuleInfo = $_
CalculatedVersion = $_ | Get-SMOModuleCalculatedVersion
}
)
}

foreach ($preferredModuleName in $Name)
{
$preferredModule = $availableModule |
Where-Object -Property 'Name' -EQ -Value $preferredModuleName
$preferredModules = $availableModules |
Where-Object -FilterScript { $_.PSModuleInfo.Name -eq $preferredModuleName }

if ($preferredModule)
if ($preferredModules)
{
if ($preferredModule.Name -eq 'SQLPS')
if ($env:SMODefaultModuleVersion)
{
# Get the latest version if available.
$preferredModule = $preferredModule |
Sort-Object -Property 'Version' -Descending |
# Get the version specified in $env:SMODefaultModuleVersion if available
$availableModule = $preferredModules |
Where-Object -FilterScript { $_.CalculatedVersion -eq $env:SMODefaultModuleVersion } |
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
# Get the latest version if available
$availableModule = $preferredModules |
Sort-Object -Property 'CalculatedVersion' -Descending |
Select-Object -First 1
}

Write-Verbose -Message ($script:localizedData.PreferredModule_ModuleFound -f $availableModuleName)
Write-Verbose -Message ($script:localizedData.PreferredModule_ModuleVersionFound -f $availableModule.PSModuleInfo.Name, $availableModule.CalculatedVersion)

break
}
}

if (-not $availableModuleName)
if (-not $availableModule)
{
$errorMessage = $script:localizedData.PreferredModule_ModuleNotFound
$errorMessage = $null

if ($env:SMODefaultModuleVersion)
{
$errorMessage = $script:localizedData.PreferredModule_ModuleVersionNotFound -f $env:SMODefaultModuleVersion
}
else
{
$errorMessage = $script:localizedData.PreferredModule_ModuleNotFound
}

# cSpell: disable-next
Write-Error -Message $errorMessage -Category 'ObjectNotFound' -ErrorId 'GSDPM0001' -TargetObject ($Name -join ', ')
}

return $availableModuleName
return $availableModule.PSModuleInfo
}
Loading