Skip to content

Commit

Permalink
SqlServerDsc: Add public commands for setup actions (#1784)
Browse files Browse the repository at this point in the history
- SqlServerDsc
  - The following private functions were added to the module (see comment-based
    help for more information):
    - `Assert-ElevatedUser`
    - `Assert-RequiredCommandParameter`
    - `Test-IsNumericType`
    - `Assert-SetupActionProperties`
    - `Invoke-SetupAction`
  - The following public functions were added to the module (see comment-based
    help for more information):
    - `Install-SqlDscServer`
    - `Uninstall-SqlDscServer`
    - `Add-SqlDscNode`
    - `Remove-SqlDscNode`
    - `Repair-SqlDscServer`
    - `Complete-SqlDscImage`
    - `Complete-SqlDscFailoverCluster`
    - `Initialize-SqlDscRebuildDatabase`
  • Loading branch information
johlju authored Nov 24, 2022
1 parent 22abcdb commit 1026d20
Show file tree
Hide file tree
Showing 32 changed files with 13,196 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"powershell.codeFormatting.alignPropertyValuePairs": true,
"powershell.codeFormatting.useConstantStrings": true,
"powershell.developer.bundledModulesPath": "${cwd}/output/RequiredModules",
"powershell.scriptAnalysis.settingsPath": ".vscode\\analyzersettings.psd1",
"powershell.scriptAnalysis.settingsPath": ".vscode/analyzersettings.psd1",
"powershell.scriptAnalysis.enable": true,
"files.trimTrailingWhitespace": true,
"files.trimFinalNewlines": true,
Expand Down
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- SqlServerDsc
- The following private functions were added to the module (see comment-based
help for more information):
- `Assert-ElevatedUser`
- `Assert-RequiredCommandParameter`
- `Test-IsNumericType`
- `Assert-SetupActionProperties`
- `Invoke-SetupAction`
- The following public functions were added to the module (see comment-based
help for more information):
- `Install-SqlDscServer`
- `Uninstall-SqlDscServer`
- `Add-SqlDscNode`
- `Remove-SqlDscNode`
- `Repair-SqlDscServer`
- `Complete-SqlDscImage`
- `Complete-SqlDscFailoverCluster`
- `Initialize-SqlDscRebuildDatabase`

### Changed

- SqlServerDsc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,7 @@ function Restart-ReportingServicesService
#>
function Invoke-Query
{
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when the output type is not available. The ScriptAnalyzer rule UseSyntacticallyCorrectExamples will always error in the editor due to https://github.com/indented-automation/Indented.ScriptAnalyzerRules/issues/8.')]
[CmdletBinding(DefaultParameterSetName = 'SqlServer')]
param
(
Expand Down
45 changes: 45 additions & 0 deletions source/Private/Assert-ElevatedUser.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<#
.SYNOPSIS
Assert that the user has elevated the PowerShell session.
.DESCRIPTION
Assert that the user has elevated the PowerShell session.
.EXAMPLE
Assert-ElevatedUser
Throws an exception if the user has not elevated the PowerShell session.
.OUTPUTS
None.
#>
function Assert-ElevatedUser
{
[CmdletBinding()]
param ()

$isElevated = $false

if ($IsMacOS -or $IsLinux)
{
$isElevated = (id -u) -eq 0
}
else
{
[Security.Principal.WindowsPrincipal] $user = [Security.Principal.WindowsIdentity]::GetCurrent()

$isElevated = $user.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

if (-not $isElevated)
{
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
$script:localizedData.IsElevated_UserNotElevated,
'AEU0001',
[System.Management.Automation.ErrorCategory]::InvalidOperation,
'Command parameters'
)
)
}
}
93 changes: 93 additions & 0 deletions source/Private/Assert-RequiredCommandParameter.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<#
.SYNOPSIS
Assert that required parameters has been specified.
.DESCRIPTION
Assert that required parameters has been specified, and throws an exception if not.
.PARAMETER BoundParameter
A hashtable containing the parameters to evaluate. Normally this is set to
$PSBoundParameters.
.PARAMETER RequiredParameter
One or more parameter names that is required to have been specified.
.PARAMETER IfParameterPresent
One or more parameter names that if specified will trigger the evaluation.
If neither of the parameter names has been specified the evaluation of required
parameters are not made.
.EXAMPLE
Assert-RequiredCommandParameter -BoundParameter $PSBoundParameters -RequiredParameter @('PBStartPortRange', 'PBEndPortRange')
Throws an exception if either of the two parameters are not specified.
.EXAMPLE
Assert-RequiredCommandParameter -BoundParameter $PSBoundParameters -RequiredParameter @('Property2', 'Property3') -IfParameterPresent @('Property1')
Throws an exception if the parameter 'Property1' is specified and one of the required parameters are not.
.OUTPUTS
None.
.NOTES
This command should probably be a parmeter set of the command Assert-BoundParameter
in the module DscResource.Common, instead of being a separate command.
#>
function Assert-RequiredCommandParameter
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[System.Collections.Hashtable]
$BoundParameter,

[Parameter(Mandatory = $true)]
[System.String[]]
$RequiredParameter,

[Parameter()]
[System.String[]]
$IfParameterPresent
)

$evaluateRequiredParameter = $true

if ($PSBoundParameters.ContainsKey('IfParameterPresent'))
{
$hasIfParameterPresent = $BoundParameter.Keys.Where( { $_ -in $IfParameterPresent } )

if (-not $hasIfParameterPresent)
{
$evaluateRequiredParameter = $false
}
}

if ($evaluateRequiredParameter)
{
foreach ($parameter in $RequiredParameter)
{
if ($parameter -notin $BoundParameter.Keys)
{
$errorMessage = if ($PSBoundParameters.ContainsKey('IfParameterPresent'))
{
$script:localizedData.RequiredCommandParameter_SpecificParametersMustAllBeSetWhenParameterExist -f ($RequiredParameter -join ''', '''), ($IfParameterPresent -join ''', ''')
}
else
{
$script:localizedData.RequiredCommandParameter_SpecificParametersMustAllBeSet -f ($RequiredParameter -join ''', ''')
}

$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
$errorMessage,
'ARCP0001', # cspell: disable-line
[System.Management.Automation.ErrorCategory]::InvalidOperation,
'Command parameters'
)
)
}
}
}
}
188 changes: 188 additions & 0 deletions source/Private/Assert-SetupActionProperties.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
<#
.SYNOPSIS
Assert that the bound parameters are set as required
.DESCRIPTION
Assert that required parameters has been specified, and throws an exception if not.
.PARAMETER Property
A hashtable containing the parameters to evaluate. Normally this is set to
$PSBoundParameters.
.PARAMETER SetupAction
A string value representing the setup action that is gonna be executed.
.EXAMPLE
Assert-SetupActionProperties -Property $PSBoundParameters -SetupAction 'Install'
Throws an exception if the bound parameters are not in the correct state.
.OUTPUTS
None.
.NOTES
This function is used by the command Invoke-SetupAction to verify that
the bound parameters are in the required state.
#>
function Assert-SetupActionProperties
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[System.Collections.Hashtable]
$Property,

