Repository navigation
SPSUpdate: harmonize Boolean config switches to accept 1/0 #77
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,7 +62,7 @@ | |
| # --- Binaries (REQUIRED block; used by -Action ProductUpdate) --------------------- | ||
| Binaries = @{ | ||
| # ProductUpdate : allow the binary installation step. | ||
| # Possible values : $true | $false. Default if omitted: $true | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $true | ||
| ProductUpdate = $true | ||
|
|
||
| # SetupFullPath : folder (local to each server) that holds the update binaries. | ||
|
|
@@ -80,7 +80,7 @@ | |
|
|
||
| # ShutdownServices : stop Search/Timer/IIS services during install to speed it up | ||
| # (they are restored to their prior state afterwards). | ||
| # Possible values : $true | $false. Default if omitted: $true | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $true | ||
| ShutdownServices = $true | ||
|
|
||
| # Schedule : OPTIONAL window restricting WHEN the binary install may run. Omit to | ||
|
|
@@ -108,12 +108,12 @@ | |
| # completion is not recorded until the grant is added. | ||
| Reboot = @{ | ||
| # Enable : allow SPSUpdate to reboot a server automatically after a CU install. | ||
| # Possible values : $true | $false. Default if omitted: $false | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $false | ||
| Enable = $false | ||
|
|
||
| # Force : reboot even when the installer did not request one (exit code 0). Leave | ||
| # $false to reboot strictly when a reboot was required (exit code 17022). | ||
| # Possible values : $true | $false. Default if omitted: $false | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $false | ||
| Force = $false | ||
|
|
||
| # Schedule : OPTIONAL window restricting WHEN a reboot may happen (same shape as | ||
|
|
@@ -129,17 +129,17 @@ | |
| # MountContentDatabase : mount the databases listed in the generated ContentDB | ||
| # inventory (typically for a SP2019 -> Subscription Edition migration). When either | ||
| # this or UpgradeContentDatabase is $true, the inventory JSON is (re)built on run. | ||
| # Possible values : $true | $false. Default if omitted: $false | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $false | ||
| MountContentDatabase = $false | ||
|
|
||
| # UpgradeContentDatabase : run Upgrade-SPContentDatabase on databases that NeedsUpgrade. | ||
| # Possible values : $true | $false. Default if omitted: $true | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $true | ||
| UpgradeContentDatabase = $true | ||
|
|
||
| # --- Side-by-side patching (OPTIONAL block) -------------------------------------- | ||
| SideBySideToken = @{ | ||
| # Enable : turn EnableSideBySide on the web applications and copy side-by-side files. | ||
| # Possible values : $true | $false. Default if omitted: $false | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $false | ||
| Enable = $false | ||
|
|
||
| # BuildVersion : the side-by-side token build. Leave empty to skip token config. | ||
|
|
@@ -155,7 +155,7 @@ | |
| # delegate the credential, so steps that need a second hop (config DB on SQL, or a | ||
| # binaries file share) may fail unless Kerberos delegation (KCD/RBCD) is configured. | ||
| # Leave off for secure, strict environments. | ||
| # Possible values : $true | $false. Default if omitted: $false | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $false | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 08f60cb. |
||
| AllowFallback = $false | ||
| } | ||
|
|
||
|
|
@@ -165,7 +165,7 @@ | |
| # parallel content-database sequences in visible PowerShell windows instead of hidden | ||
| # scheduled tasks, so you can watch per-sequence progress live. Unattended/scheduled | ||
| # runs always use scheduled tasks regardless of this setting. | ||
| # Possible values : $true | $false. Default if omitted: $false | ||
| # Possible values : $true | $false (1 | 0 also accepted). Default if omitted: $false | ||
| InteractiveSequences = $false | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| function ConvertTo-SPSConfigBoolean { | ||
| <# | ||
| .SYNOPSIS | ||
| Validates and normalizes a Boolean configuration value. | ||
|
|
||
| .DESCRIPTION | ||
| ConvertTo-SPSConfigBoolean gives every Boolean switch in the SPSUpdate | ||
| configuration the same, predictable contract. It accepts a real Boolean | ||
| ($true / $false) or the integers 1 / 0, and returns the corresponding | ||
| [bool]. Any other value (an out-of-range integer, a string such as 'true' | ||
| or 'yes', $null, ...) throws a clear error naming the property, so a typo | ||
| in the psd1 fails fast instead of being silently coerced to $true. | ||
|
|
||
| Only genuine integer types are accepted for the 1/0 form; a string like | ||
| '1' is rejected on purpose, to avoid the PowerShell footgun where | ||
| [bool]'false' evaluates to $true. | ||
|
|
||
| .PARAMETER Value | ||
| The raw value read from the configuration for the property. | ||
|
|
||
| .PARAMETER PropertyName | ||
| The dotted property path (for example 'Reboot.Enable') used in the error | ||
| message so the operator knows exactly which key to fix. | ||
|
|
||
| .EXAMPLE | ||
| ConvertTo-SPSConfigBoolean -Value 1 -PropertyName 'Reboot.Enable' | ||
|
|
||
| .EXAMPLE | ||
| ConvertTo-SPSConfigBoolean -Value $false -PropertyName 'Remoting.AllowFallback' | ||
| #> | ||
| [CmdletBinding()] | ||
| [OutputType([System.Boolean])] | ||
| param | ||
| ( | ||
| [Parameter(Mandatory = $true)] | ||
| [AllowNull()] | ||
| $Value, | ||
|
|
||
| [Parameter(Mandatory = $true)] | ||
| [System.String] | ||
| $PropertyName | ||
| ) | ||
|
|
||
| if ($Value -is [bool]) { | ||
| return $Value | ||
| } | ||
|
|
||
| # Accept any integral type valued 0 or 1; the type guard keeps strings like '0'/'1' | ||
| # out (otherwise '0' -eq 0 would match via PowerShell string coercion). | ||
| $integralTypes = @([byte], [sbyte], [int16], [uint16], [int32], [uint32], [int64], [uint64]) | ||
| if (($null -ne $Value) -and ($Value.GetType() -in $integralTypes) -and ($Value -eq 0 -or $Value -eq 1)) { | ||
| return [System.Boolean][int64]$Value | ||
| } | ||
|
|
||
| throw "Configuration property '$PropertyName' must be a Boolean (`$true/`$false) or 0/1, not '$Value'." | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # Behavioural tests for ConvertTo-SPSConfigBoolean: the shared validator/normalizer | ||
| # that gives every Boolean configuration switch the same $true/$false/1/0 contract. | ||
|
|
||
| BeforeAll { | ||
| $repoRoot = Split-Path -Path $PSScriptRoot -Parent | ||
| $modulePath = Join-Path -Path $repoRoot -ChildPath 'src/Modules/SPSUpdate.Common/SPSUpdate.Common.psd1' | ||
| Import-Module -Name $modulePath -Force | ||
| } | ||
|
|
||
| AfterAll { | ||
| Remove-Module -Name SPSUpdate.Common -Force -ErrorAction SilentlyContinue | ||
| } | ||
|
|
||
| Describe 'ConvertTo-SPSConfigBoolean' { | ||
| Context 'Accepted values' { | ||
| It 'returns $true for a $true Boolean' { | ||
| ConvertTo-SPSConfigBoolean -Value $true -PropertyName 'Reboot.Enable' | Should -BeTrue | ||
| } | ||
|
|
||
| It 'returns $false for a $false Boolean' { | ||
| ConvertTo-SPSConfigBoolean -Value $false -PropertyName 'Reboot.Enable' | Should -BeFalse | ||
| } | ||
|
|
||
| It 'normalizes the integer 1 to $true' { | ||
| $result = ConvertTo-SPSConfigBoolean -Value 1 -PropertyName 'Reboot.Enable' | ||
| $result | Should -BeOfType [System.Boolean] | ||
| $result | Should -BeTrue | ||
| } | ||
|
|
||
| It 'normalizes the integer 0 to $false' { | ||
| $result = ConvertTo-SPSConfigBoolean -Value 0 -PropertyName 'Reboot.Enable' | ||
| $result | Should -BeOfType [System.Boolean] | ||
| $result | Should -BeFalse | ||
| } | ||
|
|
||
| It 'accepts other integral types valued 1 (byte, uint16, uint64)' { | ||
| ConvertTo-SPSConfigBoolean -Value ([byte]1) -PropertyName 'Reboot.Enable' | Should -BeTrue | ||
| ConvertTo-SPSConfigBoolean -Value ([uint16]1) -PropertyName 'Reboot.Enable' | Should -BeTrue | ||
| ConvertTo-SPSConfigBoolean -Value ([uint64]1) -PropertyName 'Reboot.Enable' | Should -BeTrue | ||
| } | ||
|
|
||
| It 'accepts other integral types valued 0 (sbyte, uint32)' { | ||
| ConvertTo-SPSConfigBoolean -Value ([sbyte]0) -PropertyName 'Reboot.Enable' | Should -BeFalse | ||
| ConvertTo-SPSConfigBoolean -Value ([uint32]0) -PropertyName 'Reboot.Enable' | Should -BeFalse | ||
| } | ||
| } | ||
|
|
||
| Context 'Rejected values' { | ||
| It 'throws for an out-of-range integer' { | ||
| { ConvertTo-SPSConfigBoolean -Value 2 -PropertyName 'Reboot.Enable' } | | ||
| Should -Throw -ExpectedMessage "*'Reboot.Enable'*" | ||
| } | ||
|
|
||
| It 'rejects the string "1" (no string coercion)' { | ||
| { ConvertTo-SPSConfigBoolean -Value '1' -PropertyName 'Reboot.Force' } | | ||
| Should -Throw -ExpectedMessage "*'Reboot.Force'*" | ||
| } | ||
|
|
||
| It 'rejects the string "0" (no string coercion)' { | ||
| { ConvertTo-SPSConfigBoolean -Value '0' -PropertyName 'Reboot.Force' } | Should -Throw | ||
| } | ||
|
|
||
| It 'rejects an arbitrary truthy string such as "false"' { | ||
| { ConvertTo-SPSConfigBoolean -Value 'false' -PropertyName 'Remoting.AllowFallback' } | | ||
| Should -Throw -ExpectedMessage "*'Remoting.AllowFallback'*" | ||
| } | ||
|
|
||
| It 'rejects "yes"' { | ||
| { ConvertTo-SPSConfigBoolean -Value 'yes' -PropertyName 'Execution.InteractiveSequences' } | Should -Throw | ||
| } | ||
|
|
||
| It 'rejects $null' { | ||
| { ConvertTo-SPSConfigBoolean -Value $null -PropertyName 'Reboot.Enable' } | Should -Throw | ||
| } | ||
|
|
||
| It 'names the offending property in the error message' { | ||
| { ConvertTo-SPSConfigBoolean -Value 7 -PropertyName 'Binaries.ProductUpdate' } | | ||
| Should -Throw -ExpectedMessage "*'Binaries.ProductUpdate'*" | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 08f60cb.
wiki/Configuration.mdnow carries one shared Boolean switches rule listing all nine switches and stating they accept$true/$falseor1/0, with anything else rejected. The example psd1 comments were already updated to match.