From 33d8355ed0289ba45ba90382dd994426fdbb0b19 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 17 Mar 2022 20:59:35 +0100 Subject: [PATCH 1/2] Fixing #1398, #1340 and other minor improvements --- CHANGELOG.md | 18 ++- .../Readme.md | 16 +- .../MSFT_SPDistributedCacheService/Readme.md | 4 +- .../MSFT_SPFarmPropertyBag.psm1 | 131 +++++++++++++-- .../MSFT_SPFarmPropertyBag.schema.mof | 1 + .../MSFT_SPFarmPropertyBag/readme.md | 4 + .../MSFT_SPInstall/MSFT_SPInstall.psm1 | 9 ++ .../MSFT_SPSearchServiceApp.psm1 | 29 +++- .../MSFT_SPShellAdmins.psm1 | 96 +++++++---- .../1-AddStringFarmPropertyBag.ps1 | 64 ++++++++ .../2-AddBoolToFarmPropertyBag.ps1 | 64 ++++++++ ...yBag.ps1 => 3-AddIntToFarmPropertyBag.ps1} | 9 +- ...rtyBag.ps1 => 4-RemoveFarmPropertyBag.ps1} | 6 +- .../SharePointDsc.SPFarmPropertyBag.Tests.ps1 | 151 +++++++++++++++++- .../SharePointDsc.SPInstall.Tests.ps1 | 77 +++++++++ 15 files changed, 605 insertions(+), 74 deletions(-) create mode 100644 SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-AddStringFarmPropertyBag.ps1 create mode 100644 SharePointDsc/Examples/Resources/SPFarmPropertyBag/2-AddBoolToFarmPropertyBag.ps1 rename SharePointDsc/Examples/Resources/SPFarmPropertyBag/{1-AddFarmPropertyBag.ps1 => 3-AddIntToFarmPropertyBag.ps1} (80%) rename SharePointDsc/Examples/Resources/SPFarmPropertyBag/{1-RemoveFarmPropertyBag.ps1 => 4-RemoveFarmPropertyBag.ps1} (87%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f85f4ef8d..aa6287c83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- SPFarmPropertyBag + - Added support for boolean and int32 data types +- SPInstall + - Added additional ExitCode for incorrect license key +- SPShellAdmin + - Added additional logging to improve troubleshooting + ### Fixed + +- SPSearchServiceApp + - Fixed issue where the database permissions were not corrected for new + search service applications. - SPWebApplication - - Fixed an issue where the Set method tried to use the Parameter SecureSocketsLayer with Set-SPWebApplication on SharePoint Server older than Subscription Edition. + - Fixed an issue where the Set method tried to use the Parameter SecureSocketsLayer with + Set-SPWebApplication on SharePoint Server older than Subscription Edition. ## [5.1.0] - 2022-02-24 @@ -182,7 +196,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 created, resulting in other errors. - SPSearchTopology - Fixed issue where an error was thrown if the specified RootDirectory didn't exist on the - current server but did exist on the target server. + current server but did exist on the target server. - Fixed issue with using FQDNs instead of NetBIOS server names. - SPSite - Implemented workaround to prevent issue with creating site collections immediately after diff --git a/SharePointDsc/DSCResources/MSFT_SPDistributedCacheClientSettings/Readme.md b/SharePointDsc/DSCResources/MSFT_SPDistributedCacheClientSettings/Readme.md index 8bc6e7931..4061937cd 100644 --- a/SharePointDsc/DSCResources/MSFT_SPDistributedCacheClientSettings/Readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPDistributedCacheClientSettings/Readme.md @@ -5,8 +5,14 @@ This resource is responsible for configuring the distributed cache client settings. It only accepts Ensure='Present' as a key. The resource can -configure the following cache components: DistributedLogonTokenCache, -DistributedViewStateCache, DistributedAccessCache, -DistributedActivityFeedCache, DistributedActivityFeedLMTCache, -DistributedBouncerCache, DistributedDefaultCache, DistributedSearchCache, -DistributedSecurityTrimmingCache, and DistributedServerToAppServerAccessTokenCache. +configure the following cache components: +- DistributedLogonTokenCache +- DistributedViewStateCache +- DistributedAccessCache +- DistributedActivityFeedCache +- DistributedActivityFeedLMTCache +- DistributedBouncerCache +- DistributedDefaultCache +- DistributedSearchCache +- DistributedSecurityTrimmingCache +- DistributedServerToAppServerAccessTokenCache. diff --git a/SharePointDsc/DSCResources/MSFT_SPDistributedCacheService/Readme.md b/SharePointDsc/DSCResources/MSFT_SPDistributedCacheService/Readme.md index c3c2996c2..7deba6359 100644 --- a/SharePointDsc/DSCResources/MSFT_SPDistributedCacheService/Readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPDistributedCacheService/Readme.md @@ -5,8 +5,8 @@ This resource is responsible for provisioning the distributed cache to the service it runs on. This is required in your farm on at least one server (as -the behavior of SPCreateFarm and SPJoinFarm is to not enroll every server as a -cache server). The service will be provisioned or de-provisioned based on the +the behavior of SPFarm is to not enroll every server as a cache server). +The service will be provisioned or de-provisioned based on the Ensure property, and when provisioned the CacheSizeInMB property and ServiceAccount property will be used to configure it. The property createFirewallRules is used to determine if exceptions should be added to the diff --git a/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/MSFT_SPFarmPropertyBag.psm1 b/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/MSFT_SPFarmPropertyBag.psm1 index 023b6b572..fc0e97e49 100644 --- a/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/MSFT_SPFarmPropertyBag.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/MSFT_SPFarmPropertyBag.psm1 @@ -12,13 +12,39 @@ function Get-TargetResource [System.String] $Value, + [Parameter()] + [ValidateSet("Boolean", "String", "Int32")] + [System.String] + $ParameterType = 'String', + [Parameter()] [ValidateSet("Present", "Absent")] [System.String] $Ensure = 'Present' ) - Write-Verbose -Message "Looking for SPFarm property '$Name'" + Write-Verbose -Message "Getting SPFarm property '$Key'" + + if ($ParameterType -eq 'Boolean' -and $Value -notin @('True', 'False')) + { + $message = ("Value can only be True or False when ParameterType is Boolean. Current value: $Value") + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + $int = 0 + if ($ParameterType -eq 'Int32' -and [Int32]::TryParse($Value, [ref]$int) -eq $false) + { + $message = ("Value has to be a number when ParameterType is Int32. Current value: $Value") + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } $result = Invoke-SPDscCommand -Arguments $PSBoundParameters ` -ScriptBlock { @@ -26,11 +52,11 @@ function Get-TargetResource try { - $spFarm = Get-SPFarm -ErrorAction SilentlyContinue + $spFarm = Get-SPFarm -ErrorAction SilentlyContinue -Verbose:$false } catch { - Write-Verbose -Message ("No local SharePoint farm was detected.") + Write-Verbose -Message ('No local SharePoint farm was detected.') return @{ Key = $params.Key Value = $null @@ -45,25 +71,53 @@ function Get-TargetResource if ($spFarm.Properties.Contains($params.Key) -eq $true) { $localEnsure = "Present" - $currentValue = $spFarm.Properties[$params.Key] + $value = $spFarm.Properties[$params.Key] + switch ($value.GetType().Name) + { + 'Boolean' + { + $currentType = 'Boolean' + if ($value) + { + $currentValue = 'true' + } + else + { + $currentValue = 'false' + } + } + 'String' + { + $currentType = 'String' + $currentValue = $spFarm.Properties[$params.Key] + } + 'Int32' + { + $currentType = 'Int32' + $currentValue = $spFarm.Properties[$params.Key].ToString() + } + } } else { - $localEnsure = "Absent" $currentValue = $null + $currentType = "" + $localEnsure = "Absent" } } } else { $currentValue = $null + $currentType = "" $localEnsure = 'Absent' } return @{ - Key = $params.Key - Value = $currentValue - Ensure = $localEnsure + Key = $params.Key + Value = $currentValue + ParameterType = $currentType + Ensure = $localEnsure } } return $result @@ -82,13 +136,39 @@ function Set-TargetResource() [System.String] $Value, + [Parameter()] + [ValidateSet("Boolean", "String", "Int32")] + [System.String] + $ParameterType = 'String', + [Parameter()] [ValidateSet("Present", "Absent")] [System.String] $Ensure = 'Present' ) - Write-Verbose -Message "Setting SPFarm property '$Name'" + Write-Verbose -Message "Setting SPFarm property '$Key'" + + if ($ParameterType -eq 'Boolean' -and $Value -notin @('True', 'False')) + { + $message = ("Value can only be True or False when ParameterType is Boolean. Current value: $Value") + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + $int = 0 + if ($ParameterType -eq 'Int32' -and [Int32]::TryParse($Value, [ref]$int) -eq $false) + { + $message = ("Value has to be a number when ParameterType is Int32. Current value: $Value") + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } Invoke-SPDscCommand -Arguments @($PSBoundParameters, $MyInvocation.MyCommand.Source) ` -ScriptBlock { @@ -97,11 +177,11 @@ function Set-TargetResource() try { - $spFarm = Get-SPFarm -ErrorAction SilentlyContinue + $spFarm = Get-SPFarm -ErrorAction SilentlyContinue -Verbose:$false } catch { - $message = "No local SharePoint farm was detected." + $message = 'No local SharePoint farm was detected.' Add-SPDscEvent -Message $message ` -EntryType 'Error' ` -EventID 100 ` @@ -114,17 +194,31 @@ function Set-TargetResource() if ($params.Value) { Write-Verbose -Message "Adding property '$params.Key'='$params.value' to SPFarm.properties" - $spFarm.Properties[$params.Key] = $params.Value + switch ($params.ParameterType) + { + 'Boolean' + { + $spFarm.Properties[$params.Key] = [System.Convert]::ToBoolean($params.Value) + } + 'String' + { + $spFarm.Properties[$params.Key] = $params.Value + } + 'Int32' + { + $spFarm.Properties[$params.Key] = [Int32]::Parse($params.Value) + } + } $spFarm.Update() } else { - Write-Warning -Message 'Ensure = Present, value parameter cannot be null' + Write-Warning -Message 'Ensure = Present, parameter Value cannot be null' } } else { - Write-Verbose -Message "Removing property '$params.Key' from SPFarm.properties" + Write-Verbose -Message "Removing property '$($params.Key)' from SPFarm.properties" $spFarm.Properties.Remove($params.Key) $spFarm.Update() @@ -146,13 +240,18 @@ function Test-TargetResource() [System.String] $Value, + [Parameter()] + [ValidateSet("Boolean", "String", "Int32")] + [System.String] + $ParameterType = 'String', + [Parameter()] [ValidateSet("Present", "Absent")] [System.String] $Ensure = 'Present' ) - Write-Verbose -Message "Testing SPFarm property '$Name'" + Write-Verbose -Message "Testing SPFarm property '$Key'" $CurrentValues = Get-TargetResource @PSBoundParameters @@ -162,7 +261,7 @@ function Test-TargetResource() $result = Test-SPDscParameterState -CurrentValues $CurrentValues ` -Source $($MyInvocation.MyCommand.Source) ` -DesiredValues $PSBoundParameters ` - -ValuesToCheck @('Ensure', 'Key', 'Value') + -ValuesToCheck @('Ensure', 'Key', 'Value', 'ParameterType') Write-Verbose -Message "Test-TargetResource returned $result" diff --git a/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/MSFT_SPFarmPropertyBag.schema.mof b/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/MSFT_SPFarmPropertyBag.schema.mof index d5437dbf2..1bc2852c8 100644 --- a/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/MSFT_SPFarmPropertyBag.schema.mof +++ b/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/MSFT_SPFarmPropertyBag.schema.mof @@ -3,5 +3,6 @@ class MSFT_SPFarmPropertyBag : OMI_BaseResource { [Key, Description("The key of the SPFarm property bag")] string Key; [Write, Description("Value of the SPfarm property bag")] String Value; + [Write, Description("Type of the data in the Value parameter"), ValueMap{"Boolean","String","Int32"}, Values{"Boolean","String","Int32"}] string ParameterType; [Write, Description("Set to present to ensure the SPfarm property exists, or absent to ensure it is removed"), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; }; diff --git a/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/readme.md b/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/readme.md index 1e495a0dd..f511961cf 100644 --- a/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPFarmPropertyBag/readme.md @@ -6,5 +6,9 @@ This resource is used to work with SharePoint Property Bags at the farm level. The account that runs this resource must be a farm administrator. +The Value parameter must be in string format, but with the ParameterType +parameter, you can specify of which data type the data in Value is: String, +Boolean or Int32. See the examples for more information. + The default value for the Ensure parameter is Present. When not specifying this parameter, the property bag is configured. diff --git a/SharePointDsc/DSCResources/MSFT_SPInstall/MSFT_SPInstall.psm1 b/SharePointDsc/DSCResources/MSFT_SPInstall/MSFT_SPInstall.psm1 index 194b722da..11697b10f 100644 --- a/SharePointDsc/DSCResources/MSFT_SPInstall/MSFT_SPInstall.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPInstall/MSFT_SPInstall.psm1 @@ -435,6 +435,15 @@ function Set-TargetResource throw $message } } + 30030 + { + $message = "SharePoint install failed: Incorrect license key!" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } 30203 { $message = "SharePoint install failed, license terms are not accepted." diff --git a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 index 28988a7f0..b11d530e8 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 @@ -202,8 +202,8 @@ function Get-TargetResource -Database $analyticsDB ` -User $farmAccount ` -DatabaseCredentials $params.DatabaseCredentials) -eq $false + Write-Verbose -Message "Farm Account Permissions Need Correcting: $farmAccountPermissionsNeedCorrecting" } - Write-Verbose -Message "Farm Account Permissions Need Correcting: $farmAccountPermissionsNeedCorrecting" } Write-Verbose -Message "Checking Crawl Database(s)" @@ -370,11 +370,13 @@ function Set-TargetResource $result = Get-TargetResource @PSBoundParameters + $newServiceApp = $false + if ($result.Ensure -eq "Absent" -and $Ensure -eq "Present") { # Create the service app as it doesn't exist Write-Verbose -Message "Creating Search Service Application $Name" - Invoke-SPDscCommand -Arguments @($PSBoundParameters, $MyInvocation.MyCommand.Source) ` + $newServiceApp = Invoke-SPDscCommand -Arguments @($PSBoundParameters, $MyInvocation.MyCommand.Source) ` -ScriptBlock { $params = $args[0] $eventSource = $args[1] @@ -469,8 +471,14 @@ function Set-TargetResource Set-SPEnterpriseSearchServiceApplication @setParams } - Write-Verbose -Message ("NOTE: Don't forget to configure a Search topology " + ` + Write-Warning -Message ("NOTE: Don't forget to configure a Search topology " + ` "using the SPSearchTopology resource!") + + return $true + } + else + { + return $false } } } @@ -549,8 +557,9 @@ function Set-TargetResource # Only check and correct when Ensure=Present, FixFarmAccountPermissions=True and the permissions are incorrect if ($Ensure -eq "Present") { - if ($FixFarmAccountPermissions -eq $true -and ` - $result.FixFarmAccountPermissions -eq $true) + if (($FixFarmAccountPermissions -eq $true -and ` + $result.FixFarmAccountPermissions -eq $true) -or ` + $newServiceApp -eq $true) { Write-Verbose -Message "Fixing database permissions for Search Service Application $Name" Invoke-SPDscCommand -Arguments @($PSBoundParameters, $PSScriptRoot) ` @@ -876,7 +885,10 @@ function Test-TargetResource $message = ("Specified Default content access account is not in the desired state" + ` "Actual: $current Desired: $desired") Write-Verbose -Message $message - Add-SPDscEvent -Message $message -EntryType 'Error' -EventID 1 -Source $MyInvocation.MyCommand.Source + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 1 ` + -Source $MyInvocation.MyCommand.Source return $false } } @@ -888,7 +900,10 @@ function Test-TargetResource $message = ("FixFarmAccountPermissions is set to True, but the Search databases " + ` "do not have the correct permissions") Write-Verbose -Message $message - Add-SPDscEvent -Message $message -EntryType 'Error' -EventID 1 -Source $MyInvocation.MyCommand.Source + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 1 ` + -Source $MyInvocation.MyCommand.Source return $false } } diff --git a/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 b/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 index 1146067c9..12cc49442 100644 --- a/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 @@ -107,7 +107,7 @@ function Get-TargetResource try { - $null = Get-SPFarm + $null = Get-SPFarm -Verbose:$false } catch { @@ -116,10 +116,10 @@ function Get-TargetResource return $nullreturn } - $shellAdmins = Get-SPShellAdmin + $shellAdmins = Get-SPShellAdmin -Verbose:$false $cdbPermissions = @() - $databases = Get-SPDatabase + $databases = Get-SPDatabase -Verbose:$false if ($params.ContainsKey("ExcludeDatabases")) { $databases = $databases | Where-Object -FilterScript { @@ -129,7 +129,7 @@ function Get-TargetResource foreach ($database in $databases) { - $dbShellAdmins = Get-SPShellAdmin -Database $database.Id + $dbShellAdmins = Get-SPShellAdmin -Database $database.Id -Verbose:$false $cdbPermission = @{ Name = $database.Name @@ -278,7 +278,7 @@ function Set-TargetResource try { - $null = Get-SPFarm + $null = Get-SPFarm -Verbose:$false } catch { @@ -291,7 +291,7 @@ function Set-TargetResource throw $message } - $shellAdmins = Get-SPShellAdmin + $shellAdmins = Get-SPShellAdmin -Verbose:$false if ($params.Members) { @@ -318,7 +318,8 @@ function Set-TargetResource $user = $difference.InputObject try { - Add-SPShellAdmin -UserName $user + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -UserName $user -Verbose:$false } catch { @@ -337,7 +338,8 @@ function Set-TargetResource $user = $difference.InputObject try { - Remove-SPShellAdmin -UserName $user -Confirm:$false + Write-Verbose -Message "Removing $member" + Remove-SPShellAdmin -UserName $user -Confirm:$false -Verbose:$false } catch { @@ -360,7 +362,8 @@ function Set-TargetResource { try { - Add-SPShellAdmin -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -UserName $member -Verbose:$false } catch { @@ -388,7 +391,8 @@ function Set-TargetResource { try { - Add-SPShellAdmin -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -UserName $member -Verbose:$false } catch { @@ -410,7 +414,8 @@ function Set-TargetResource { try { - Add-SPShellAdmin -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -UserName $member -Verbose:$false } catch { @@ -437,7 +442,8 @@ function Set-TargetResource { try { - Remove-SPShellAdmin -UserName $member -Confirm:$false + Write-Verbose -Message "Removing $member" + Remove-SPShellAdmin -UserName $member -Confirm:$false -Verbose:$false } catch { @@ -466,12 +472,12 @@ function Set-TargetResource # Check if configured database exists, throw error if not Write-Verbose -Message "Processing Database: $($database.Name)" - $currentCDB = Get-SPDatabase | Where-Object -FilterScript { + $currentCDB = Get-SPDatabase -Verbose:$false | Where-Object -FilterScript { $_.Name -eq $database.Name } if ($null -ne $currentCDB) { - $dbShellAdmins = Get-SPShellAdmin -database $currentCDB.Id + $dbShellAdmins = Get-SPShellAdmin -Database $currentCDB.Id -Verbose:$false if ($database.Members) { @@ -487,7 +493,10 @@ function Set-TargetResource $user = $difference.InputObject try { - Add-SPShellAdmin -database $currentCDB.Id -UserName $user + Write-Verbose -Message "Adding $user" + Add-SPShellAdmin -Database $currentCDB.Id ` + -UserName $user ` + -Verbose:$false } catch { @@ -506,9 +515,11 @@ function Set-TargetResource $user = $difference.InputObject try { + Write-Verbose -Message "Removing $user" Remove-SPShellAdmin -Database $currentCDB.Id ` -UserName $user ` - -Confirm:$false + -Confirm:$false ` + -Verbose:$false } catch { @@ -530,7 +541,10 @@ function Set-TargetResource { try { - Add-SPShellAdmin -database $currentCDB.Id -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -Database $currentCDB.Id ` + -UserName $member ` + -Verbose:$false } catch { @@ -558,7 +572,10 @@ function Set-TargetResource { try { - Add-SPShellAdmin -database $currentCDB.Id -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -Database $currentCDB.Id ` + -UserName $member ` + -Verbose:$false } catch { @@ -580,7 +597,10 @@ function Set-TargetResource { try { - Add-SPShellAdmin -database $currentCDB.Id -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -Database $currentCDB.Id ` + -UserName $member ` + -Verbose:$false } catch { @@ -608,9 +628,11 @@ function Set-TargetResource { try { + Write-Verbose -Message "Removing $member" Remove-SPShellAdmin -Database $currentCDB.Id ` -UserName $member ` - -Confirm:$false + -Confirm:$false ` + -Verbose:$false } catch { @@ -644,7 +666,7 @@ function Set-TargetResource { Write-Verbose -Message "Processing AllDatabases parameter" - $databases = Get-SPDatabase + $databases = Get-SPDatabase -Verbose:$false if ($params.ContainsKey("ExcludeDatabases")) { $databases = $databases | Where-Object -FilterScript { @@ -653,10 +675,10 @@ function Set-TargetResource } foreach ($database in $databases) { - $dbShellAdmins = Get-SPShellAdmin -database $database.Id + Write-Verbose -Message "Processing Database: $($database.Name)" + $dbShellAdmins = Get-SPShellAdmin -Database $database.Id -Verbose:$false if ($params.Members) { - Write-Verbose -Message "Processing Database: $($database.Name)" if ($dbShellAdmins) { $differences = Compare-Object -ReferenceObject $dbShellAdmins.UserName ` @@ -679,7 +701,10 @@ function Set-TargetResource $user = $difference.InputObject try { - Add-SPShellAdmin -database $database.Id -UserName $user + Write-Verbose -Message "Adding $user" + Add-SPShellAdmin -Database $database.Id ` + -UserName $user ` + -Verbose:$false } catch { @@ -698,9 +723,11 @@ function Set-TargetResource $user = $difference.InputObject try { + Write-Verbose -Message "Removing $user" Remove-SPShellAdmin -Database $database.Id ` -UserName $user ` - -Confirm:$false + -Confirm:$false ` + -Verbose:$false } catch { @@ -723,7 +750,10 @@ function Set-TargetResource { try { - Add-SPShellAdmin -database $database.Id -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -Database $database.Id ` + -UserName $member ` + -Verbose:$false } catch { @@ -750,7 +780,10 @@ function Set-TargetResource { try { - Add-SPShellAdmin -database $database.Id -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -Database $database.Id ` + -UserName $member ` + -Verbose:$false } catch { @@ -772,7 +805,10 @@ function Set-TargetResource { try { - Add-SPShellAdmin -database $database.Id -UserName $member + Write-Verbose -Message "Adding $member" + Add-SPShellAdmin -Database $database.Id ` + -UserName $member ` + -Verbose:$false } catch { @@ -800,9 +836,11 @@ function Set-TargetResource { try { + Write-Verbose -Message "Removing $member" Remove-SPShellAdmin -Database $database.Id ` -UserName $member ` - -Confirm:$false + -Confirm:$false ` + -Verbose:$false } catch { diff --git a/SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-AddStringFarmPropertyBag.ps1 b/SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-AddStringFarmPropertyBag.ps1 new file mode 100644 index 000000000..485f66662 --- /dev/null +++ b/SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-AddStringFarmPropertyBag.ps1 @@ -0,0 +1,64 @@ + +<#PSScriptInfo + +.VERSION 1.0.0 + +.GUID 80d306fa-8bd4-4a8d-9f7a-bf40df95e661 + +.AUTHOR DSC Community + +.COMPANYNAME DSC Community + +.COPYRIGHT DSC Community contributors. All rights reserved. + +.TAGS + +.LICENSEURI https://github.com/dsccommunity/SharePointDsc/blob/master/LICENSE + +.PROJECTURI https://github.com/dsccommunity/SharePointDsc + +.ICONURI https://dsccommunity.org/images/DSC_Logo_300p.png + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES +Updated author, copyright notice, and URLs. + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + This example shows how add property bag in the current farm. + +#> + +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + + Import-DscResource -ModuleName SharePointDsc + + node localhost + { + SPFarmPropertyBag 'SetStringValue' + { + Key = 'FARM_TYPE' + Value = 'SearchFarm' + ParameterType = 'String' + Ensure = 'Present' + PsDscRunAsCredential = $SetupAccount + } + } +} diff --git a/SharePointDsc/Examples/Resources/SPFarmPropertyBag/2-AddBoolToFarmPropertyBag.ps1 b/SharePointDsc/Examples/Resources/SPFarmPropertyBag/2-AddBoolToFarmPropertyBag.ps1 new file mode 100644 index 000000000..e9be2cf83 --- /dev/null +++ b/SharePointDsc/Examples/Resources/SPFarmPropertyBag/2-AddBoolToFarmPropertyBag.ps1 @@ -0,0 +1,64 @@ + +<#PSScriptInfo + +.VERSION 1.0.0 + +.GUID 80d306fa-8bd4-4a8d-9f7a-bf40df95e661 + +.AUTHOR DSC Community + +.COMPANYNAME DSC Community + +.COPYRIGHT DSC Community contributors. All rights reserved. + +.TAGS + +.LICENSEURI https://github.com/dsccommunity/SharePointDsc/blob/master/LICENSE + +.PROJECTURI https://github.com/dsccommunity/SharePointDsc + +.ICONURI https://dsccommunity.org/images/DSC_Logo_300p.png + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES +Updated author, copyright notice, and URLs. + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + This example shows how add property bag in the current farm. + +#> + +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + + Import-DscResource -ModuleName SharePointDsc + + node localhost + { + SPFarmPropertyBag 'SetBooleanValue' + { + Key = 'disableIntranetCalls' + Value = 'False' + ParameterType = 'Boolean' + Ensure = 'Present' + PsDscRunAsCredential = $SetupAccount + } + } +} diff --git a/SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-AddFarmPropertyBag.ps1 b/SharePointDsc/Examples/Resources/SPFarmPropertyBag/3-AddIntToFarmPropertyBag.ps1 similarity index 80% rename from SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-AddFarmPropertyBag.ps1 rename to SharePointDsc/Examples/Resources/SPFarmPropertyBag/3-AddIntToFarmPropertyBag.ps1 index a5c704d7f..2e8aefe8f 100644 --- a/SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-AddFarmPropertyBag.ps1 +++ b/SharePointDsc/Examples/Resources/SPFarmPropertyBag/3-AddIntToFarmPropertyBag.ps1 @@ -52,12 +52,13 @@ Configuration Example node localhost { - SPFarmPropertyBag APPLICATION_APPCodeProperty + SPFarmPropertyBag 'SetIntValue' { + Key = 'AnswerToEverything' + Value = '42' + ParameterType = 'Int32' + Ensure = 'Present' PsDscRunAsCredential = $SetupAccount - Key = "FARM_TYPE" - Value = "SearchFarm" - Ensure = "Present" } } } diff --git a/SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-RemoveFarmPropertyBag.ps1 b/SharePointDsc/Examples/Resources/SPFarmPropertyBag/4-RemoveFarmPropertyBag.ps1 similarity index 87% rename from SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-RemoveFarmPropertyBag.ps1 rename to SharePointDsc/Examples/Resources/SPFarmPropertyBag/4-RemoveFarmPropertyBag.ps1 index 0adff66d8..a1b1c85a8 100644 --- a/SharePointDsc/Examples/Resources/SPFarmPropertyBag/1-RemoveFarmPropertyBag.ps1 +++ b/SharePointDsc/Examples/Resources/SPFarmPropertyBag/4-RemoveFarmPropertyBag.ps1 @@ -52,11 +52,11 @@ Configuration Example node localhost { - SPFarmPropertyBag APPLICATION_APPCodeProperty + SPFarmPropertyBag 'RemoveVlaue' { + Key = 'KeyToRemove' + Ensure = 'Absent' PsDscRunAsCredential = $SetupAccount - Key = "KeyToRemove" - Ensure = "Absent" } } } diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPFarmPropertyBag.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPFarmPropertyBag.Tests.ps1 index 009fcf26e..5742c6043 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPFarmPropertyBag.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPFarmPropertyBag.Tests.ps1 @@ -111,6 +111,52 @@ try } } + Context -Name 'ParameterType is Boolean, but Value is not True or False' { + BeforeAll { + $testParams = @{ + Key = 'Property' + Value = 'String' + ParameterType = 'Boolean' + } + + } + + It 'Should throw exception from the get method' { + { Get-TargetResource @testParams } | Should -Throw 'Value can only be True or False when ParameterType is Boolean. Current value:' + } + + It 'Should throw exception from the set method' { + { Set-TargetResource @testParams } | Should -Throw 'Value can only be True or False when ParameterType is Boolean. Current value:' + } + + It 'Should throw exception from the test method' { + { Test-TargetResource @testParams } | Should -Throw 'Value can only be True or False when ParameterType is Boolean. Current value:' + } + } + + Context -Name 'ParameterType is Int32, but Value is not an integer' { + BeforeAll { + $testParams = @{ + Key = 'Property' + Value = 'String' + ParameterType = 'Int32' + } + + } + + It 'Should throw exception from the get method' { + { Get-TargetResource @testParams } | Should -Throw 'Value has to be a number when ParameterType is Int32. Current value:' + } + + It 'Should throw exception from the set method' { + { Set-TargetResource @testParams } | Should -Throw 'Value has to be a number when ParameterType is Int32. Current value:' + } + + It 'Should throw exception from the test method' { + { Test-TargetResource @testParams } | Should -Throw 'Value has to be a number when ParameterType is Int32. Current value:' + } + } + Context -Name 'The farm property does not exist, but should be' -Fixture { BeforeAll { $testParams = @{ @@ -200,7 +246,97 @@ try } } - Context -Name 'The farm property does not exist, and should be' -Fixture { + Context -Name 'The farm property exists, but with wrong type (Boolean)' -Fixture { + BeforeAll { + $testParams = @{ + Key = 'FARM_TYPE' + Value = '5' + ParameterType = "Int32" + Ensure = 'Present' + } + + Mock -CommandName Get-SPFarm -MockWith { + $spFarm = [pscustomobject]@{ + Properties = @{ + FARM_TYPE = $true + } + } + $spFarm = $spFarm | Add-Member ScriptMethod Update { + $Global:SPDscFarmPropertyUpdated = $true + } -PassThru + $spFarm = $spFarm | Add-Member ScriptMethod Remove { + $Global:SPDscFarmPropertyRemoved = $true + } -PassThru + return $spFarm + } + } + + It 'Should return the same values as passed as parameters' { + $result = Get-TargetResource @testParams + $result.Ensure | Should -Be 'present' + $result.Key | Should -Be $testParams.Key + $result.Value | Should -Be 'True' + $result.ParameterType | Should -Be 'Boolean' + } + + It 'Should return false from the test method' { + Test-TargetResource @testParams | Should -Be $false + } + + $Global:SPDscFarmPropertyUpdated = $false + It 'Calls Get-SPFarm and updates farm property bag from the set method' { + Set-TargetResource @testParams + + $Global:SPDscFarmPropertyUpdated | Should -Be $true + } + } + + Context -Name 'The farm property exists, but with wrong type (Boolean)' -Fixture { + BeforeAll { + $testParams = @{ + Key = 'FARM_TYPE' + Value = 'False' + ParameterType = "Boolean" + Ensure = 'Present' + } + + Mock -CommandName Get-SPFarm -MockWith { + $spFarm = [pscustomobject]@{ + Properties = @{ + FARM_TYPE = 5 + } + } + $spFarm = $spFarm | Add-Member ScriptMethod Update { + $Global:SPDscFarmPropertyUpdated = $true + } -PassThru + $spFarm = $spFarm | Add-Member ScriptMethod Remove { + $Global:SPDscFarmPropertyRemoved = $true + } -PassThru + return $spFarm + } + } + + It 'Should return the same values as passed as parameters' { + $result = Get-TargetResource @testParams + $result.Ensure | Should -Be 'present' + $result.Key | Should -Be $testParams.Key + $result.Value | Should -Be '5' + $result.ParameterType | Should -Be 'Int32' + } + + It 'Should return false from the test method' { + Test-TargetResource @testParams | Should -Be $false + } + + $Global:SPDscFarmPropertyUpdated = $false + It 'Calls Get-SPFarm and updates farm property bag from the set method' { + Set-TargetResource @testParams + + $Global:SPDscFarmPropertyUpdated | Should -Be $true + } + } + + Context -Name 'The farm property does not exist, and should not be' -Fixture { BeforeAll { $testParams = @{ Key = 'FARM_TYPED' @@ -250,7 +386,7 @@ try Mock -CommandName Get-SPFarm -MockWith { $spFarm = [pscustomobject]@{ Properties = @{ - FARM_TYPE = 'SearchFarm' + FARM_TYPE = 5 } } $spFarm = $spFarm | Add-Member ScriptMethod Update { @@ -271,7 +407,8 @@ try It 'Should return the same values as passed as parameters' { $result.Key | Should -Be $testParams.Key - $result.value | Should -Be $testParams.Value + $result.Value | Should -Be '5' + $result.ParameterType | Should -Be 'Int32' } It 'Should return false from the test method' { @@ -298,9 +435,10 @@ try Mock -CommandName Get-TargetResource -MockWith { return @{ - Key = "Key" - Value = "Value" - Ensure = "Present" + Key = "Key" + Value = "Value" + ParameterType = "String" + Ensure = "Present" } } @@ -324,6 +462,7 @@ try { Ensure = "Present"; Key = "Key"; + ParameterType = "String"; PsDscRunAsCredential = \$Credsspfarm; Value = "Value"; } diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPInstall.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPInstall.Tests.ps1 index 20c24effc..736952c4c 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPInstall.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPInstall.Tests.ps1 @@ -384,6 +384,83 @@ try } } + Context -Name "SharePoint installation fails: Issue with Prerequisites" -Fixture { + BeforeAll { + $testParams = @{ + IsSingleInstance = "Yes" + BinaryDir = "C:\SPInstall" + ProductKey = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" + Ensure = "Present" + } + + Mock -CommandName Start-Process -MockWith { + return @{ + ExitCode = 30066 + } + } + + Mock -CommandName Get-Item -MockWith { + return $null + } + + Mock -CommandName Get-Item -MockWith { + return @{ + Path = "RegKey" + } + } -ParameterFilter { $Path -eq "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" } + + Mock -CommandName Get-ItemProperty -MockWith { + return 0 + } + } + + It "Should throw an exception on an unknown exit code" { + { Set-TargetResource @testParams } | Should -Throw 'SharePoint installation has failed due to an issue with prerequisites not being installed correctly. Please review the setup logs.' + } + } + + Context -Name "SharePoint installation fails: Incorrect license key" -Fixture { + BeforeAll { + $testParams = @{ + IsSingleInstance = "Yes" + BinaryDir = "C:\SPInstall" + ProductKey = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" + Ensure = "Present" + } + + Mock -CommandName Start-Process -MockWith { + return @{ + ExitCode = 30030 + } + } + } + + It "Should throw an exception on an unknown exit code" { + { Set-TargetResource @testParams } | Should -Throw 'SharePoint install failed: Incorrect license key!' + } + } + + Context -Name "SharePoint installation fails: License terms are not accepted" -Fixture { + BeforeAll { + $testParams = @{ + IsSingleInstance = "Yes" + BinaryDir = "C:\SPInstall" + ProductKey = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" + Ensure = "Present" + } + + Mock -CommandName Start-Process -MockWith { + return @{ + ExitCode = 30203 + } + } + } + + It "Should throw an exception on an unknown exit code" { + { Set-TargetResource @testParams } | Should -Throw 'SharePoint install failed, license terms are not accepted.' + } + } + Context -Name "SharePoint binaries are installed and should not be" -Fixture { BeforeAll { $testParams = @{ From 059ca7e8058499f2bb8cb9bf4c3747c2c811c22c Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 25 Mar 2022 15:12:57 +0100 Subject: [PATCH 2/2] Fixed failing unit tests --- .../MSFT_SPSearchServiceApp.psm1 | 6 +- ...SharePointDsc.SPSearchServiceApp.Tests.ps1 | 90 ++++++++++++++++--- 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 index b11d530e8..09de6d4f3 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 @@ -557,9 +557,9 @@ function Set-TargetResource # Only check and correct when Ensure=Present, FixFarmAccountPermissions=True and the permissions are incorrect if ($Ensure -eq "Present") { - if (($FixFarmAccountPermissions -eq $true -and ` - $result.FixFarmAccountPermissions -eq $true) -or ` - $newServiceApp -eq $true) + if ($FixFarmAccountPermissions -eq $true -and ` + ($result.FixFarmAccountPermissions -eq $true -or ` + $newServiceApp -eq $true)) { Write-Verbose -Message "Fixing database permissions for Search Service Application $Name" Invoke-SPDscCommand -Arguments @($PSBoundParameters, $PSScriptRoot) ` diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 index d4603294d..7b9d643e8 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 @@ -50,7 +50,7 @@ try InModuleScope -ModuleName $script:DSCResourceFullName -ScriptBlock { Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { BeforeAll { - Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope + Invoke-Command -Scriptblock $Global:SPDscHelper.InitializeScript -NoNewScope # Initialize tests Import-Module -Name (Join-Path -Path (Get-Module SharePointDsc -ListAvailable).ModuleBase ` @@ -267,32 +267,67 @@ try Mock Import-Module -MockWith { } -ParameterFilter { $_.Name -eq $ModuleName } Mock -CommandName Get-SPServiceApplication -MockWith { - $spServiceApp = [PSCustomObject]@{ - DisplayName = $testParams.Name - Name = $testParams.Name + if ($global:SPDscGetServiceApplicationCount -eq 0) + { + $spServiceApp = [PSCustomObject]@{ + DisplayName = $testParams.Name + Name = $testParams.Name + } + $spServiceApp | Add-Member -MemberType ScriptMethod ` + -Name GetType ` + -Value { + return @{ + FullName = "Microsoft.Office.UnKnownWebServiceApplication" + } + } -PassThru -Force } - $spServiceApp | Add-Member -MemberType ScriptMethod ` - -Name GetType ` - -Value { - return @{ - FullName = "Microsoft.Office.UnKnownWebServiceApplication" + else + { + $spServiceApp = [PSCustomObject]@{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + Database = @{ + Name = "SP_Search" + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = "SP_Search" + '_Admin' + NormalizedDataSource = 'SQL01' + } + AnalyticsReportingDatabases = @{ + Name = "SP_Search" + '_AnalyticsReportingStore' + NormalizedDataSource = 'SQL01' + } } - } -PassThru -Force + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } + } -PassThru -Force + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetProperty -Value { + return 0 + } -PassThru -Force + } + $global:SPDscGetServiceApplicationCount++ return $spServiceApp } } + $global:SPDscGetServiceApplicationCount = 0 It "Should return absent from the Get method" { (Get-TargetResource @testParams).Ensure | Should -Be "Absent" } + $global:SPDscGetServiceApplicationCount = 0 It "Should return false when the Test method is called" { Test-TargetResource @testParams | Should -Be $false } + $global:SPDscGetServiceApplicationCount = 0 It "Should create a new service application in the set method" { Set-TargetResource @testParams Assert-MockCalled New-SPEnterpriseSearchServiceApplication + $global:SPDscGetServiceApplicationCount | Should -Be 3 } } @@ -1163,7 +1198,39 @@ try Mock Import-Module -MockWith { } -ParameterFilter { $_.Name -eq $ModuleName } Mock -CommandName Get-SPServiceApplication -MockWith { - return $null + if ($global:SPDscGetServiceApplicationCount -eq 0) + { + $spServiceApp = $null + } + else + { + $spServiceApp = [PSCustomObject]@{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + Database = @{ + Name = "SP_Search" + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = "SP_Search" + '_Admin' + NormalizedDataSource = 'SQL01' + } + AnalyticsReportingDatabases = @{ + Name = "SP_Search" + '_AnalyticsReportingStore' + NormalizedDataSource = 'SQL01' + } + } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } + } -PassThru -Force + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetProperty -Value { + return 0 + } -PassThru -Force + } + $global:SPDscGetServiceApplicationCount++ + return $spServiceApp } Mock -CommandName Get-SPDscInstalledProductVersion -MockWith { @@ -1178,6 +1245,7 @@ try Set-TargetResource @testParams } + $global:SPDscGetServiceApplicationCount = 0 It "Should throw an error in the set method if the version of SharePoint isn't high enough" { Mock -CommandName Get-SPDscInstalledProductVersion -MockWith { return @{