[Parameter(Mandatory = $true)]
[System.String]
$SetupAction
)

# If one of the properties PBStartPortRange and PBEndPortRange are specified, then both must be specified.
$assertParameters = @('PBStartPortRange', 'PBEndPortRange')

$assertRequiredCommandParameterParameters = @{
BoundParameter = $Property
RequiredParameter = $assertParameters
IfParameterPresent = $assertParameters
}

Assert-RequiredCommandParameter @assertRequiredCommandParameterParameters

# The parameter UseSqlRecommendedMemoryLimits is mutually exclusive to SqlMinMemory and SqlMaxMemory.
Assert-BoundParameter -BoundParameterList $Property -MutuallyExclusiveList1 @(
'UseSqlRecommendedMemoryLimits'
) -MutuallyExclusiveList2 @(
'SqlMinMemory'
'SqlMaxMemory'
)

# If Role is set to SPI_AS_NewFarm then the specific parameters are required.
if ($Property.ContainsKey('Role') -and $Property.Role -eq 'SPI_AS_NewFarm')
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @(
'FarmAccount'
'FarmPassword'
'Passphrase'
'FarmAdminiPort' # cspell: disable-line
)
}

# If the parameter SecurityMode is set to 'SQL' then the parameter SAPwd is required.
if ($Property.ContainsKey('SecurityMode') -and $Property.SecurityMode -eq 'SQL')
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @('SAPwd')
}

