Skip to content

Commit

Permalink
Get-SqlDscPreferredModule: New command (#1898)
Browse files Browse the repository at this point in the history
- SqlServerDsc
  - New public command:
    - `Get-SqlDscPreferredModule` - Returns the name of the first available
      preferred module (issue #1879).
- `Import-SqlDscPreferredModule`
  - Refactor to re-use the command `Get-SqlDscPreferredModule`.
  • Loading branch information
johlju authored Apr 8, 2023
1 parent 4602416 commit ac13d70
Show file tree
Hide file tree
Showing 6 changed files with 617 additions and 137 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
175 changes: 175 additions & 0 deletions source/Public/Get-SqlDscPreferredModule.ps1
Original file line number Diff line number Diff line change
@@ -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
}
67 changes: 1 addition & 66 deletions source/Public/Import-SqlDscPreferredModule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
6 changes: 4 additions & 2 deletions source/en-US/SqlServerDsc.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit ac13d70

Please sign in to comment.