From 30b1f713d8188372dc539c79ed045b37bc84d844 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 24 Sep 2020 17:13:30 +0200 Subject: [PATCH 1/9] Updated documentation --- CHANGELOG.md | 7 +++++++ SharePointDsc/DSCResources/MSFT_SPSite/readme.md | 10 +++++++--- SharePointDsc/DSCResources/MSFT_SPWeb/readme.md | 5 +++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c68108640..412dd50e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SharePointDsc - Added logging to the event log when the code throws an exception +### Changed + +- SPSite + - Added more explanation to documentation on which parameters are checked +- SPWeb + - Added more explanation to documentation on using this resource + ## [4.3.0] - 2020-09-30 ### Added diff --git a/SharePointDsc/DSCResources/MSFT_SPSite/readme.md b/SharePointDsc/DSCResources/MSFT_SPSite/readme.md index 7b20f6fea..656ba6d69 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSite/readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPSite/readme.md @@ -7,9 +7,13 @@ This resource will provision a site collection to the current farm, based on the settings that are passed through. These settings map to the New-SPSite cmdlet and accept the same values and types. -The current version of SharePointDsc is only able to check for the existence -of a site collection, the additional parameters are not checked for yet, but -will be in a later release +When the site collection exists, not all parameters are checked for being +in the desired state. The following parameters are checked: +QuotaTemplate, OwnerAlias, SecondaryOwnerAlias, AdministrationSiteType + +Since the title of the site collection can be changed by the site collection +owner and can result in a conflict between the owner and DSC. Therefore the +resource is only using the Name parameter during site creation. NOTE: When creating Host Header Site Collections, do not use the HostHeader diff --git a/SharePointDsc/DSCResources/MSFT_SPWeb/readme.md b/SharePointDsc/DSCResources/MSFT_SPWeb/readme.md index 1183566fd..473580d53 100644 --- a/SharePointDsc/DSCResources/MSFT_SPWeb/readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPWeb/readme.md @@ -8,3 +8,8 @@ through. These settings map to the New-SPWeb cmdlet and accept the same values The default value for the Ensure parameter is Present. When not specifying this parameter, the web is created. + +NOTE: +Since subsites/webs can be created/deleted by site collection owners it is +possible that using this resource results in a conflict between the owner +and DSC. Therefore be careful using this resource. From a7881b47f13255fbb92119bbe99f9d6726b33d84 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 23 Oct 2020 21:44:51 +0200 Subject: [PATCH 2/9] Fixed issue in SPShellAdmins --- CHANGELOG.md | 6 ++++++ .../DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 412dd50e1..f1b1205f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SPWeb - Added more explanation to documentation on using this resource +### Fixed + +- SPShellAdmins + - Fixed issue with Get-DscConfiguration which threw an error when only one + item was returned by the Get method + ## [4.3.0] - 2020-09-30 ### Added diff --git a/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 b/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 index 9464c83e8..585a72b79 100644 --- a/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 @@ -146,7 +146,7 @@ function Get-TargetResource return @{ IsSingleInstance = "Yes" - Members = $shellAdmins.UserName + Members = [System.Array]$shellAdmins.UserName MembersToInclude = $params.MembersToInclude MembersToExclude = $params.MembersToExclude Databases = $cdbPermissions From 77d102d884caafb547f8eb20262a61fb02bc3136 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 23 Oct 2020 21:48:12 +0200 Subject: [PATCH 3/9] Fixed issue #1245 --- CHANGELOG.md | 3 +++ .../MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1b1205f9..b9d84ea55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- SPSearchTopology + - Fixes issue where applying a topology failed when the search service + instance was disabled instead of offline - SPShellAdmins - Fixed issue with Get-DscConfiguration which threw an error when only one item was returned by the Get method diff --git a/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 b/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 index 83c925bf1..20ffe1b7c 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 @@ -283,7 +283,7 @@ function Set-TargetResource $searchService = Get-SPEnterpriseSearchServiceInstance -Identity $searchServer } - if ($searchService.Status -eq "Offline") + if (($searchService.Status -eq "Offline") -or ($searchService.Status -eq "Disabled")) { Write-Verbose -Message "Start Search Service Instance" Start-SPEnterpriseSearchServiceInstance -Identity $searchServer From ec6a68542aff4aeb6ff085e16ba8f4bf81e3c346 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 23 Oct 2020 22:03:51 +0200 Subject: [PATCH 4/9] Fixed issue #1244 --- CHANGELOG.md | 3 +++ .../MSFT_SPWordAutomationServiceApp.psm1 | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9d84ea55..db607d786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SPShellAdmins - Fixed issue with Get-DscConfiguration which threw an error when only one item was returned by the Get method +- SPWordAutomationServiceApp + - Fixed issue where provisioning the service app requires a second run to + update all specified parameters ## [4.3.0] - 2020-09-30 diff --git a/SharePointDsc/DSCResources/MSFT_SPWordAutomationServiceApp/MSFT_SPWordAutomationServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPWordAutomationServiceApp/MSFT_SPWordAutomationServiceApp.psm1 index 5cbd436b5..1aa2e35eb 100644 --- a/SharePointDsc/DSCResources/MSFT_SPWordAutomationServiceApp/MSFT_SPWordAutomationServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPWordAutomationServiceApp/MSFT_SPWordAutomationServiceApp.psm1 @@ -371,20 +371,18 @@ function Set-TargetResource $appPool = Get-SPServiceApplicationPool -Identity $params.ApplicationPool if ($appPool) { - $cmdletparams = @{ } - $cmdletparams.Name = $params.Name - if ($params.Name) + $cmdletparams = @{ + Name = $params.Name + ApplicationPool = $params.ApplicationPool + } + if ($params.ContainsKey("DatabaseName")) { $cmdletparams.DatabaseName = $params.DatabaseName } - if ($params.Name) + if ($params.ContainsKey("DatabaseServer")) { $cmdletparams.DatabaseServer = $params.DatabaseServer } - if ($params.Name) - { - $cmdletparams.ApplicationPool = $params.ApplicationPool - } if ($params.useSQLAuthentication -eq $true) { @@ -408,6 +406,10 @@ function Set-TargetResource throw $message } } + + # Retrieving updated current state, so additionally + # specified parameters are also updated. + $result = Get-TargetResource @PSBoundParameters } if ($result.Ensure -eq "Present" -and $Ensure -eq "Present") From 673886f8f070ed4884b0e126f2d830e3fa3762e5 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 27 Oct 2020 15:44:07 +0100 Subject: [PATCH 5/9] Fixing issue #1249 --- CHANGELOG.md | 2 ++ .../MSFT_SPSecureStoreServiceApp.psm1 | 7 +++++++ .../DSCResources/MSFT_SPUserProfileServiceApp/readme.md | 4 ---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db607d786..b078b7821 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SPSearchTopology - Fixes issue where applying a topology failed when the search service instance was disabled instead of offline +- SPSecureStoreServiceApp + - Fixes issue where custom database name was no longer used since v4.3 - SPShellAdmins - Fixed issue with Get-DscConfiguration which threw an error when only one item was returned by the Get method diff --git a/SharePointDsc/DSCResources/MSFT_SPSecureStoreServiceApp/MSFT_SPSecureStoreServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPSecureStoreServiceApp/MSFT_SPSecureStoreServiceApp.psm1 index 55ac6f805..472c2f7ce 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSecureStoreServiceApp/MSFT_SPSecureStoreServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPSecureStoreServiceApp/MSFT_SPSecureStoreServiceApp.psm1 @@ -232,6 +232,13 @@ function Set-TargetResource $newParams.Add("DatabasePassword", $params.DatabaseCredentials.Password) } + $paramList = @('AuditlogMaxSize', 'DatabaseName', 'DatabaseServer', 'FailoverDatabaseServer', 'PartitionMode', 'Sharing') + + foreach ($item in ($params.GetEnumerator() | Where-Object -FilterScript { $_.Key -in $paramList })) + { + $params.Add($item.Key, $item.Value) + } + $pName = "$($params.Name) Proxy" if ($params.ContainsKey("ProxyName") -and $null -ne $params.ProxyName) diff --git a/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/readme.md b/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/readme.md index 2112766ab..e9d38ab2d 100644 --- a/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/readme.md @@ -33,10 +33,6 @@ implications. More information about these risks can be found at: http://www.powershellmagazine.com/2014/03/06/accidental-sabotage-beware-of-credssp/ NOTE2: -You should always specify the MySiteHostLocation parameter. Currently this is not -a required parameter, but will be as of SharePointDsc v4.0. - -NOTE3: The UpdateProxyGroup parameter fixes the following issue: The User Profile service is looking up the proxy groups to find the correct MMS. Unfortunately it doesn't follow what you configured in Central Administration. From e9b8836975a9ea509ef416f0af9932717ed4c8a2 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 27 Oct 2020 16:32:24 +0100 Subject: [PATCH 6/9] Fixes issue #1195 --- CHANGELOG.md | 3 +++ .../MSFT_SPConfigWizard.psm1 | 19 +++++++++++++++++++ .../SharePointDsc.SPConfigWizard.Tests.ps1 | 8 ++++++++ 3 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b078b7821..ce0eac573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- SPConfigWizard + - Fixes issue where a CU installation wasn't registered properly in the + config database. Added logic to run the Product Version timer job - SPSearchTopology - Fixes issue where applying a topology failed when the search service instance was disabled instead of offline diff --git a/SharePointDsc/DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 b/SharePointDsc/DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 index fab968773..b3ee71c4d 100644 --- a/SharePointDsc/DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 @@ -254,6 +254,25 @@ function Set-TargetResource -ScriptBlock { $psconfigExe = $args[0] + Write-Verbose -Message "Starting 'Product Version Job' timer job" + $pvTimerJob = Get-SPTimerJob -Identity 'job-admin-product-version' + $lastRunTime = $pvTimerJob.LastRunTime + + Start-SPTimerJob -Identity $pvTimerJob + + $jobRunning = $true + $maxCount = 30 + $count = 0 + while ($jobRunning -and $count -le $maxCount) + { + Start-Sleep -Seconds 10 + + $pvTimerJob = Get-SPTimerJob -Identity 'job-admin-product-version' + $jobRunning = $lastRunTime -eq $pvTimerJob.LastRunTime + + $count++ + } + $stdOutTempFile = "$env:TEMP\$((New-Guid).Guid)" $psconfig = Start-Process -FilePath $psconfigExe ` -ArgumentList "-cmd upgrade -inplace b2b -wait -cmd applicationcontent -install -cmd installfeatures -cmd secureresources -cmd services -install" ` diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPConfigWizard.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPConfigWizard.Tests.ps1 index 8b6949df2..f1df5b565 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPConfigWizard.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPConfigWizard.Tests.ps1 @@ -52,6 +52,14 @@ try Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope # Mocks for all contexts + Mock -CommandName Start-Sleep -MockWith { } + Mock -CommandName Start-SPTimerJob -MockWith { } + Mock -CommandName Get-SPTimerJob -MockWith { + return @{ + LastRunTime = Get-Date + } + } + Mock -CommandName Remove-Item -MockWith { } Mock -CommandName Get-Content -MockWith { return "log info" } Mock -CommandName Get-SPDscServerPatchStatus -MockWith { return "UpgradeRequired" } From 3ab86afa64d481b6a105dc52cf62c3eefc648ba0 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 4 Nov 2020 20:34:31 +0100 Subject: [PATCH 7/9] Small logging update --- .../DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 | 1 + 1 file changed, 1 insertion(+) diff --git a/SharePointDsc/DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 b/SharePointDsc/DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 index b3ee71c4d..9dbc1b3a4 100644 --- a/SharePointDsc/DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPConfigWizard/MSFT_SPConfigWizard.psm1 @@ -263,6 +263,7 @@ function Set-TargetResource $jobRunning = $true $maxCount = 30 $count = 0 + Write-Verbose -Message "Waiting for 'Product Version Job' timer job to complete" while ($jobRunning -and $count -le $maxCount) { Start-Sleep -Seconds 10 From 770bb675ff08fe6668a49072b5ee4fb011b44d84 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 5 Nov 2020 13:44:38 +0100 Subject: [PATCH 8/9] Fixes #1241 and unit tests --- CHANGELOG.md | 3 ++ .../DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 | 49 +++++++++++++------ .../DSCResources/MSFT_SPFarm/Readme.md | 3 ++ .../MSFT_SPSecureStoreServiceApp.psm1 | 2 +- .../Modules/SharePointDsc.Farm/SPFarm.psm1 | 20 ++++---- 5 files changed, 52 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce0eac573..477f4d001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- SPFarm + - Switched from creating a Lock database to a Lock table in the TempDB. + This to allow the use of precreated databases. - SPSite - Added more explanation to documentation on which parameters are checked - SPWeb diff --git a/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 b/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 index 7546e5f89..384cf0150 100644 --- a/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 @@ -631,7 +631,8 @@ function Set-TargetResource $currentUri = [System.Uri]$centralAdminSite.Url if ($desiredUri.AbsoluteUri -ne $currentUri.AbsoluteUri) { - Write-Verbose -Message "Re-provisioning CA because $($currentUri.AbsoluteUri) does not equal $($desiredUri.AbsoluteUri)" + Write-Verbose -Message ("Re-provisioning CA because $($currentUri.AbsoluteUri) " + ` + "does not equal $($desiredUri.AbsoluteUri)") $reprovisionCentralAdmin = $true } else @@ -657,14 +658,17 @@ function Set-TargetResource if ($desiredUri.Host -ne $iisBindings[0].HostHeader -or $desiredUri.Port -ne $iisBindings[0].Port) { - Write-Verbose -Message "Re-provisioning CA because $($desiredUri.Host) does not equal $($iisBindings[0].HostHeader) or $($desiredUri.Port) does not equal $($iisBindings[0].Port)" + Write-Verbose -Message ("Re-provisioning CA because $($desiredUri.Host) does not " + ` + "equal $($iisBindings[0].HostHeader) or $($desiredUri.Port) does not " + ` + "equal $($iisBindings[0].Port)") $reprovisionCentralAdmin = $true } } else { # iisBindings did not exist or did not contain a valid hostheader - Write-Verbose -Message "Re-provisioning CA because IIS Bindings does not exist or does not contain a valid host header" + Write-Verbose -Message ("Re-provisioning CA because IIS Bindings does not " + ` + "exist or does not contain a valid host header") $reprovisionCentralAdmin = $true } } @@ -707,7 +711,8 @@ function Set-TargetResource if ($CurrentValues.CentralAdministrationAuth -ne $CentralAdministrationAuth -and (-not $reprovisionCentralAdmin)) { - Write-Verbose -Message "Updating CentralAdmin authentication method from $($CurrentValues.CentralAdministrationAuth) to $CentralAdministrationAuth" + Write-Verbose -Message ("Updating CentralAdmin authentication method from " + ` + "$($CurrentValues.CentralAdministrationAuth) to $CentralAdministrationAuth") Invoke-SPDscCommand -Credential $InstallAccount ` -Arguments $PSBoundParameters ` -ScriptBlock { @@ -756,7 +761,8 @@ function Set-TargetResource if ($params.UseSQLAuthentication -eq $true) { - Write-Verbose -Message "Using SQL authentication to create service application as `$useSQLAuthentication is set to $($params.useSQLAuthentication)." + Write-Verbose -Message ("Using SQL authentication to create service application as " + ` + "`$useSQLAuthentication is set to $($params.useSQLAuthentication).") $databaseCredentialsParam = @{ DatabaseCredentials = $params.DatabaseCredentials } @@ -795,12 +801,24 @@ function Set-TargetResource if ($dbStatus.ValidPermissions -eq $false) { - $message = "The current user does not have sufficient permissions to SQL Server" - Add-SPDscEvent -Message $message ` - -EntryType 'Error' ` - -EventID 100 ` - -Source $eventSource - throw $message + if ($dbStatus.DatabaseEmpty -eq $true) + { + # If DatabaseEmpty is True most probably precreated databases are being used + Write-Verbose -Message ("IMPORTANT: Permissions check failed, but an empty " + ` + "configDB '$($params.FarmConfigDatabaseName)' was found. Assuming that " + ` + "precreated databases are being used.") + } + else + { + # If DatabaseEmpty is False, then either the specified ConfigDB doesn't exist or + # is already provisioned + $message = "The current user does not have sufficient permissions to SQL Server" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $eventSource + throw $message + } } $executeArgs = @{ @@ -814,12 +832,14 @@ function Set-TargetResource if ($params.useSQLAuthentication -eq $true) { - Write-Verbose -Message "Using SQL authentication to connect to / create farm as `$useSQLAuthentication is set to $($params.useSQLAuthentication)." + Write-Verbose -Message ("Using SQL authentication to connect to / create farm as " + ` + "`$useSQLAuthentication is set to $($params.useSQLAuthentication).") $executeArgs.Add("DatabaseCredentials", $params.DatabaseCredentials) } else { - Write-Verbose -Message "`$useSQLAuthentication is false or not specified; using default Windows authentication." + Write-Verbose -Message ("`$useSQLAuthentication is false or not specified; using " + ` + "default Windows authentication.") } $installedVersion = Get-SPDscInstalledProductVersion @@ -1087,7 +1107,8 @@ function Set-TargetResource } elseif ($desiredUri.AbsoluteUri -ne $currentUri.AbsoluteUri) { - Write-Verbose -Message "Re-provisioning CA because $($currentUri.AbsoluteUri) does not equal $($desiredUri.AbsoluteUri)" + Write-Verbose -Message ("Re-provisioning CA because $($currentUri.AbsoluteUri) " + ` + "does not equal $($desiredUri.AbsoluteUri)") $reprovisionCentralAdmin = $true } diff --git a/SharePointDsc/DSCResources/MSFT_SPFarm/Readme.md b/SharePointDsc/DSCResources/MSFT_SPFarm/Readme.md index f483a9722..9af563627 100644 --- a/SharePointDsc/DSCResources/MSFT_SPFarm/Readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPFarm/Readme.md @@ -61,3 +61,6 @@ NOTE: When using SharePoint 2016 and later and enabling the Developer Dashboard, please make sure you also provision the Usage and Health service application to make sure the Developer Dashboard works properly. + +NOTE2: +Since v4.4 the resource supports the use of precreated databases. diff --git a/SharePointDsc/DSCResources/MSFT_SPSecureStoreServiceApp/MSFT_SPSecureStoreServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPSecureStoreServiceApp/MSFT_SPSecureStoreServiceApp.psm1 index 472c2f7ce..25f678a86 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSecureStoreServiceApp/MSFT_SPSecureStoreServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPSecureStoreServiceApp/MSFT_SPSecureStoreServiceApp.psm1 @@ -236,7 +236,7 @@ function Set-TargetResource foreach ($item in ($params.GetEnumerator() | Where-Object -FilterScript { $_.Key -in $paramList })) { - $params.Add($item.Key, $item.Value) + $newParams.Add($item.Key, $item.Value) } $pName = "$($params.Name) Proxy" diff --git a/SharePointDsc/Modules/SharePointDsc.Farm/SPFarm.psm1 b/SharePointDsc/Modules/SharePointDsc.Farm/SPFarm.psm1 index 5f7e521b9..9763b518f 100644 --- a/SharePointDsc/Modules/SharePointDsc.Farm/SPFarm.psm1 +++ b/SharePointDsc/Modules/SharePointDsc.Farm/SPFarm.psm1 @@ -64,9 +64,6 @@ function Get-SPDscConfigDBStatus $command.CommandText = "SELECT COUNT(*) FROM sys.databases WHERE name = '$Database'" $configDBexists = ($command.ExecuteScalar() -eq 1) - $command.CommandText = "SELECT COUNT(*) FROM sys.databases WHERE name = '$($Database)_Lock'" - $lockExists = ($command.ExecuteScalar() -eq 1) - $serverRolesToCheck = @("dbcreator", "securityadmin") $hasPermissions = $true foreach ($serverRole in $serverRolesToCheck) @@ -88,6 +85,10 @@ function Get-SPDscConfigDBStatus $configDBempty = ($command.ExecuteScalar() -eq 0) } + $connection.ChangeDatabase('TempDB') + $command.CommandText = "SELECT COUNT([name]) FROM sys.tables WHERE [name] = 'SPDscLock'" + $lockExists = ($command.ExecuteScalar() -eq 1) + return @{ DatabaseExists = $configDBexists DatabaseEmpty = $configDBempty @@ -232,7 +233,7 @@ function Add-SPDscConfigDBLock } else # Just use Windows integrated auth { - $connection.ConnectionString = "Server=$SQLServer;Integrated Security=SSPI;Database=Master" + $connection.ConnectionString = "Server=$SQLServer;Integrated Security=SSPI;Database=TempDB" } $command = New-Object -TypeName "System.Data.SqlClient.SqlCommand" @@ -241,8 +242,8 @@ function Add-SPDscConfigDBLock $connection.Open() $command.Connection = $connection - $command.CommandText = "CREATE DATABASE [$($Database)_Lock]" - $command.ExecuteNonQuery() + $command.CommandText = "CREATE TABLE SPDscLock (Locked BIT)" + $null = $command.ExecuteNonQuery() } finally { @@ -308,7 +309,7 @@ function Remove-SPDscConfigDBLock } else # Just use Windows integrated auth { - $connection.ConnectionString = "Server=$SQLServer;Integrated Security=SSPI;Database=Master" + $connection.ConnectionString = "Server=$SQLServer;Integrated Security=SSPI;Database=TempDB" } $command = New-Object -TypeName "System.Data.SqlClient.SqlCommand" @@ -317,8 +318,8 @@ function Remove-SPDscConfigDBLock $connection.Open() $command.Connection = $connection - $command.CommandText = "DROP DATABASE [$($Database)_Lock]" - $command.ExecuteNonQuery() + $command.CommandText = "DROP TABLE [SPDscLock]" + $null = $command.ExecuteNonQuery() } finally { @@ -329,4 +330,3 @@ function Remove-SPDscConfigDBLock } } } - From f17a22be6f43566339a487cc49c3dfbc5dc5ba8e Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 10 Nov 2020 16:12:31 +0100 Subject: [PATCH 9/9] Added SPFarm module tests --- .../SharePointDsc.Farm.Tests.ps1 | 456 ++++++++++++++++++ .../SharePointDsc.SPFarm.Tests.ps1 | 52 ++ 2 files changed, 508 insertions(+) create mode 100644 tests/Unit/SharePointDsc/SharePointDsc.Farm.Tests.ps1 diff --git a/tests/Unit/SharePointDsc/SharePointDsc.Farm.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.Farm.Tests.ps1 new file mode 100644 index 000000000..e40334deb --- /dev/null +++ b/tests/Unit/SharePointDsc/SharePointDsc.Farm.Tests.ps1 @@ -0,0 +1,456 @@ +# Ignoring this because we need to generate a stub credential to run the tests here +[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] +[CmdletBinding()] +param +( + [Parameter()] + [string] + $SharePointCmdletModule = (Join-Path -Path $PSScriptRoot ` + -ChildPath "..\Stubs\SharePoint\15.0.4805.1000\Microsoft.SharePoint.PowerShell.psm1" ` + -Resolve) +) + +#region HEADER +$script:projectPath = "$PSScriptRoot\..\..\.." | Convert-Path +$script:projectName = (Get-ChildItem -Path "$script:projectPath\*\*.psd1" | Where-Object -FilterScript { + ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and + $(try + { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop + } + catch + { $false + }) + }).BaseName + +$script:parentModule = Get-Module -Name $script:projectName -ListAvailable | Select-Object -First 1 +$script:subModulesFolder = Join-Path -Path $script:parentModule.ModuleBase -ChildPath 'Modules' +Remove-Module -Name $script:parentModule -Force -ErrorAction 'SilentlyContinue' + +$script:subModuleName = (Split-Path -Path $PSCommandPath -Leaf) -replace '\.Tests.ps1' +$script:subModuleFile = Join-Path -Path $script:subModulesFolder -ChildPath "$($script:subModuleName)\SPFarm.psm1" + +Import-Module $script:subModuleFile -Force -ErrorAction Stop +#endregion HEADER + +function Invoke-TestSetup +{ + try + { + Import-Module -Name DscResource.Test -Force + + Import-Module -Name (Join-Path -Path $PSScriptRoot ` + -ChildPath "..\UnitTestHelper.psm1" ` + -Resolve) + + $moduleVersionFolder = ($ModuleVersion -split "-")[0] + + $Global:SPDscHelper = New-SPDscUnitTestHelper -SharePointStubModule $SharePointCmdletModule ` + -SubModulePath "Modules\SharePointDsc.Farm\SPFarm.psm1" ` + -ExcludeInvokeHelper ` + -ModuleVersion $moduleVersionFolder + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + } +} + +function Invoke-TestCleanup +{ +} + +Invoke-TestSetup + +try +{ + InModuleScope -ModuleName $Global:SPDscHelper.ModuleName -ScriptBlock { + Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { + BeforeAll { + Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope + } + + Context -Name "Validate Get-SPDscConfigDBStatus" -Fixture { + BeforeAll { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + ConnectionString = '' + State = 'Open' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Open ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name ChangeDatabase ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Close ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Dispose ` + -Value { + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlConnection" + } + } + + It "Should return ValidPermissions=False" { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + Connection = '' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -name ExecuteScalar ` + -Value { + $global:RunQuery++ + switch ($global:RunQuery) + { + 1 # ConfigDB exists + { return 1 + } + 2 # Check permissions + { return "0" + } + 3 # Check permissions + { return "1" + } + 4 # Database empty + { return 20 + } + 5 # Locked + { return 0 + } + } + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlCommand" + } + + $global:RunQuery = 0 + $result = Get-SPDscConfigDBStatus -SQLServer 'sql01' -Database 'SP_Config' + $result.DatabaseExists | Should -Be $true + $result.DatabaseEmpty | Should -Be $false + $result.ValidPermissions | Should -Be $false + $result.Locked | Should -Be $false + } + + It "Should return DatabaseEmpty=False" { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + Connection = '' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -name ExecuteScalar ` + -Value { + $global:RunQuery++ + switch ($global:RunQuery) + { + 1 # ConfigDB exists + { return 1 + } + 2 # Check permissions + { return "1" + } + 3 # Check permissions + { return "1" + } + 4 # Database empty + { return 20 + } + 5 # Locked + { return 0 + } + } + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlCommand" + } + + $global:RunQuery = 0 + $result = Get-SPDscConfigDBStatus -SQLServer 'sql01' -Database 'SP_Config' + $result.DatabaseExists | Should -Be $true + $result.DatabaseEmpty | Should -Be $false + $result.ValidPermissions | Should -Be $true + $result.Locked | Should -Be $false + } + + It "Should return DatabaseExists=True" { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + Connection = '' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -name ExecuteScalar ` + -Value { + $global:RunQuery++ + switch ($global:RunQuery) + { + 1 # ConfigDB exists + { return 1 + } + 2 # Check permissions + { return "1" + } + 3 # Check permissions + { return "1" + } + 4 # Database empty + { return 0 + } + 5 # Locked + { return 0 + } + } + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlCommand" + } + + $global:RunQuery = 0 + $result = Get-SPDscConfigDBStatus -SQLServer 'sql01' -Database 'SP_Config' + $result.DatabaseExists | Should -Be $true + $result.DatabaseEmpty | Should -Be $true + $result.ValidPermissions | Should -Be $true + $result.Locked | Should -Be $false + } + + It "Should return DatabaseExists=False, ValidPermissions=True, DatabaseEmpty=False and Locked=False" { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + Connection = '' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -name ExecuteScalar ` + -Value { + $global:RunQuery++ + switch ($global:RunQuery) + { + 1 # ConfigDB exists + { return 0 + } + 2 # Check permissions + { return "1" + } + 3 # Check permissions + { return "1" + } + 4 # Locked + { return 0 + } + } + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlCommand" + } + + $global:RunQuery = 0 + $result = Get-SPDscConfigDBStatus -SQLServer 'sql01' -Database 'SP_Config' + $result.DatabaseExists | Should -Be $false + $result.DatabaseEmpty | Should -Be $false + $result.ValidPermissions | Should -Be $true + $result.Locked | Should -Be $false + } + } + + Context -Name "Validate Get-SPDscSQLInstanceStatus" -Fixture { + BeforeAll { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + ConnectionString = '' + State = 'Open' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Open ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Close ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Dispose ` + -Value { + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlConnection" + } + } + + It "Should return MaxDopCorrect=True" { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + Connection = '' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -name ExecuteScalar ` + -Value { + return 1 + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlCommand" + } + + $result = Get-SPDscSQLInstanceStatus -SQLServer 'sql01' + $result.MaxDOPCorrect | Should -Be $true + } + + It "Should return MaxDopCorrect=False" { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + Connection = '' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -name ExecuteScalar ` + -Value { + return 0 + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlCommand" + } + + $result = Get-SPDscSQLInstanceStatus -SQLServer 'sql01' + $result.MaxDOPCorrect | Should -Be $false + } + } + + Context -Name "Validate Add-SPDscConfigDBLock" -Fixture { + BeforeAll { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + ConnectionString = '' + State = 'Open' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Open ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Close ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Dispose ` + -Value { + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlConnection" + } + } + + It "Should run query to create TempDB Lock table" { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + Connection = '' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -name ExecuteNonQuery ` + -Value { + $global:ExecutedQuery = $true + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlCommand" + } + + $global:ExecutedQuery = $false + $result = Add-SPDscConfigDBLock -SQLServer 'sql01' -Database 'SP_Config' + $global:ExecutedQuery | Should -Be $true + } + } + + Context -Name "Validate Remove-SPDscConfigDBLock" -Fixture { + BeforeAll { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + ConnectionString = '' + State = 'Open' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Open ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Close ` + -Value { + } -PassThru -Force + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Dispose ` + -Value { + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlConnection" + } + } + + It "Should run query to create TempDB Lock table" { + Mock -CommandName New-Object -MockWith { + $returnval = @{ + Connection = '' + } + + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -name ExecuteNonQuery ` + -Value { + $global:ExecutedQuery = $true + } -PassThru -Force + + return $returnval + } -ParameterFilter { + $TypeName -eq "System.Data.SqlClient.SqlCommand" + } + + $global:ExecutedQuery = $false + $result = Remove-SPDscConfigDBLock -SQLServer 'sql01' -Database 'SP_Config' + $global:ExecutedQuery | Should -Be $true + } + } + } + } +} +finally +{ +} diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 index 94836ce9a..f9e6be1d6 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 @@ -316,6 +316,57 @@ try } } + Context -Name "A config database exists, but is empty. This server should be connected to it and needs to populate the empty database" -Fixture { + BeforeAll { + $testParams = @{ + IsSingleInstance = "Yes" + Ensure = "Present" + FarmConfigDatabaseName = "SP_Config" + DatabaseServer = "sql.contoso.com" + FarmAccount = $mockFarmAccount + Passphrase = $mockPassphrase + AdminContentDatabaseName = "SP_AdminContent" + RunCentralAdmin = $true + } + + Mock -CommandName "Get-SPDscRegistryKey" -MockWith { return $null } + Mock -CommandName "Get-SPFarm" -MockWith { return $null } + Mock -CommandName "Get-SPDscConfigDBStatus" -MockWith { + return @{ + Locked = $false + ValidPermissions = $false + DatabaseExists = $true + DatabaseEmpty = $true + } + } + Mock -CommandName "Get-SPDscSQLInstanceStatus" -MockWith { + return @{ + MaxDOPCorrect = $true + } + } + Mock -CommandName "Get-SPWebApplication" -MockWith { + return @{ + IsAdministrationWebApplication = $true + Url = "http://localhost:12345" + } + } + } + + It "Should return absent from the get method" { + (Get-TargetResource @testParams).Ensure | Should -Be "Absent" + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should create the config database in the set method" { + Set-TargetResource @testParams + Assert-MockCalled -CommandName "New-SPConfigurationDatabase" + Assert-MockCalled -CommandName "New-SPCentralAdministration" + } + } + Context -Name "A config database exists, and this server should be connected to it but isn't and this server won't run central admin" -Fixture { BeforeAll { $testParams = @{ @@ -430,6 +481,7 @@ try Locked = $false ValidPermissions = $true DatabaseExists = $true + DatabaseEmpty = $false } } Mock -CommandName "Get-SPDscSQLInstanceStatus" -MockWith {