# If the parameter FileStreamLevel is set and is greater or equal to 2 then the parameter FileStreamShareName is required.
if ($Property.ContainsKey('FileStreamLevel') -and $Property.FileStreamLevel -ge 2)
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @('FileStreamShareName')
}

# If a *SvcAccount is specified then the accompanying *SvcPassword must be set unless it is a (global) managed service account, virtual account, or a built-in account.
$accountProperty = @(
'PBEngSvcAccount'
'PBDMSSvcAccount' # cSpell: disable-line
'AgtSvcAccount'
'ASSvcAccount'
'FarmAccount'
'SqlSvcAccount'
'ISSvcAccount'
'RSSvcAccount'
)

foreach ($currentAccountProperty in $accountProperty)
{
if ($currentAccountProperty -in $Property.Keys)
{
# If not (global) managed service account, virtual account, or a built-in account.
if ((Test-ServiceAccountRequirePassword -Name $Property.$currentAccountProperty))
{
$assertPropertyName = $currentAccountProperty -replace 'Account', 'Password'

Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter $assertPropertyName
}
}
}

# If feature ARC is specified then the all the Azure* parameters must be set (except AzureArcProxy).
if ($Property.ContainsKey('Features') -and $Property.Features -contains 'ARC')
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @(
'AzureSubscriptionId'
'AzureResourceGroup'
'AzureRegion'
'AzureTenantId'
'AzureServicePrincipal'
'AzureServicePrincipalSecret'
)
}

# If feature is SQLENGINE, then for specified setup actions the parameter AgtSvcAccount is mandatory.
if ($SetupAction -in ('Install', 'CompleteImage', 'InstallFailoverCluster', 'PrepareFailoverCluster', 'AddNode'))
{
if ($Property.ContainsKey('Features') -and $Property.Features -contains 'SQLENGINE')
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @('AgtSvcAccount')
}
}

if ($SetupAction -in ('InstallFailoverCluster', 'PrepareFailoverCluster', 'AddNode'))
{
# The parameter ASSvcAccount is mandatory if feature AS is installed and setup action is InstallFailoverCluster, PrepareFailoverCluster, or AddNode.
if ($Property.ContainsKey('Features') -and $Property.Features -contains 'AS')
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @('ASSvcAccount')
}

# The parameter SqlSvcAccount is mandatory if feature SQLENGINE is installed and setup action is InstallFailoverCluster, PrepareFailoverCluster, or AddNode.
if ($Property.ContainsKey('Features') -and $Property.Features -contains 'SQLENGINE')
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @('SqlSvcAccount')
}

# The parameter ISSvcAccount is mandatory if feature IS is installed and setup action is InstallFailoverCluster, PrepareFailoverCluster, or AddNode.
if ($Property.ContainsKey('Features') -and $Property.Features -contains 'IS')
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @('ISSvcAccount')
}

if ($Property.ContainsKey('Features') -and $Property.Features -contains 'RS')
{
Assert-RequiredCommandParameter -BoundParameter $Property -RequiredParameter @('RSSvcAccount')
}
}

# The ASServerMode value PowerPivot is not allowed when parameter set is InstallFailoverCluster or CompleteFailoverCluster.
if ($SetupAction -in ('InstallFailoverCluster', 'CompleteFailoverCluster'))
{
if ($Property.ContainsKey('ASServerMode') -and $Property.ASServerMode -eq 'PowerPivot')
{
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
($script:localizedData.InstallSqlServerProperties_ASServerModeInvalidValue -f $SetupAction),
'ASAP0001', # cSpell: disable-line
[System.Management.Automation.ErrorCategory]::InvalidOperation,
'Command parameters'
)
)
}
}

# The ASServerMode value PowerPivot is not allowed when parameter set is InstallFailoverCluster or CompleteFailoverCluster.
if ($SetupAction -in ('AddNode'))
{
if ($Property.ContainsKey('RsInstallMode') -and $Property.RsInstallMode -ne 'FilesOnlyMode')
{
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
($script:localizedData.InstallSqlServerProperties_RsInstallModeInvalidValue -f $SetupAction),
'ASAP0002', # cSpell: disable-line
[System.Management.Automation.ErrorCategory]::InvalidOperation,
'Command parameters'
)
)
}
}
}
Loading

0 comments on commit 1026d20

Please sign in to comment.