Skip to content

Commit

Permalink
Get-SqlDscPreferredModule: Optionally specify which version of the SQ…
Browse files Browse the repository at this point in the history
…L module is imported (#1966)

- SqlServerDsc
  - `Get-SqlDscPreferredModule`
    - Optionally specify what version of the the SQL preferred module to be imported using the SMODefaultModuleVersion environment variable ([issue #1965](#1965)).
 - `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.
  - Removed PreferredModule_ModuleFound string in favor for more verbose PreferredModule_ModuleVersionFound.
- 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.
  • Loading branch information
YaroBear authored Sep 1, 2023
1 parent 472ef04 commit 9de42c3
Show file tree
Hide file tree
Showing 8 changed files with 641 additions and 272 deletions.
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

0 comments on commit 9de42c3

Please sign in to comment.