From 6d29f43b1ae2f0c53a2370038f6430051b1456ad Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 1 Apr 2021 21:30:26 +0200 Subject: [PATCH 1/8] Removal of spaces --- .../MSFT_SPPowerPointAutomationServiceApp.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharePointDsc/DSCResources/MSFT_SPPowerPointAutomationServiceApp/MSFT_SPPowerPointAutomationServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPPowerPointAutomationServiceApp/MSFT_SPPowerPointAutomationServiceApp.psm1 index da43cae8e..34f09bdd6 100644 --- a/SharePointDsc/DSCResources/MSFT_SPPowerPointAutomationServiceApp/MSFT_SPPowerPointAutomationServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPPowerPointAutomationServiceApp/MSFT_SPPowerPointAutomationServiceApp.psm1 @@ -362,7 +362,7 @@ function Set-TargetResource $serviceApps = Get-SPServiceApplication | Where-Object -FilterScript { $_.Name -eq $params.Name } - + if ($null -eq $serviceApps) { return; From fd22597672731496178c8dcb33ff3e920aaa3a1b Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 14 Apr 2021 15:21:17 +0200 Subject: [PATCH 2/8] Fixing #1248 --- CHANGELOG.md | 8 +++- .../MSFT_SPUserProfileProperty.psm1 | 46 +++++++++++++++++++ ...rePointDsc.SPUserProfileProperty.Tests.ps1 | 38 ++++++++++++++- 3 files changed, 88 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c318341f7..f14832223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added + - SPSecurityTokenServiceConfig - Added support for LogonTokenCacheExpirationWindow, WindowsTokenLifetime and FormsTokenLifetime settings - SPService - New resource -- SPUsageDefinition - - New resource - SPSecurityTokenServiceConfig - Added support for LogonTokenCacheExpirationWindow, WindowsTokenLifetime and FormsTokenLifetime settings +- SPUsageDefinition + - New resource +- SPUserProfileProperty + - Added check for unique ConnectionNames in PropertyMappings, which is required by SharePoint ### Fixed + - SharePointDsc - Fixed code coverage in pipeline. - SPConfigWizard diff --git a/SharePointDsc/DSCResources/MSFT_SPUserProfileProperty/MSFT_SPUserProfileProperty.psm1 b/SharePointDsc/DSCResources/MSFT_SPUserProfileProperty/MSFT_SPUserProfileProperty.psm1 index d4dd3f4a8..38698f21d 100644 --- a/SharePointDsc/DSCResources/MSFT_SPUserProfileProperty/MSFT_SPUserProfileProperty.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPUserProfileProperty/MSFT_SPUserProfileProperty.psm1 @@ -121,6 +121,30 @@ function Get-TargetResource Write-Verbose -Message "Getting user profile property $Name" + if ($PSBoundParameters.ContainsKey("PropertyMappings") -eq $true) + { + $connections = $PropertyMappings.ConnectionName + + $connectionsCounts = @{} + $duplicates = "" + $connections | ForEach-Object -Process { $connectionsCounts["$_"] += 1 } + $connectionsCounts.Keys | Where-Object -FilterScript { $connectionsCounts["$_"] -gt 1 } | ForEach-Object -Process { $duplicates += "$_," } + $duplicates = $duplicates.TrimEnd(",") + + if ([System.String]::IsNullOrEmpty($duplicates) -eq $false) + { + $message = ("You have specified two PropertyMappings with the same ConnectionName. " + ` + "Make sure each PropertyMapping is using a unique ConnectionName: $duplicate") + Write-Verbose -Message $message + + return @{ + Name = $Name + UserProfileService = $UserProfileService + Ensure = "Absent" + } + } + } + $result = Invoke-SPDscCommand -Credential $InstallAccount ` -Arguments $PSBoundParameters ` -ScriptBlock { @@ -421,6 +445,28 @@ function Set-TargetResource Write-Verbose -Message "Setting user profile property $Name" + if ($PSBoundParameters.ContainsKey("PropertyMappings") -eq $true) + { + $connections = $PropertyMappings.ConnectionName + + $connectionsCounts = @{} + $duplicates = "" + $connections | ForEach-Object -Process { $connectionsCounts["$_"] += 1 } + $connectionsCounts.Keys | Where-Object -FilterScript { $connectionsCounts["$_"] -gt 1 } | ForEach-Object -Process { $duplicates += "$_," } + $duplicates = $duplicates.TrimEnd(",") + + if ([System.String]::IsNullOrEmpty($duplicates) -eq $false) + { + $message = ("You have specified two PropertyMappings with the same ConnectionName. " + ` + "Make sure each PropertyMapping is using a unique ConnectionName: $duplicate") + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + } + $PSBoundParameters.Ensure = $Ensure Invoke-SPDscCommand -Credential $InstallAccount ` diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPUserProfileProperty.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPUserProfileProperty.Tests.ps1 index 61f8b5f9f..a048b8d71 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPUserProfileProperty.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPUserProfileProperty.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 $testParamsNewProperty = @{ Name = "WorkEmailNew" @@ -344,7 +344,7 @@ try } -ParameterFilter { $TypeName -eq "Microsoft.Office.Server.UserProfiles.UserProfileManager" } Mock Invoke-SPDscCommand { - return Invoke-Command -Scriptblock $ScriptBlock -ArgumentList $Arguments -NoNewScope + return Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $Arguments -NoNewScope } $propertyMappingItem = @{ @@ -468,6 +468,40 @@ try } } + Context -Name "Same ConnectionName is specified multiple times in PropertyMappings" { + BeforeAll { + $testParams = @{ + Name = "WorkEmail" + UserProfileService = "User Profile Service Application" + DisplayName = "WorkEmail" + Type = "String (Single Value)" + Description = "" + PolicySetting = "Mandatory" + PrivacySetting = "Public" + PropertyMappings = @( + (New-CimInstance -ClassName MSFT_SPUserProfilePropertyMapping -ClientOnly -Property @{ + ConnectionName = "contoso" + PropertyName = "department" + Direction = "Import" + }), + (New-CimInstance -ClassName MSFT_SPUserProfilePropertyMapping -ClientOnly -Property @{ + ConnectionName = "contoso" + PropertyName = "givenname" + Direction = "Import" + }) + ) + } + } + + It "Should return Ensure = Absent" { + (Get-TargetResource @testParams).Ensure | Should -Be "Absent" + } + + It "Should throw an exception" { + { Set-TargetResource @testParams } | Should -Throw "You have specified two PropertyMappings with the same ConnectionName. Make sure each PropertyMapping is using a unique ConnectionName:" + } + } + Context -Name "Non-Existing User Profile Service Application" { BeforeAll { Mock -CommandName Get-SPServiceApplication { return $null } From ee2d9a9e40d4f79750660a37c21dc7396820f0a0 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 23 Apr 2021 10:29:46 +0200 Subject: [PATCH 3/8] Fixing issue #1311 --- CHANGELOG.md | 3 + CODE_OF_CONDUCT.md | 10 +- .../MSFT_SPSearchServiceApp.psm1 | 163 ++++++++- .../MSFT_SPSearchServiceApp.schema.mof | 2 +- .../MSFT_SPSearchServiceApp/readme.md | 6 + .../SPSearchServiceApp.psm1 | 172 ++++++++++ ...SharePointDsc.SPSearchServiceApp.Tests.ps1 | 310 +++++++++++++----- 7 files changed, 582 insertions(+), 84 deletions(-) create mode 100644 SharePointDsc/Modules/SharePointDsc.Search/SPSearchServiceApp.psm1 diff --git a/CHANGELOG.md b/CHANGELOG.md index f14832223..e8df6d3e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- SPSearchServiceApp + - Added ability to correct database permissions for the farm account, to prevent issue + as described in the Readme of the resource - SPSecurityTokenServiceConfig - Added support for LogonTokenCacheExpirationWindow, WindowsTokenLifetime and FormsTokenLifetime settings - SPService diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index d7589ddbb..f9ba8cf65 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,9 @@ -# Code of Conduct +# Microsoft Open Source Code of Conduct -This project has adopted the [DSC Community Code of Conduct](https://dsccommunity.org/code_of_conduct). +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +Resources: + +- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) +- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 index eb0e0e82c..4c79d433f 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 @@ -55,6 +55,10 @@ function Get-TargetResource [System.Boolean] $AlertsEnabled, + [Parameter()] + [System.Boolean] + $FixFarmAccountPermissions = $true, + [Parameter()] [System.Management.Automation.PSCredential] $DefaultContentAccessAccount, @@ -72,7 +76,8 @@ function Get-TargetResource $params = $args[0] $scriptRoot = $args[1] - Import-Module -Name (Join-Path $scriptRoot "MSFT_SPSearchServiceApp.psm1") + $modulePath = "..\..\Modules\SharePointDsc.Search\SPSearchServiceApp.psm1" + Import-Module -Name (Join-Path -Path $scriptRoot -ChildPath $modulePath -Resolve) -Verbose:$false [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration") @@ -143,6 +148,56 @@ function Get-TargetResource } } + Write-Verbose -Message "Checking Farm account permissions" + $correctFarmAccountPermissions = $true + + $farmAccount = (Get-SPFarm).DefaultServiceAccount.Name + $dbServer = $serviceApp.SearchAdminDatabase.NormalizedDataSource + + Write-Verbose -Message "Checking Admin Database" + $adminDB = $serviceApp.SearchAdminDatabase.Name + if ($correctFarmAccountPermissions -eq $true) + { + $correctFarmAccountPermissions = Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $adminDB ` + -User $farmAccount + } + + Write-Verbose -Message "Checking Analytics reporting Database" + $analyticsDB = "$($adminDB)_AnalyticsReportingStore" + if ($correctFarmAccountPermissions -eq $true) + { + $correctFarmAccountPermissions = Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $analyticsDB ` + -User $farmAccount + } + + Write-Verbose -Message "Checking Crawl Database(s)" + if ($correctFarmAccountPermissions -eq $true) + { + foreach ($database in (Get-SPEnterpriseSearchCrawlDatabase -SearchApplication $serviceApp)) + { + $crawlDB = $database.Database.Name + $dbServer = $database.Database.NormalizedDataSource + $correctFarmAccountPermissions = Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $crawlDB ` + -User $farmAccount + } + } + + Write-Verbose -Message "Checking Links Database(s)" + if ($correctFarmAccountPermissions -eq $true) + { + foreach ($database in (Get-SPEnterpriseSearchLinksDatabase -SearchApplication $serviceApp)) + { + $linksDB = $database.Database.Name + $dbServer = $database.Database.NormalizedDataSource + $correctFarmAccountPermissions = Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $linksDB ` + -User $farmAccount + } + } + $returnVal = @{ Name = $serviceApp.DisplayName ProxyName = $pName @@ -154,6 +209,7 @@ function Get-TargetResource DefaultContentAccessAccount = $defaultAccount CloudIndex = $cloudIndex AlertsEnabled = $serviceApp.AlertsEnabled + FixFarmAccountPermissions = $correctFarmAccountPermissions } return $returnVal } @@ -211,6 +267,10 @@ function Set-TargetResource [System.Boolean] $AlertsEnabled, + [Parameter()] + [System.Boolean] + $FixFarmAccountPermissions = $true, + [Parameter()] [System.Management.Automation.PSCredential] $DefaultContentAccessAccount, @@ -222,12 +282,13 @@ function Set-TargetResource Write-Verbose -Message "Setting Search service application '$Name'" + $PSBoundParameters.FixFarmAccountPermissions = $FixFarmAccountPermissions + $result = Get-TargetResource @PSBoundParameters 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 -Credential $InstallAccount ` -Arguments @($PSBoundParameters, $MyInvocation.MyCommand.Source) ` @@ -446,6 +507,87 @@ function Set-TargetResource } } + # Only check and correct when Ensure=Present, FixFarmAccountPermissions=True and the permissions are incorrect + if ($Ensure -eq "Present" -and ` + $FixFarmAccountPermissions -eq $true -and ` + $result.FixFarmAccountPermissions -eq $false) + { + Write-Verbose -Message "Fixing database permissions for Search Service Application $Name" + Invoke-SPDscCommand -Credential $InstallAccount ` + -Arguments @($PSBoundParameters, $PSScriptRoot) ` + -ScriptBlock { + $params = $args[0] + $scriptRoot = $args[1] + + $modulePath = "..\..\Modules\SharePointDsc.Search\SPSearchServiceApp.psm1" + Import-Module -Name (Join-Path -Path $scriptRoot -ChildPath $modulePath -Resolve) -Verbose:$false + + $serviceApp = Get-SPServiceApplication | Where-Object -FilterScript { + $_.Name -eq $params.Name -and ` + $_.GetType().FullName -eq "Microsoft.Office.Server.Search.Administration.SearchServiceApplication" + } + + $farmAccount = (Get-SPFarm).DefaultServiceAccount.Name + $dbServer = $serviceApp.SearchAdminDatabase.NormalizedDataSource + + Write-Verbose -Message "Checking and correcting Admin Database" + $adminDB = $serviceApp.SearchAdminDatabase.Name + if ((Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $adminDB ` + -User $farmAccount) -eq $false) + { + Set-UserAsDBOwner -SQLServer $dbServer ` + -Database $adminDB ` + -User $farmAccount + } + + Write-Verbose -Message "Checking and correcting Analytics reporting Database" + $analyticsDB = "$($adminDB)_AnalyticsReportingStore" + if ((Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $analyticsDB ` + -User $farmAccount) -eq $false) + { + Set-UserAsDBOwner -SQLServer $dbServer ` + -Database $analyticsDB ` + -User $farmAccount + } + + Write-Verbose -Message "Checking and correcting Crawl Database(s)" + foreach ($database in (Get-SPEnterpriseSearchCrawlDatabase -SearchApplication $serviceApp)) + { + $crawlDB = $database.Database.Name + Write-Verbose -Message " * Processing $crawlDB" + + $dbServer = $database.Database.NormalizedDataSource + if ((Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $crawlDB ` + -User $farmAccount) -eq $false) + { + Set-UserAsDBOwner -SQLServer $dbServer ` + -Database $crawlDB ` + -User $farmAccount + } + } + + Write-Verbose -Message "Checking and correcting Links Database(s)" + foreach ($database in (Get-SPEnterpriseSearchLinksDatabase -SearchApplication $serviceApp)) + { + $linksDB = $database.Database.Name + Write-Verbose -Message " * Processing $linksDB" + + $dbServer = $database.Database.NormalizedDataSource + if ((Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $linksDB ` + -User $farmAccount) -eq $false) + { + Set-UserAsDBOwner -SQLServer $dbServer ` + -Database $linksDB ` + -User $farmAccount + } + } + } + } + if ($Ensure -eq "Absent") { # The service app should not exit @@ -525,6 +667,10 @@ function Test-TargetResource [System.Boolean] $AlertsEnabled, + [Parameter()] + [System.Boolean] + $FixFarmAccountPermissions = $true, + [Parameter()] [System.Management.Automation.PSCredential] $DefaultContentAccessAccount, @@ -537,6 +683,7 @@ function Test-TargetResource Write-Verbose -Message "Testing Search service application '$Name'" $PSBoundParameters.Ensure = $Ensure + $PSBoundParameters.FixFarmAccountPermissions = $FixFarmAccountPermissions $CurrentValues = Get-TargetResource @PSBoundParameters @@ -555,8 +702,18 @@ function Test-TargetResource "Actual: $current Desired: $desired") Write-Verbose -Message $message Add-SPDscEvent -Message $message -EntryType 'Error' -EventID 1 -Source $MyInvocation.MyCommand.Source + return $false + } + } - Write-Verbose -Message "Desired: $desired. Current: $current." + if ($FixFarmAccountPermissions -eq $true) + { + if ($CurrentValues.FixFarmAccountPermissions -eq $false) + { + $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 return $false } } diff --git a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.schema.mof b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.schema.mof index 9708de689..277086f54 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.schema.mof +++ b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.schema.mof @@ -10,9 +10,9 @@ class MSFT_SPSearchServiceApp : OMI_BaseResource [Write, Description("The default content access account for this search service app"), EmbeddedInstance("MSFT_Credential")] String DefaultContentAccessAccount; [Write, Description("Should this search service application be a cloud based service app")] boolean CloudIndex; [Write, Description("Should alerts be enabled for this search service application")] boolean AlertsEnabled; + [Write, Description("Should the permissions for the Farm account on the Search databases be corrected")] boolean FixFarmAccountPermissions; [Write, Description("Present if the service app should exist, absent if it should not"), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; [Write, Description("POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsCredential if using PowerShell 5"), EmbeddedInstance("MSFT_Credential")] String InstallAccount; [Write, Description("Should SQL Server authentication be used to connect to the database?")] Boolean UseSQLAuthentication; [Write, Description("If using SQL authentication, the SQL credentials to use to connect to the instance"), EmbeddedInstance("MSFT_Credential")] String DatabaseCredentials; }; - diff --git a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/readme.md b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/readme.md index 9a2b282e0..afe5d8ec4 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/readme.md @@ -17,3 +17,9 @@ parameter, the service application is provisioned. NOTE: The WindowsServiceAccount parameter is deprecated and no longer does anything. The functionality for changing this account has been moved to SPSearchServiceSettings. + +NOTE2: The resource is also able to add the Farm account as db_owner to all +Search databases, to prevent the issue described here: +https://www.techmikael.com/2014/10/caution-if-you-have-used.html +Use the FixFarmAccountPermissions parameter to implement this fix (default +$true if not specified). diff --git a/SharePointDsc/Modules/SharePointDsc.Search/SPSearchServiceApp.psm1 b/SharePointDsc/Modules/SharePointDsc.Search/SPSearchServiceApp.psm1 new file mode 100644 index 000000000..5b2eb49e6 --- /dev/null +++ b/SharePointDsc/Modules/SharePointDsc.Search/SPSearchServiceApp.psm1 @@ -0,0 +1,172 @@ +$script:SPDscUtilModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\SharePointDsc.Util' +Import-Module -Name $script:SPDscUtilModulePath + +function Confirm-UserIsDBOwner +{ + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $SQLServer, + + [Parameter(Mandatory = $true)] + [System.String] + $Database, + + [Parameter(Mandatory = $true)] + [System.String] + $User, + + [Parameter()] + [PSCredential] + $DatabaseCredentials + ) + + $connection = New-Object -TypeName "System.Data.SqlClient.SqlConnection" + $command = New-Object -TypeName "System.Data.SqlClient.SqlCommand" + + # If we specified SQL credentials then try to use them + if ($PSBoundParameters.ContainsKey("DatabaseCredentials")) + { + $marshal = [Runtime.InteropServices.Marshal] + $dbCredentialsPlainPassword = $marshal::PtrToStringAuto($marshal::SecureStringToBSTR($DatabaseCredentials.Password)) + $connection.ConnectionString = "Server=$SQLServer;Integrated Security=False;User ID=$($DatabaseCredentials.Username);Password=$dbCredentialsPlainPassword;Database=master" + } + else # Just use Windows integrated auth + { + $connection.ConnectionString = "Server=$SQLServer;Integrated Security=SSPI;Database=master" + } + + try + { + $connection.Open() + $command.Connection = $connection + + $command.CommandText = @" +USE $Database + +SELECT DP1.name AS DatabaseRoleName, + isnull (DP2.name, 'No members') AS DatabaseUserName + FROM sys.database_role_members AS DRM + RIGHT OUTER JOIN sys.database_principals AS DP1 + ON DRM.role_principal_id = DP1.principal_id + LEFT OUTER JOIN sys.database_principals AS DP2 + ON DRM.member_principal_id = DP2.principal_id +WHERE DP1.type = 'R' AND DP2.name = '$User' AND DP1.name = 'db_owner' +"@ + + $result = ($command.ExecuteScalar() -eq "db_owner") + } + catch + { + throw "Error while running SQL query: $($_.Exception.InnerException.Message)" + $result = $false + } + finally + { + if ($connection.State -eq "Open") + { + $connection.Close() + $connection.Dispose() + } + } + + return $result +} + +function Set-UserAsDBOwner +{ + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $SQLServer, + + [Parameter(Mandatory = $true)] + [System.String] + $Database, + + [Parameter(Mandatory = $true)] + [System.String] + $User, + + [Parameter()] + [PSCredential] + $DatabaseCredentials + ) + + $connection = New-Object -TypeName "System.Data.SqlClient.SqlConnection" + $command = New-Object -TypeName "System.Data.SqlClient.SqlCommand" + + # If we specified SQL credentials then try to use them + if ($PSBoundParameters.ContainsKey("DatabaseCredentials")) + { + $marshal = [Runtime.InteropServices.Marshal] + $dbCredentialsPlainPassword = $marshal::PtrToStringAuto($marshal::SecureStringToBSTR($DatabaseCredentials.Password)) + $connection.ConnectionString = "Server=$SQLServer;Integrated Security=False;User ID=$($DatabaseCredentials.Username);Password=$dbCredentialsPlainPassword;Database=master" + } + else # Just use Windows integrated auth + { + $connection.ConnectionString = "Server=$SQLServer;Integrated Security=SSPI;Database=master" + } + + try + { + $connection.Open() + $command.Connection = $connection + + $command.CommandText = @" +USE $Database + +DECLARE @NewUserName sysname; + +SET @NewUserName = '$User'; + +/* Users are typically mapped to logins, as OP's question implies, +so make sure an appropriate login exists. */ +IF NOT EXISTS(SELECT principal_id FROM sys.server_principals WHERE name = @NewUserName) BEGIN + /* Syntax for SQL server login. See BOL for domain logins, etc. */ + DECLARE @LoginSQL as varchar(500); + SET @LoginSQL = 'CREATE LOGIN ['+ @NewUserName + '] FROM WINDOWS'; + EXEC (@LoginSQL); +END + +/* Create the user for the specified login. */ +IF NOT EXISTS(SELECT principal_id FROM sys.database_principals WHERE name = @NewUserName) BEGIN + DECLARE @UserSQL as varchar(500); + SET @UserSQL = 'CREATE USER [' + @NewUserName + '] FOR LOGIN [' + @NewUserName + ']'; + EXEC (@UserSQL); +END + +IF NOT EXISTS + (SELECT DP1.name AS DatabaseRoleName, + isnull (DP2.name, 'No members') AS DatabaseUserName + FROM sys.database_role_members AS DRM + RIGHT OUTER JOIN sys.database_principals AS DP1 + ON DRM.role_principal_id = DP1.principal_id + LEFT OUTER JOIN sys.database_principals AS DP2 + ON DRM.member_principal_id = DP2.principal_id + WHERE DP1.type = 'R' AND DP2.name = @NewUserName AND DP1.name = 'db_owner') +BEGIN + DECLARE @roleSQL as varchar(500); + SET @roleSQL = 'ALTER ROLE db_owner ADD MEMBER [' + @NewUserName + ']'; + EXEC (@roleSQL); +END +"@ + $null = $command.ExecuteNonQuery() + } + catch + { + throw "Error while running SQL query: $($_.Exception.InnerException.Message)" + } + finally + { + if ($connection.State -eq "Open") + { + $connection.Close() + $connection.Dispose() + } + } +} + +Export-ModuleMember -Function * diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 index 51ed0266e..8d44f6626 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 @@ -50,9 +50,13 @@ 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 $PSScriptRoot ` + -ChildPath "..\..\..\output\SharePointDsc\$ModuleVersion\Modules\SharePointDsc.Search\SPSearchServiceApp.psm1" ` + -Resolve) + $getTypeFullName = "Microsoft.Office.Server.Search.Administration.SearchServiceApplication" Add-Type -TypeDefinition @" @@ -102,6 +106,42 @@ try } } + Mock -CommandName Get-SPFarm -MockWith { + return @{ + DefaultServiceAccount = @{ + Name = 'contoso\sa_farm' + } + } + } + + Mock -CommandName Get-SPEnterpriseSearchCrawlDatabase -MockWith { + return @( + @{ + Database = @{ + Name = 'SP_Search_CrawlStore' + NormalizedDataSource = 'SQL01' + } + } + ) + } + + Mock -CommandName Get-SPEnterpriseSearchLinksDatabase -MockWith { + return @( + @{ + Database = @{ + Name = 'SP_Search_LinksStore' + NormalizedDataSource = 'SQL01' + } + } + ) + } + + Mock -CommandName Confirm-UserIsDBOwner -MockWith { + return $true + } + + Mock -CommandName Set-UserAsDBOwner -MockWith {} + function Add-SPDscEvent { param ( @@ -151,6 +191,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = 'SP_Search' AlertsEnabled = $true Ensure = "Present" } @@ -167,14 +208,18 @@ try else { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - AlertsEnabled = $false - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + AlertsEnabled = $false + Database = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member ScriptMethod Update { @@ -247,11 +292,66 @@ try } } + Context -Name "When a service application exists but the database permissions are not fixed" -Fixture { + BeforeAll { + $testParams = @{ + Name = "Search Service Application" + ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" + FixFarmAccountPermissions = $true + Ensure = "Present" + } + + Mock Import-Module -MockWith { } -ParameterFilter { $_.Name -eq $ModuleName } + + Mock -CommandName Get-SPServiceApplication -MockWith { + $spServiceApp = [PSCustomObject]@{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + Database = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' + } + } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } + } -PassThru -Force + return $spServiceApp + } + + + Mock -CommandName Confirm-UserIsDBOwner -MockWith { + return $false + } + } + + It "Should return FixFarmAccountPermissions=False from the get method" { + (Get-TargetResource @testParams).FixFarmAccountPermissions | Should -Be $false + Assert-MockCalled Confirm-UserIsDBOwner + } + + It "Should return false when the Test method is called" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should correct database permissions in the set method" { + Set-TargetResource @testParams + Assert-MockCalled Set-UserAsDBOwner -Times 4 + } + } + Context -Name "When a service application exists and is configured correctly" -Fixture { BeforeAll { $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" } @@ -259,13 +359,17 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + Database = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { @@ -290,6 +394,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" } @@ -297,13 +402,17 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = "Wrong App Pool Name" } - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = "Wrong App Pool Name" } + Database = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { @@ -346,6 +455,7 @@ try Name = "Search Service Application" ProxyName = "Search SA Proxy" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" } @@ -353,13 +463,17 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + Database = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { @@ -406,6 +520,7 @@ try Name = "Search Service Application" ProxyName = "Search SA Proxy" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" } @@ -413,13 +528,17 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + Database = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { @@ -457,6 +576,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" DefaultContentAccessAccount = $mockCredential } @@ -465,13 +585,17 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + Database = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { @@ -515,6 +639,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" DefaultContentAccessAccount = $mockCredential } @@ -523,15 +648,19 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } - Database = @{ + Database = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { @@ -559,6 +688,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" SearchCenterUrl = "http://search.sp.contoso.com" } @@ -569,14 +699,18 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - SearchCenterUrl = "http://wrong.url.here" - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + SearchCenterUrl = "http://wrong.url.here" + Database = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member ScriptMethod Update { @@ -627,6 +761,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" AlertsEnabled = $true } @@ -637,14 +772,18 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - AlertsEnabled = $false - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + AlertsEnabled = $false + Database = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member ScriptMethod Update { @@ -695,6 +834,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" } @@ -708,14 +848,18 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - SearchCenterUrl = "http://search.sp.contoso.com" - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + SearchCenterUrl = "http://search.sp.contoso.com" + Database = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { @@ -743,6 +887,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Absent" } @@ -750,15 +895,19 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } - Database = @{ + Database = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { @@ -811,6 +960,7 @@ try $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" + DatabaseName = "SP_Search" Ensure = "Present" CloudIndex = $true } @@ -819,14 +969,18 @@ try Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ - TypeName = "Search Service Application" - DisplayName = $testParams.Name - Name = $testParams.Name - ApplicationPool = @{ Name = $testParams.ApplicationPool } - CloudIndex = $true - Database = @{ + TypeName = "Search Service Application" + DisplayName = $testParams.Name + Name = $testParams.Name + ApplicationPool = @{ Name = $testParams.ApplicationPool } + CloudIndex = $true + Database = @{ + Name = $testParams.DatabaseName + NormalizedDataSource = 'SQL01' + } + SearchAdminDatabase = @{ Name = $testParams.DatabaseName - NormalizedDataSource = $testParams.DatabaseServer + NormalizedDataSource = 'SQL01' } } $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { From b16f08cec4aa8f37061d10a0578ba6859f54bb46 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 3 Jun 2021 12:57:11 +0200 Subject: [PATCH 4/8] Enhancement of SPWebAppAuth #1199 --- CHANGELOG.md | 3 + .../MSFT_SPWebAppAuthentication.psm1 | 596 ++++++++++++++- .../MSFT_SPWebAppAuthentication.schema.mof | 14 +- .../MSFT_SPWebAppAuthentication/readme.md | 9 +- .../6-AuthenticationSettings.ps1 | 68 ++ ...ePointDsc.SPWebAppAuthentication.Tests.ps1 | 698 +++++++++++++++++- 6 files changed, 1353 insertions(+), 35 deletions(-) create mode 100644 SharePointDsc/Examples/Resources/SPWebAppAuthentication/6-AuthenticationSettings.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index e8df6d3e0..e7bf629c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New resource - SPUserProfileProperty - Added check for unique ConnectionNames in PropertyMappings, which is required by SharePoint +- SPWebAppAuthentication + - Added ability to configure generic authentication settings per zone, like allow + anonymous authentication or a custom signin page ### Fixed diff --git a/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/MSFT_SPWebAppAuthentication.psm1 b/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/MSFT_SPWebAppAuthentication.psm1 index 0a62e1799..76784bbe7 100644 --- a/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/MSFT_SPWebAppAuthentication.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/MSFT_SPWebAppAuthentication.psm1 @@ -31,6 +31,26 @@ function Get-TargetResource [Microsoft.Management.Infrastructure.CimInstance[]] $Custom, + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $DefaultSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $IntranetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $InternetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ExtranetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $CustomSettings, + [Parameter()] [System.Management.Automation.PSCredential] $InstallAccount @@ -39,21 +59,31 @@ function Get-TargetResource Write-Verbose -Message "Getting web application authentication for '$WebAppUrl'" $nullreturn = @{ - WebAppUrl = $WebAppUrl - Default = $null - Intranet = $null - Internet = $null - Extranet = $null - Custom = $null + WebAppUrl = $WebAppUrl + Default = $null + Intranet = $null + Internet = $null + Extranet = $null + Custom = $null + DefaultSettings = $null + IntranetSettings = $null + InternetSettings = $null + ExtranetSettings = $null + CustomSettings = $null } if ($PSBoundParameters.ContainsKey("Default") -eq $false -and ` $PSBoundParameters.ContainsKey("Intranet") -eq $false -and ` $PSBoundParameters.ContainsKey("Internet") -eq $false -and ` $PSBoundParameters.ContainsKey("Extranet") -eq $false -and ` - $PSBoundParameters.ContainsKey("Custom") -eq $false) + $PSBoundParameters.ContainsKey("Custom") -eq $false -and ` + $PSBoundParameters.ContainsKey("DefaultSettings") -eq $false -and ` + $PSBoundParameters.ContainsKey("IntranetSettings") -eq $false -and ` + $PSBoundParameters.ContainsKey("InternetSettings") -eq $false -and ` + $PSBoundParameters.ContainsKey("ExtranetSettings") -eq $false -and ` + $PSBoundParameters.ContainsKey("CustomSettings") -eq $false) { - Write-Verbose -Message "You have to specify at least one zone." + Write-Verbose -Message "You have to specify at least one parameter." return $nullreturn } @@ -110,24 +140,43 @@ function Get-TargetResource $wa = Get-SPWebApplication -Identity $params.WebAppUrl -ErrorAction SilentlyContinue if ($null -eq $wa) { + Write-Verbose -Message "Specified web application not found!" return @{ - WebAppUrl = $params.WebAppUrl - Default = $null - Intranet = $null - Internet = $null - Extranet = $null - Custom = $null + WebAppUrl = $params.WebAppUrl + Default = $null + Intranet = $null + Internet = $null + Extranet = $null + Custom = $null + DefaultSettings = $null + IntranetSettings = $null + InternetSettings = $null + ExtranetSettings = $null + CustomSettings = $null } } $zones = $wa.IisSettings.Keys $zoneConfig = @{} + $zoneSettings = @{} foreach ($zone in $zones) { $zoneName = $zone.ToString() $zoneConfig.$zoneName = @() + $zoneSettings.$zoneName = "" + + Write-Verbose -Message "Getting Zone Settings for zone '$zone'" + $settings = @{ + AnonymousAuthentication = $wa.IisSettings[$zone].AllowAnonymous + CustomSignInPage = $wa.IisSettings[$zone].ClaimsAuthenticationRedirectionUrl + EnableClientIntegration = $wa.IisSettings[$zone].EnableClientIntegration + RequireUseRemoteInterfaces = $wa.IisSettings[$zone].ClientObjectModelRequiresUseRemoteAPIsPermission + } + + $zoneSettings.$zoneName = $settings + Write-Verbose -Message "Getting Authentication Methods for zone '$zone'" $authProviders = Get-SPAuthenticationProvider -WebApplication $params.WebAppUrl -Zone $zone if ($null -eq $authProviders) { @@ -201,12 +250,17 @@ function Get-TargetResource } return @{ - WebAppUrl = $params.WebAppUrl - Default = $zoneConfig.Default - Intranet = $zoneConfig.Intranet - Internet = $zoneConfig.Internet - Extranet = $zoneConfig.Extranet - Custom = $zoneConfig.Custom + WebAppUrl = $params.WebAppUrl + Default = $zoneConfig.Default + Intranet = $zoneConfig.Intranet + Internet = $zoneConfig.Internet + Extranet = $zoneConfig.Extranet + Custom = $zoneConfig.Custom + DefaultSettings = $zoneSettings.Default + IntranetSettings = $zoneSettings.Intranet + InternetSettings = $zoneSettings.Internet + ExtranetSettings = $zoneSettings.Extranet + CustomSettings = $zoneSettings.Custom } } return $result @@ -241,6 +295,26 @@ function Set-TargetResource [Microsoft.Management.Infrastructure.CimInstance[]] $Custom, + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $DefaultSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $IntranetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $InternetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ExtranetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $CustomSettings, + [Parameter()] [System.Management.Automation.PSCredential] $InstallAccount @@ -253,9 +327,14 @@ function Set-TargetResource $PSBoundParameters.ContainsKey("Intranet") -eq $false -and ` $PSBoundParameters.ContainsKey("Internet") -eq $false -and ` $PSBoundParameters.ContainsKey("Extranet") -eq $false -and ` - $PSBoundParameters.ContainsKey("Custom") -eq $false) + $PSBoundParameters.ContainsKey("Custom") -eq $false -and ` + $PSBoundParameters.ContainsKey("DefaultSettings") -eq $false -and ` + $PSBoundParameters.ContainsKey("IntranetSettings") -eq $false -and ` + $PSBoundParameters.ContainsKey("InternetSettings") -eq $false -and ` + $PSBoundParameters.ContainsKey("ExtranetSettings") -eq $false -and ` + $PSBoundParameters.ContainsKey("CustomSettings") -eq $false) { - $message = "You have to specify at least one zone." + $message = "You have to specify at least one parameter." Add-SPDscEvent -Message $message ` -EntryType 'Error' ` -EventID 100 ` @@ -352,17 +431,34 @@ function Set-TargetResource if ($Default) { - # Test is current config matches desired config + # Test if current config matches desired config + Write-Verbose -Message "Testing Authentication for Default zone" $result = Test-ZoneConfiguration -DesiredConfig $Default ` -CurrentConfig $CurrentValues.Default # If that is the case, set desired config. if ($result -eq $false) { + Write-Verbose -Message "Correcting Authentication for Default zone" Set-ZoneConfiguration -WebAppUrl $WebAppUrl -Zone "Default" -DesiredConfig $Default } } + if ($DefaultSettings) + { + # Test if current config matches desired config + Write-Verbose -Message "Testing Settings for Default zone" + $result = Test-ZoneSettings -DesiredSettings $DefaultSettings ` + -CurrentSettings $CurrentValues.DefaultSettings + + # If that is the case, set desired config. + if ($result -eq $false) + { + Write-Verbose -Message "Correcting Settings for Default zone" + Set-ZoneSettings -WebAppUrl $WebAppUrl -Zone "Default" -DesiredSettings $DefaultSettings + } + } + if ($Intranet) { # Check if specified zone exists @@ -376,17 +472,45 @@ function Set-TargetResource throw $message } - # Test is current config matches desired config + # Test if current config matches desired config + Write-Verbose -Message "Testing Authentication for Intranet zone" $result = Test-ZoneConfiguration -DesiredConfig $Intranet ` -CurrentConfig $CurrentValues.Intranet # If that is the case, set desired config. if ($result -eq $false) { + Write-Verbose -Message "Correcting Authentication for Intranet zone" Set-ZoneConfiguration -WebAppUrl $WebAppUrl -Zone "Intranet" -DesiredConfig $Intranet } } + if ($IntranetSettings) + { + # Check if specified zone exists + if ($null -eq $CurrentValues.IntranetSettings) + { + $message = "Specified zone Intranet does not exist" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + # Test if current config matches desired config + Write-Verbose -Message "Testing Settings for Intranet zone" + $result = Test-ZoneSettings -DesiredSettings $IntranetSettings ` + -CurrentSettings $CurrentValues.IntranetSettings + + # If that is the case, set desired config. + if ($result -eq $false) + { + Write-Verbose -Message "Correcting Settings for Intranet zone" + Set-ZoneSettings -WebAppUrl $WebAppUrl -Zone "Intranet" -DesiredSettings $IntranetSettings + } + } + if ($Internet) { # Check if specified zone exists @@ -400,17 +524,45 @@ function Set-TargetResource throw $message } - # Test is current config matches desired config + # Test if current config matches desired config + Write-Verbose -Message "Testing Authentication for Internet zone" $result = Test-ZoneConfiguration -DesiredConfig $Internet ` -CurrentConfig $CurrentValues.Internet # If that is the case, set desired config. if ($result -eq $false) { + Write-Verbose -Message "Correcting Authentication for Internet zone" Set-ZoneConfiguration -WebAppUrl $WebAppUrl -Zone "Internet" -DesiredConfig $Internet } } + if ($InternetSettings) + { + # Check if specified zone exists + if ($null -eq $CurrentValues.InternetSettings) + { + $message = "Specified zone Internet does not exist" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + # Test if current config matches desired config + Write-Verbose -Message "Testing Settings for Internet zone" + $result = Test-ZoneSettings -DesiredSettings $InternetSettings ` + -CurrentSettings $CurrentValues.InternetSettings + + # If that is the case, set desired config. + if ($result -eq $false) + { + Write-Verbose -Message "Correcting Settings for Internet zone" + Set-ZoneSettings -WebAppUrl $WebAppUrl -Zone "Internet" -DesiredSettings $InternetSettings + } + } + if ($Extranet) { # Check if specified zone exists @@ -424,17 +576,45 @@ function Set-TargetResource throw $message } - # Test is current config matches desired config + # Test if current config matches desired config + Write-Verbose -Message "Testing Authentication for Extranet zone" $result = Test-ZoneConfiguration -DesiredConfig $Extranet ` -CurrentConfig $CurrentValues.Extranet # If that is the case, set desired config. if ($result -eq $false) { + Write-Verbose -Message "Correcting Authentication for Extranet zone" Set-ZoneConfiguration -WebAppUrl $WebAppUrl -Zone "Extranet" -DesiredConfig $Extranet } } + if ($ExtranetSettings) + { + # Check if specified zone exists + if ($null -eq $CurrentValues.ExtranetSettings) + { + $message = "Specified zone Extranet does not exist" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + # Test if current config matches desired config + Write-Verbose -Message "Testing Settings for Extranet zone" + $result = Test-ZoneSettings -DesiredSettings $ExtranetSettings ` + -CurrentSettings $CurrentValues.ExtranetSettings + + # If that is the case, set desired config. + if ($result -eq $false) + { + Write-Verbose -Message "Correcting Settings for Extranet zone" + Set-ZoneSettings -WebAppUrl $WebAppUrl -Zone "Extranet" -DesiredSettings $ExtranetSettings + } + } + if ($Custom) { # Check if specified zone exists @@ -448,16 +628,44 @@ function Set-TargetResource throw $message } - # Test is current config matches desired config + # Test if current config matches desired config + Write-Verbose -Message "Testing Authentication for Custom zone" $result = Test-ZoneConfiguration -DesiredConfig $Custom ` -CurrentConfig $CurrentValues.Custom # If that is the case, set desired config. if ($result -eq $false) { + Write-Verbose -Message "Correcting Authentication for Custom zone" Set-ZoneConfiguration -WebAppUrl $WebAppUrl -Zone "Custom" -DesiredConfig $Custom } } + + if ($CustomSettings) + { + # Check if specified zone exists + if ($null -eq $CurrentValues.CustomSettings) + { + $message = "Specified zone Custom does not exist" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + # Test if current config matches desired config + Write-Verbose -Message "Testing Settings for Custom zone" + $result = Test-ZoneSettings -DesiredSettings $CustomSettings ` + -CurrentSettings $CurrentValues.CustomSettings + + # If that is the case, set desired config. + if ($result -eq $false) + { + Write-Verbose -Message "Correcting Settings for Custom zone" + Set-ZoneSettings -WebAppUrl $WebAppUrl -Zone "Custom" -DesiredSettings $CustomSettings + } + } } function Test-TargetResource @@ -490,6 +698,26 @@ function Test-TargetResource [Microsoft.Management.Infrastructure.CimInstance[]] $Custom, + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $DefaultSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $IntranetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $InternetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ExtranetSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $CustomSettings, + [Parameter()] [System.Management.Automation.PSCredential] $InstallAccount @@ -506,7 +734,12 @@ function Test-TargetResource $null -eq $CurrentValues.Intranet -and ` $null -eq $CurrentValues.Internet -and ` $null -eq $CurrentValues.Extranet -and ` - $null -eq $CurrentValues.Custom) + $null -eq $CurrentValues.Custom -and ` + $null -eq $CurrentValues.DefaultSettings -and ` + $null -eq $CurrentValues.IntranetSettings -and ` + $null -eq $CurrentValues.InternetSettings -and ` + $null -eq $CurrentValues.ExtranetSettings -and ` + $null -eq $CurrentValues.CustomSettings) { Write-Verbose -Message "Test-TargetResource returned false" return $false @@ -514,12 +747,29 @@ function Test-TargetResource if ($Default) { + Write-Verbose -Message "Testing Authentication for Default zone" $result = Test-ZoneConfiguration -DesiredConfig $Default ` -CurrentConfig $CurrentValues.Default ` -ZoneName "Default" if ($result -eq $false) { + Write-Verbose -Message "Parameter Default does not match Desired values" + Write-Verbose -Message "Test-TargetResource returned false" + return $false + } + } + + if ($DefaultSettings) + { + Write-Verbose -Message "Testing Settings for Default zone" + $result = Test-ZoneSettings -DesiredSettings $DefaultSettings ` + -CurrentSettings $CurrentValues.DefaultSettings ` + -ZoneName "Default" + + if ($result -eq $false) + { + Write-Verbose -Message "Parameter DefaultSettings does not match Desired values" Write-Verbose -Message "Test-TargetResource returned false" return $false } @@ -527,6 +777,7 @@ function Test-TargetResource if ($Intranet) { + Write-Verbose -Message "Testing Authentication for Intranet zone" if ($null -eq $CurrentValues.Intranet) { $message = "Specified zone Intranet does not exist" @@ -543,6 +794,32 @@ function Test-TargetResource if ($result -eq $false) { + Write-Verbose -Message "Parameter Intranet does not match Desired values" + Write-Verbose -Message "Test-TargetResource returned false" + return $false + } + } + + if ($IntranetSettings) + { + Write-Verbose -Message "Testing Settings for Intranet zone" + if ($null -eq $CurrentValues.IntranetSettings) + { + $message = "Specified zone Intranet does not exist" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + $result = Test-ZoneSettings -DesiredSettings $IntranetSettings ` + -CurrentSettings $CurrentValues.IntranetSettings ` + -ZoneName "Intranet" + + if ($result -eq $false) + { + Write-Verbose -Message "Parameter IntranetSettings does not match Desired values" Write-Verbose -Message "Test-TargetResource returned false" return $false } @@ -550,6 +827,7 @@ function Test-TargetResource if ($Internet) { + Write-Verbose -Message "Testing Authentication for Internet zone" if ($null -eq $CurrentValues.Internet) { $message = "Specified zone Internet does not exist" @@ -566,6 +844,32 @@ function Test-TargetResource if ($result -eq $false) { + Write-Verbose -Message "Parameter Internet does not match Desired values" + Write-Verbose -Message "Test-TargetResource returned false" + return $false + } + } + + if ($InternetSettings) + { + Write-Verbose -Message "Testing Settings for Internet zone" + if ($null -eq $CurrentValues.InternetSettings) + { + $message = "Specified zone Internet does not exist" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + $result = Test-ZoneSettings -DesiredSettings $InternetSettings ` + -CurrentSettings $CurrentValues.InternetSettings ` + -ZoneName "Internet" + + if ($result -eq $false) + { + Write-Verbose -Message "Parameter InternetSettings does not match Desired values" Write-Verbose -Message "Test-TargetResource returned false" return $false } @@ -573,6 +877,7 @@ function Test-TargetResource if ($Extranet) { + Write-Verbose -Message "Testing Authentication for Extranet zone" if ($null -eq $CurrentValues.Extranet) { $message = "Specified zone Extranet does not exist" @@ -589,6 +894,32 @@ function Test-TargetResource if ($result -eq $false) { + Write-Verbose -Message "Parameter Extranet does not match Desired values" + Write-Verbose -Message "Test-TargetResource returned false" + return $false + } + } + + if ($ExtranetSettings) + { + Write-Verbose -Message "Testing Settings for Extranet zone" + if ($null -eq $CurrentValues.ExtranetSettings) + { + $message = "Specified zone Extranet does not exist" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + } + + $result = Test-ZoneSettings -DesiredSettings $ExtranetSettings ` + -CurrentSettings $CurrentValues.ExtranetSettings ` + -ZoneName "Extranet" + + if ($result -eq $false) + { + Write-Verbose -Message "Parameter ExtranetSettings does not match Desired values" Write-Verbose -Message "Test-TargetResource returned false" return $false } @@ -596,6 +927,7 @@ function Test-TargetResource if ($Custom) { + Write-Verbose -Message "Testing Authentication for Custom zone" if ($null -eq $CurrentValues.Custom) { $message = "Specified zone Custom does not exist" @@ -613,6 +945,33 @@ function Test-TargetResource if ($result -eq $false) { + Write-Verbose -Message "Parameter Custom does not match Desired values" + Write-Verbose -Message "Test-TargetResource returned false" + return $false + } + } + + if ($CustomSettings) + { + Write-Verbose -Message "Testing Settings for Custom zone" + if ($null -eq $CurrentValues.CustomSettings) + { + $message = "Specified zone Custom does not exist" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $MyInvocation.MyCommand.Source + throw $message + Write-Verbose -Message "Test-TargetResource returned false" + } + + $result = Test-ZoneSettings -DesiredSettings $CustomSettings ` + -CurrentSettings $CurrentValues.CustomSettings ` + -ZoneName "Custom" + + if ($result -eq $false) + { + Write-Verbose -Message "Parameter CustomSettings does not match Desired values" Write-Verbose -Message "Test-TargetResource returned false" return $false } @@ -979,6 +1338,79 @@ function Set-ZoneConfiguration() } } +function Set-ZoneSettings() +{ + param ( + [Parameter(Mandatory = $true)] + [System.String] + $WebAppUrl, + + [Parameter(Mandatory = $true)] + [ValidateSet("Default", "Intranet", "Internet", "Extranet", "Custom")] + [System.String] + $Zone, + + [Parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance] + $DesiredSettings + ) + + Invoke-SPDscCommand -Credential $InstallAccount ` + -Arguments $PSBoundParameters ` + -ScriptBlock { + $params = $args[0] + + $wa = Get-SPWebApplication -Identity $params.WebAppUrl + + #Anonymous Authentication: True/False + $prop = $params.DesiredSettings.CimInstanceProperties | Where-Object -FilterScript { + $_.Name -eq "AnonymousAuthentication" + } + if ($null -ne $prop.Value) + { + Write-Verbose -Message ("Updating AnonymousAuthentication to " + ` + "$($params.DesiredSettings.AnonymousAuthentication) for zone $($params.Zone)") + $wa.IisSettings[$params.Zone].AllowAnonymous = $params.DesiredSettings.AnonymousAuthentication + } + + #Custom Sign In Page (Empty string for default, URL for custom) + $prop = $params.DesiredSettings.CimInstanceProperties | Where-Object -FilterScript { + $_.Name -eq "CustomSignInPage" + } + if ($null -ne $prop.Value) + { + Write-Verbose -Message ("Updating CustomSignInPage to " + ` + "$($params.DesiredSettings.CustomSignInPage) for zone $($params.Zone)") + $wa.IisSettings[$params.Zone].ClaimsAuthenticationRedirectionUrl = $params.DesiredSettings.CustomSignInPage + } + + #Require Use Remote Interfaces permission: True/False + $prop = $params.DesiredSettings.CimInstanceProperties | Where-Object -FilterScript { + $_.Name -eq "RequireUseRemoteInterfaces" + } + if ($null -ne $prop.Value) + { + Write-Verbose -Message ("Updating RequireUseRemoteInterfaces to " + ` + "$($params.DesiredSettings.RequireUseRemoteInterfaces) for zone $($params.Zone)") + $wa.IisSettings[$params.Zone].ClientObjectModelRequiresUseRemoteAPIsPermission = $params.DesiredSettings.RequireUseRemoteInterfaces + } + + #Enable Client Integration + $prop = $params.DesiredSettings.CimInstanceProperties | Where-Object -FilterScript { + $_.Name -eq "EnableClientIntegration" + } + if ($null -ne $prop.Value) + { + Write-Verbose -Message ("Updating EnableClientIntegration to " + ` + "$($params.DesiredSettings.EnableClientIntegration) for zone $($params.Zone)") + $wa.IisSettings[$params.Zone].EnableClientIntegration = $params.DesiredSettings.EnableClientIntegration + } + + Write-Verbose -Message "Committing changes to web application" + $wa.Update() + } +} + function Test-ZoneConfiguration() { param ( @@ -1190,3 +1622,111 @@ function Test-ZoneConfiguration() } return $true } + +function Test-ZoneSettings() +{ + param + ( + [Parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance] + $DesiredSettings, + + [Parameter(Mandatory = $true)] + [System.Collections.Hashtable] + $CurrentSettings, + + [Parameter()] + [System.String] + $ZoneName + ) + + # Testing specified configuration against configured values + $parametersNotInDesiredState = @() + $prop = $DesiredSettings.CimInstanceProperties | Where-Object -FilterScript { + $_.Name -eq "AnonymousAuthentication" + } + if ($null -ne $prop.Value) + { + if ($CurrentSettings.AnonymousAuthentication -ne $DesiredSettings.AnonymousAuthentication) + { + Write-Verbose "AnonymousAuthentication does not match" + $parametersNotInDesiredState += "AnonymousAuthentication" + } + } + + $prop = $DesiredSettings.CimInstanceProperties | Where-Object -FilterScript { + $_.Name -eq "CustomSignInPage" + } + if ($null -ne $prop.Value) + { + if ($CurrentSettings.CustomSignInPage -ne $DesiredSettings.CustomSignInPage) + { + Write-Verbose "CustomSignInPage does not match" + $parametersNotInDesiredState += "CustomSignInPage" + } + } + + $prop = $DesiredSettings.CimInstanceProperties | Where-Object -FilterScript { + $_.Name -eq "EnableClientIntegration" + } + if ($null -ne $prop.Value) + { + if ($CurrentSettings.EnableClientIntegration -ne $DesiredSettings.EnableClientIntegration) + { + Write-Verbose "EnableClientIntegration does not match" + $parametersNotInDesiredState += "EnableClientIntegration" + } + } + + $prop = $DesiredSettings.CimInstanceProperties | Where-Object -FilterScript { + $_.Name -eq "RequireUseRemoteInterfaces" + } + if ($null -ne $prop.Value) + { + if ($CurrentSettings.RequireUseRemoteInterfaces -ne $DesiredSettings.RequireUseRemoteInterfaces) + { + Write-Verbose "RequireUseRemoteInterfaces does not match" + $parametersNotInDesiredState += "RequireUseRemoteInterfaces" + } + } + + if ($parametersNotInDesiredState.Count -ne 0) + { + if ($PSBoundParameters.ContainsKey('ZoneName') -eq $true) + { + $source = $MyInvocation.MyCommand.Source + + $EventMessage = "`r`n" + $EventMessage += " `r`n" + + $EventMessage += " `r`n" + foreach ($parameter in $parametersNotInDesiredState) + { + $EventMessage += " `r`n" + $EventMessage += " " + $CurrentSettings.$parameter + "`r`n" + $EventMessage += " `r`n" + } + $EventMessage += " `r`n" + $EventMessage += " `r`n" + $EventMessage += " `r`n" + $EventMessage += " `r`n" + $EventMessage += " $ZoneName`r`n" + $EventMessage += " `r`n" + foreach ($prop in $DesiredSettings.CimInstanceProperties) + { + $EventMessage += " " + $prop.Value + "`r`n" + + } + $EventMessage += " `r`n" + $EventMessage += " `r`n" + $EventMessage += " `r`n" + $EventMessage += "" + + Add-SPDscEvent -Message $EventMessage -EntryType 'Error' -EventID 1 -Source $source + } + + return $false + } + + return $true +} diff --git a/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/MSFT_SPWebAppAuthentication.schema.mof b/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/MSFT_SPWebAppAuthentication.schema.mof index 527fa5b10..cbc888051 100644 --- a/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/MSFT_SPWebAppAuthentication.schema.mof +++ b/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/MSFT_SPWebAppAuthentication.schema.mof @@ -8,6 +8,14 @@ Class MSFT_SPWebAppAuthenticationMode [Write, Description("Name of Membership Provider (only for FBA)")] String MembershipProvider; [Write, Description("Name of the Role Manager (only for FBA)")] String RoleProvider; }; +[ClassVersion("1.0.0.0")] +Class MSFT_SPWebAppZoneSettings +{ + [Write, Description("Use Basic Authentication (only for Windows Authentication)")] Boolean AnonymousAuthentication; + [Write, Description("Specifies the used authentication method")] String CustomSignInPage; + [Write, Description("Use Basic Authentication (only for Windows Authentication)")] Boolean EnableClientIntegration; + [Write, Description("Use Basic Authentication (only for Windows Authentication)")] Boolean RequireUseRemoteInterfaces; +}; [ClassVersion("1.0.0.0"), FriendlyName("SPWebAppAuthentication")] class MSFT_SPWebAppAuthentication : OMI_BaseResource { @@ -17,6 +25,10 @@ class MSFT_SPWebAppAuthentication : OMI_BaseResource [Write, Description("Specifies the authentication for the Internet zone."), EmbeddedInstance("MSFT_SPWebAppAuthenticationMode")] string Internet[]; [Write, Description("Specifies the authentication for the Extranet zone."), EmbeddedInstance("MSFT_SPWebAppAuthenticationMode")] string Extranet[]; [Write, Description("Specifies the authentication for the Custom zone."), EmbeddedInstance("MSFT_SPWebAppAuthenticationMode")] string Custom[]; + [Write, Description("Specifies the zone settings for the Default zone."), EmbeddedInstance("MSFT_SPWebAppZoneSettings")] string DefaultSettings; + [Write, Description("Specifies the zone settings for the Intranet zone."), EmbeddedInstance("MSFT_SPWebAppZoneSettings")] string IntranetSettings; + [Write, Description("Specifies the zone settings for the Internet zone."), EmbeddedInstance("MSFT_SPWebAppZoneSettings")] string InternetSettings; + [Write, Description("Specifies the zone settings for the Extranet zone."), EmbeddedInstance("MSFT_SPWebAppZoneSettings")] string ExtranetSettings; + [Write, Description("Specifies the zone settings for the Custom zone."), EmbeddedInstance("MSFT_SPWebAppZoneSettings")] string CustomSettings; [Write, Description("POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsCredential if using PowerShell 5"), EmbeddedInstance("MSFT_Credential")] string InstallAccount; }; - diff --git a/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/readme.md b/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/readme.md index bf8613768..1ed300f04 100644 --- a/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPWebAppAuthentication/readme.md @@ -3,10 +3,11 @@ **Type:** Distributed **Requires CredSSP:** No -This resource is responsible for configuring the authentication on a web -application within the local SharePoint farm. The resource is able to -configure the five available zones (if they exist) separately and each -zone can have multiple authentication methods configured. +This resource is responsible for configuring the authentication and +authentication settings on a web application within the local SharePoint +farm. The resource is able to configure the five available zones (if +they exist) separately and each zone can have multiple authentication +methods configured. NOTE: This resource cannot be used to convert a Classic web application diff --git a/SharePointDsc/Examples/Resources/SPWebAppAuthentication/6-AuthenticationSettings.ps1 b/SharePointDsc/Examples/Resources/SPWebAppAuthentication/6-AuthenticationSettings.ps1 new file mode 100644 index 000000000..f12b1f072 --- /dev/null +++ b/SharePointDsc/Examples/Resources/SPWebAppAuthentication/6-AuthenticationSettings.ps1 @@ -0,0 +1,68 @@ + +<#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 to configure the authentication settings of a web application + in the local farm to allow anonymous authentication. + +#> + +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + + Import-DscResource -ModuleName SharePointDsc + + node localhost + { + SPWebAppAuthentication ContosoAuthentication + { + WebAppUrl = "http://sharepoint.contoso.com" + DefaultSettings = MSFT_SPWebAppZoneSettings { + AnonymousAuthentication = $true + CustomSignInPage = "/signin" + EnableClientIntegration = $false + RequireUseRemoteInterfaces = $false + } + PsDscRunAsCredential = $SetupAccount + } + } +} diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPWebAppAuthentication.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPWebAppAuthentication.Tests.ps1 index 5d820f72b..011b76b2e 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPWebAppAuthentication.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPWebAppAuthentication.Tests.ps1 @@ -427,7 +427,7 @@ try } } - Context -Name "No zones are specified" -Fixture { + Context -Name "No additional parameters are specified" -Fixture { BeforeAll { $testParams = @{ WebAppUrl = "http://sharepoint.contoso.com" @@ -450,7 +450,7 @@ try } It "Should throw exception in the set method" { - { Set-TargetResource @testParams } | Should -Throw "You have to specify at least one zone." + { Set-TargetResource @testParams } | Should -Throw "You have to specify at least one parameter." } } @@ -1292,6 +1292,700 @@ try } } + Context -Name "Default Zone Settings of Web application is configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + DefaultSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $false + CustomSignInPage = "" + EnableClientIntegration = $true + RequireUseRemoteInterfaces = $true + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + return @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Intranet = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + }, + @{ + DisplayName = "ADFS" + } + ) + } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.DefaultSettings.AnonymousAuthentication | Should -Be $false + $result.DefaultSettings.CustomSignInPage | Should -Be "" + $result.DefaultSettings.EnableClientIntegration | Should -Be $true + $result.DefaultSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Default Zone Settings of Web application is not configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + DefaultSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $true + CustomSignInPage = "/signin" + EnableClientIntegration = $false + RequireUseRemoteInterfaces = $false + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $returnval = @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Intranet = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Update ` + -Value { + $global:SPWebAppUpdateExecuted = $true + } -PassThru -Force + + return $returnval + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + } + ) + } + + Mock -CommandName New-SPAuthenticationProvider -MockWith { return @{ } } + Mock -CommandName Get-SPTrustedIdentityTokenIssuer -MockWith { return @{ } } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.DefaultSettings.AnonymousAuthentication | Should -Be $false + $result.DefaultSettings.CustomSignInPage | Should -Be "" + $result.DefaultSettings.EnableClientIntegration | Should -Be $true + $result.DefaultSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should run the Set-SPWebApplication cmdlet in the set method" { + $global:SPWebAppUpdateExecuted = $false + Set-TargetResource @testParams + $global:SPWebAppUpdateExecuted | Should -Be $true + } + } + + Context -Name "Intranet Zone Settings of Web application is configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + IntranetSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $false + CustomSignInPage = "" + EnableClientIntegration = $true + RequireUseRemoteInterfaces = $true + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + return @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Intranet = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + }, + @{ + DisplayName = "ADFS" + } + ) + } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.IntranetSettings.AnonymousAuthentication | Should -Be $false + $result.IntranetSettings.CustomSignInPage | Should -Be "" + $result.IntranetSettings.EnableClientIntegration | Should -Be $true + $result.IntranetSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Intranet Zone Settings of Web application is not configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + IntranetSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $true + CustomSignInPage = "/signin" + EnableClientIntegration = $false + RequireUseRemoteInterfaces = $false + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $returnval = @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Intranet = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Update ` + -Value { + $global:SPWebAppUpdateExecuted = $true + } -PassThru -Force + + return $returnval + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + } + ) + } + + Mock -CommandName New-SPAuthenticationProvider -MockWith { return @{ } } + Mock -CommandName Get-SPTrustedIdentityTokenIssuer -MockWith { return @{ } } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.IntranetSettings.AnonymousAuthentication | Should -Be $false + $result.IntranetSettings.CustomSignInPage | Should -Be "" + $result.IntranetSettings.EnableClientIntegration | Should -Be $true + $result.IntranetSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should run the Set-SPWebApplication cmdlet in the set method" { + $global:SPWebAppUpdateExecuted = $false + Set-TargetResource @testParams + $global:SPWebAppUpdateExecuted | Should -Be $true + } + } + + Context -Name "Internet Zone Settings of Web application is configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + InternetSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $false + CustomSignInPage = "" + EnableClientIntegration = $true + RequireUseRemoteInterfaces = $true + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + return @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Internet = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + }, + @{ + DisplayName = "ADFS" + } + ) + } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.InternetSettings.AnonymousAuthentication | Should -Be $false + $result.InternetSettings.CustomSignInPage | Should -Be "" + $result.InternetSettings.EnableClientIntegration | Should -Be $true + $result.InternetSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Internet Zone Settings of Web application is not configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + InternetSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $true + CustomSignInPage = "/signin" + EnableClientIntegration = $false + RequireUseRemoteInterfaces = $false + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $returnval = @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Internet = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Update ` + -Value { + $global:SPWebAppUpdateExecuted = $true + } -PassThru -Force + + return $returnval + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + } + ) + } + + Mock -CommandName New-SPAuthenticationProvider -MockWith { return @{ } } + Mock -CommandName Get-SPTrustedIdentityTokenIssuer -MockWith { return @{ } } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.InternetSettings.AnonymousAuthentication | Should -Be $false + $result.InternetSettings.CustomSignInPage | Should -Be "" + $result.InternetSettings.EnableClientIntegration | Should -Be $true + $result.InternetSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should run the Set-SPWebApplication cmdlet in the set method" { + $global:SPWebAppUpdateExecuted = $false + Set-TargetResource @testParams + $global:SPWebAppUpdateExecuted | Should -Be $true + } + } + + Context -Name "Extranet Zone Settings of Web application is configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + ExtranetSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $false + CustomSignInPage = "" + EnableClientIntegration = $true + RequireUseRemoteInterfaces = $true + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + return @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Extranet = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + }, + @{ + DisplayName = "ADFS" + } + ) + } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.ExtranetSettings.AnonymousAuthentication | Should -Be $false + $result.ExtranetSettings.CustomSignInPage | Should -Be "" + $result.ExtranetSettings.EnableClientIntegration | Should -Be $true + $result.ExtranetSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Extranet Zone Settings of Web application is not configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + ExtranetSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $true + CustomSignInPage = "/signin" + EnableClientIntegration = $false + RequireUseRemoteInterfaces = $false + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $returnval = @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Extranet = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Update ` + -Value { + $global:SPWebAppUpdateExecuted = $true + } -PassThru -Force + + return $returnval + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + } + ) + } + + Mock -CommandName New-SPAuthenticationProvider -MockWith { return @{ } } + Mock -CommandName Get-SPTrustedIdentityTokenIssuer -MockWith { return @{ } } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.ExtranetSettings.AnonymousAuthentication | Should -Be $false + $result.ExtranetSettings.CustomSignInPage | Should -Be "" + $result.ExtranetSettings.EnableClientIntegration | Should -Be $true + $result.ExtranetSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should run the Set-SPWebApplication cmdlet in the set method" { + $global:SPWebAppUpdateExecuted = $false + Set-TargetResource @testParams + $global:SPWebAppUpdateExecuted | Should -Be $true + } + } + + Context -Name "Custom Zone Settings of Web application is configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + CustomSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $false + CustomSignInPage = "" + EnableClientIntegration = $true + RequireUseRemoteInterfaces = $true + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + return @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Custom = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + }, + @{ + DisplayName = "ADFS" + } + ) + } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.CustomSettings.AnonymousAuthentication | Should -Be $false + $result.CustomSettings.CustomSignInPage | Should -Be "" + $result.CustomSettings.EnableClientIntegration | Should -Be $true + $result.CustomSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Custom Zone Settings of Web application is not configured as specified" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = "http://sharepoint.contoso.com" + CustomSettings = (New-CimInstance -ClassName MSFT_SPWebAppZoneSettings -Property @{ + AnonymousAuthentication = $true + CustomSignInPage = "/signin" + EnableClientIntegration = $false + RequireUseRemoteInterfaces = $false + } -ClientOnly) + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $returnval = @{ + IisSettings = @{ + Default = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + Custom = @{ + AllowAnonymous = $false + ClaimsAuthenticationRedirectionUrl = "" + EnableClientIntegration = $true + ClientObjectModelRequiresUseRemoteAPIsPermission = $true + } + } + } + $returnval = $returnval | Add-Member -MemberType ScriptMethod ` + -Name Update ` + -Value { + $global:SPWebAppUpdateExecuted = $true + } -PassThru -Force + + return $returnval + } + Mock -CommandName Get-SPAuthenticationProvider -MockWith { + return @( + @{ + DisplayName = "Windows Authentication" + ClaimProviderName = 'AD' + DisableKerberos = $true + }, + @{ + DisplayName = "Forms Authentication" + ClaimProviderName = 'Forms' + RoleProvider = "RoleProvider" + MembershipProvider = "MemberProvider" + } + ) + } + + Mock -CommandName New-SPAuthenticationProvider -MockWith { return @{ } } + Mock -CommandName Get-SPTrustedIdentityTokenIssuer -MockWith { return @{ } } + } + + It "Should return null from the get method" { + $result = Get-TargetResource @testParams + $result.CustomSettings.AnonymousAuthentication | Should -Be $false + $result.CustomSettings.CustomSignInPage | Should -Be "" + $result.CustomSettings.EnableClientIntegration | Should -Be $true + $result.CustomSettings.RequireUseRemoteInterfaces | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should run the Set-SPWebApplication cmdlet in the set method" { + $global:SPWebAppUpdateExecuted = $false + Set-TargetResource @testParams + $global:SPWebAppUpdateExecuted | Should -Be $true + } + } } } } From 62f6787734ef50327fa05a8406d50d5e1ce77cd1 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 8 Jun 2021 13:59:05 +0200 Subject: [PATCH 5/8] Fixed #1318 --- CHANGELOG.md | 6 +- .../DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 | 7 +- .../Modules/SharePointDsc.Farm/SPFarm.psm1 | 76 +++++++++------- .../SharePointDsc.Farm.Tests.ps1 | 87 ++++++++++++------- .../SharePointDsc.SPFarm.Tests.ps1 | 4 +- 5 files changed, 113 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7bf629c0..63ad81c55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,11 +27,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - SharePointDsc - - Fixed code coverage in pipeline. + - Fixed code coverage in pipeline - SPConfigWizard - Fixed issue with executing PSCONFIG remotely. - SPFarm - Fixed issue where developer dashboard could not be configured on first farm setup. + - Fixed issue with PSConfig in SharePoint 2019 when executed remotely + - Corrected issue where the setup account didn't have permissions to create the Lock + table in the TempDB. Updated to use a global temporary table, which users are always + allowed to create ## [4.6.0] - 2021-04-02 diff --git a/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 b/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 index 958f16f26..f0b7f0df7 100644 --- a/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 @@ -1032,8 +1032,8 @@ function Set-TargetResource { Write-Verbose -Message "The database does not exist, so create a new farm" - Write-Verbose -Message "Creating Lock database to prevent two servers creating the same farm" - Add-SPDscConfigDBLock -SQLServer $params.DatabaseServer ` + Write-Verbose -Message "Creating Lock to prevent two servers creating the same farm" + $lockConnection = Add-SPDscConfigDBLock -SQLServer $params.DatabaseServer ` -Database $params.FarmConfigDatabaseName ` @databaseCredentialsParam @@ -1063,9 +1063,10 @@ function Set-TargetResource } finally { - Write-Verbose -Message "Removing Lock database" + Write-Verbose -Message "Removing Lock" Remove-SPDscConfigDBLock -SQLServer $params.DatabaseServer ` -Database $params.FarmConfigDatabaseName ` + -Connection $lockConnection ` @databaseCredentialsParam } } diff --git a/SharePointDsc/Modules/SharePointDsc.Farm/SPFarm.psm1 b/SharePointDsc/Modules/SharePointDsc.Farm/SPFarm.psm1 index 0c97dfd37..1753fd949 100644 --- a/SharePointDsc/Modules/SharePointDsc.Farm/SPFarm.psm1 +++ b/SharePointDsc/Modules/SharePointDsc.Farm/SPFarm.psm1 @@ -89,7 +89,10 @@ function Get-SPDscConfigDBStatus } $connection.ChangeDatabase('TempDB') - $command.CommandText = "SELECT COUNT([name]) FROM sys.tables WHERE [name] = 'SPDscLock'" + + # Added $Database just in case multiple farms are added at once. + Write-Verbose -Message "Testing lock for $Database" + $command.CommandText = "SELECT COUNT([name]) FROM sys.tables WHERE [name] = '##SPDscLock$Database'" $lockExists = ($command.ExecuteScalar() -eq 1) return @{ @@ -204,7 +207,7 @@ The name of the database to validate as the configuration database .EXAMPLE -Add-SPDscConfigDBLock -SQLServer sql.contoso.com -Database SP_Config +$lockConnection = Add-SPDscConfigDBLock -SQLServer sql.contoso.com -Database SP_Config #> function Add-SPDscConfigDBLock @@ -224,7 +227,7 @@ function Add-SPDscConfigDBLock $DatabaseCredentials ) - Write-Verbose -Message "Creating lock database $($Database)_Lock" + Write-Verbose -Message "Creating lock for database $Database" $connection = New-Object -TypeName "System.Data.SqlClient.SqlConnection" # If we specified SQL credentials then try to use them @@ -245,29 +248,28 @@ function Add-SPDscConfigDBLock $connection.Open() $command.Connection = $connection - $command.CommandText = "CREATE TABLE SPDscLock (Locked BIT)" + # Added $Database just in case multiple farms are added at once. + $command.CommandText = "CREATE TABLE ##SPDscLock$Database (Locked BIT)" $null = $command.ExecuteNonQuery() } finally { - if ($connection.State -eq "Open") - { - $connection.Close() - $connection.Dispose() - } + # cannot close the connection here, that would destroy the ##lock table } + + return $connection } <# .SYNOPSIS -Remove-SPDscConfigDBLock is used to create a lock to tell other servers that the -config DB is currently provisioning +Remove-SPDscConfigDBLock will remove the lock created by the +Add-SPDscConfigDBLock command. .DESCRIPTION -Remove-SPDscConfigDBLock will cremove the lock database created by the +Remove-SPDscConfigDBLock will remove the lock created by the Add-SPDscConfigDBLock command. .PARAMETER SQLServer @@ -280,7 +282,7 @@ The name of the database to validate as the configuration database .EXAMPLE -Remove-SPDscConfigDBLock -SQLServer sql.contoso.com -Database SP_Config +Remove-SPDscConfigDBLock -SQLServer sql.contoso.com -Database SP_Config -Connection $lockConnection #> function Remove-SPDscConfigDBLock @@ -297,39 +299,55 @@ function Remove-SPDscConfigDBLock [Parameter()] [System.Management.Automation.PSCredential] - $DatabaseCredentials + $DatabaseCredentials, + + [Parameter(Mandatory = $true)] + [System.Data.SqlClient.SqlConnection] + $Connection ) - Write-Verbose -Message "Removing lock database $($Database)_Lock" + Write-Verbose -Message "Removing lock for database $Database" - $connection = New-Object -TypeName "System.Data.SqlClient.SqlConnection" - # If we specified SQL credentials then try to use them - if ($PSBoundParameters.ContainsKey("DatabaseCredentials")) + if ($Connection.State -ne "Open") { - $marshal = [Runtime.InteropServices.Marshal] - $dbCredentialsPlainPassword = $marshal::PtrToStringAuto($marshal::SecureStringToBSTR($DatabaseCredentials.Password)) - $connection.ConnectionString = "Server=$SQLServer;Integrated Security=False;User ID=$($DatabaseCredentials.Username);Password=$dbCredentialsPlainPassword;Database=Master" + $conn = New-Object -TypeName "System.Data.SqlClient.SqlConnection" + + # If we specified SQL credentials then try to use them + if ($PSBoundParameters.ContainsKey("DatabaseCredentials")) + { + $marshal = [Runtime.InteropServices.Marshal] + $dbCredentialsPlainPassword = $marshal::PtrToStringAuto($marshal::SecureStringToBSTR($DatabaseCredentials.Password)) + $conn.ConnectionString = "Server=$SQLServer;Integrated Security=False;User ID=$($DatabaseCredentials.Username);Password=$dbCredentialsPlainPassword;Database=Master" + } + else # Just use Windows integrated auth + { + $conn.ConnectionString = "Server=$SQLServer;Integrated Security=SSPI;Database=TempDB" + } } - else # Just use Windows integrated auth + else { - $connection.ConnectionString = "Server=$SQLServer;Integrated Security=SSPI;Database=TempDB" + $conn = $Connection } + $command = New-Object -TypeName "System.Data.SqlClient.SqlCommand" + $command.Connection = $conn try { - $connection.Open() - $command.Connection = $connection + if ($conn.State -ne "Open") + { + $conn.Open() + } - $command.CommandText = "DROP TABLE [SPDscLock]" + $command.CommandText = "DROP TABLE [##SPDscLock$Database]" $null = $command.ExecuteNonQuery() } finally { - if ($connection.State -eq "Open") + if ($conn.State -eq "Open") { - $connection.Close() - $connection.Dispose() + $conn.Close() + $conn.Dispose() } } } diff --git a/tests/Unit/SharePointDsc/SharePointDsc.Farm.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.Farm.Tests.ps1 index e40334deb..14a41dee2 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.Farm.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.Farm.Tests.ps1 @@ -15,10 +15,12 @@ $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 + { + Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch - { $false + { + $false }) }).BaseName @@ -110,25 +112,30 @@ try } $returnval = $returnval | Add-Member -MemberType ScriptMethod ` - -name ExecuteScalar ` + -Name ExecuteScalar ` -Value { $global:RunQuery++ switch ($global:RunQuery) { 1 # ConfigDB exists - { return 1 + { + return 1 } 2 # Check permissions - { return "0" + { + return "0" } 3 # Check permissions - { return "1" + { + return "1" } 4 # Database empty - { return 20 + { + return 20 } 5 # Locked - { return 0 + { + return 0 } } } -PassThru -Force @@ -153,25 +160,30 @@ try } $returnval = $returnval | Add-Member -MemberType ScriptMethod ` - -name ExecuteScalar ` + -Name ExecuteScalar ` -Value { $global:RunQuery++ switch ($global:RunQuery) { 1 # ConfigDB exists - { return 1 + { + return 1 } 2 # Check permissions - { return "1" + { + return "1" } 3 # Check permissions - { return "1" + { + return "1" } 4 # Database empty - { return 20 + { + return 20 } 5 # Locked - { return 0 + { + return 0 } } } -PassThru -Force @@ -196,25 +208,30 @@ try } $returnval = $returnval | Add-Member -MemberType ScriptMethod ` - -name ExecuteScalar ` + -Name ExecuteScalar ` -Value { $global:RunQuery++ switch ($global:RunQuery) { 1 # ConfigDB exists - { return 1 + { + return 1 } 2 # Check permissions - { return "1" + { + return "1" } 3 # Check permissions - { return "1" + { + return "1" } 4 # Database empty - { return 0 + { + return 0 } 5 # Locked - { return 0 + { + return 0 } } } -PassThru -Force @@ -239,22 +256,26 @@ try } $returnval = $returnval | Add-Member -MemberType ScriptMethod ` - -name ExecuteScalar ` + -Name ExecuteScalar ` -Value { $global:RunQuery++ switch ($global:RunQuery) { 1 # ConfigDB exists - { return 0 + { + return 0 } 2 # Check permissions - { return "1" + { + return "1" } 3 # Check permissions - { return "1" + { + return "1" } 4 # Locked - { return 0 + { + return 0 } } } -PassThru -Force @@ -309,7 +330,7 @@ try } $returnval = $returnval | Add-Member -MemberType ScriptMethod ` - -name ExecuteScalar ` + -Name ExecuteScalar ` -Value { return 1 } -PassThru -Force @@ -330,7 +351,7 @@ try } $returnval = $returnval | Add-Member -MemberType ScriptMethod ` - -name ExecuteScalar ` + -Name ExecuteScalar ` -Value { return 0 } -PassThru -Force @@ -381,7 +402,7 @@ try } $returnval = $returnval | Add-Member -MemberType ScriptMethod ` - -name ExecuteNonQuery ` + -Name ExecuteNonQuery ` -Value { $global:ExecutedQuery = $true } -PassThru -Force @@ -399,6 +420,8 @@ try Context -Name "Validate Remove-SPDscConfigDBLock" -Fixture { BeforeAll { + $conn = New-Object -TypeName "System.Data.SqlClient.SqlConnection" + Mock -CommandName New-Object -MockWith { $returnval = @{ ConnectionString = '' @@ -424,16 +447,14 @@ try } -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 ` + -Name ExecuteNonQuery ` -Value { $global:ExecutedQuery = $true } -PassThru -Force @@ -442,9 +463,11 @@ try } -ParameterFilter { $TypeName -eq "System.Data.SqlClient.SqlCommand" } + } + It "Should run query to create TempDB Lock table" { $global:ExecutedQuery = $false - $result = Remove-SPDscConfigDBLock -SQLServer 'sql01' -Database 'SP_Config' + $result = Remove-SPDscConfigDBLock -SQLServer 'sql01' -Database 'SP_Config' -Connection $conn $global:ExecutedQuery | Should -Be $true } } diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 index 62f1f0871..414383e6b 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPFarm.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 $mockPassword = ConvertTo-SecureString -String 'password' -AsPlainText -Force @@ -73,7 +73,7 @@ try } # Mocks for all contexts - Mock -CommandName Add-SPDscConfigDBLock -MockWith { } + Mock -CommandName Add-SPDscConfigDBLock -MockWith { return (New-Object -TypeName "System.Data.SqlClient.SqlConnection") } Mock -CommandName Remove-SPDscConfigDBLock -MockWith { } Mock -CommandName New-SPConfigurationDatabase -MockWith { } Mock -CommandName Connect-SPConfigurationDatabase -MockWith { } From c6b0fac734c5a48f4ed82a26065227ad55b68736 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 8 Jun 2021 14:38:37 +0200 Subject: [PATCH 6/8] Corrected tabs --- .../SharePointDsc.Search/SPSearchServiceApp.psm1 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SharePointDsc/Modules/SharePointDsc.Search/SPSearchServiceApp.psm1 b/SharePointDsc/Modules/SharePointDsc.Search/SPSearchServiceApp.psm1 index 5b2eb49e6..11b656d7b 100644 --- a/SharePointDsc/Modules/SharePointDsc.Search/SPSearchServiceApp.psm1 +++ b/SharePointDsc/Modules/SharePointDsc.Search/SPSearchServiceApp.psm1 @@ -139,14 +139,14 @@ IF NOT EXISTS(SELECT principal_id FROM sys.database_principals WHERE name = @New END IF NOT EXISTS - (SELECT DP1.name AS DatabaseRoleName, - isnull (DP2.name, 'No members') AS DatabaseUserName - FROM sys.database_role_members AS DRM - RIGHT OUTER JOIN sys.database_principals AS DP1 - ON DRM.role_principal_id = DP1.principal_id - LEFT OUTER JOIN sys.database_principals AS DP2 - ON DRM.member_principal_id = DP2.principal_id - WHERE DP1.type = 'R' AND DP2.name = @NewUserName AND DP1.name = 'db_owner') + (SELECT DP1.name AS DatabaseRoleName, + isnull (DP2.name, 'No members') AS DatabaseUserName + FROM sys.database_role_members AS DRM + RIGHT OUTER JOIN sys.database_principals AS DP1 + ON DRM.role_principal_id = DP1.principal_id + LEFT OUTER JOIN sys.database_principals AS DP2 + ON DRM.member_principal_id = DP2.principal_id + WHERE DP1.type = 'R' AND DP2.name = @NewUserName AND DP1.name = 'db_owner') BEGIN DECLARE @roleSQL as varchar(500); SET @roleSQL = 'ALTER ROLE db_owner ADD MEMBER [' + @NewUserName + ']'; From f6dbc53a513c781c59a756bd4620e69d6caae8c4 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 8 Jun 2021 22:12:32 +0200 Subject: [PATCH 7/8] Fix unit tests --- ...SharePointDsc.SPSearchServiceApp.Tests.ps1 | 4 +-- tests/Unit/UnitTestHelper.psm1 | 28 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 index 8d44f6626..0b050ba58 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 @@ -53,8 +53,8 @@ try Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope # Initialize tests - Import-Module -Name (Join-Path -Path $PSScriptRoot ` - -ChildPath "..\..\..\output\SharePointDsc\$ModuleVersion\Modules\SharePointDsc.Search\SPSearchServiceApp.psm1" ` + Import-Module -Name (Join-Path -Path (Get-Module SharePointDsc -ListAvailable).ModuleBase ` + -ChildPath "Modules\SharePointDsc.Search\SPSearchServiceApp.psm1" ` -Resolve) $getTypeFullName = "Microsoft.Office.Server.Search.Administration.SearchServiceApplication" diff --git a/tests/Unit/UnitTestHelper.psm1 b/tests/Unit/UnitTestHelper.psm1 index 258e19dcc..7a003a314 100644 --- a/tests/Unit/UnitTestHelper.psm1 +++ b/tests/Unit/UnitTestHelper.psm1 @@ -37,7 +37,7 @@ function New-SPDscUnitTestHelper $describeHeader += "[SP Build: $spBuild] " $repoRoot = Join-Path -Path $PSScriptRoot -ChildPath "..\..\" -Resolve - $moduleRoot = Join-Path -Path $repoRoot -ChildPath "output\SharePointDsc\$ModuleVersion" + $moduleRoot = (Get-Module SharePointDsc -ListAvailable).ModuleBase $initScript = @" Set-StrictMode -Version 1 @@ -142,21 +142,21 @@ function Write-SPDscStubFile $SPStubContent = ((Get-Command | Where-Object -FilterScript { $_.Source -eq "Microsoft.SharePoint.PowerShell" } ) | ForEach-Object -Process { - $signature = $null - $command = $_ - $metadata = New-Object -TypeName System.Management.Automation.CommandMetaData ` - -ArgumentList $command - $definition = [System.Management.Automation.ProxyCommand]::Create($metadata) - foreach ($line in $definition -split "`n") - { - if ($line.Trim() -eq 'begin') + $signature = $null + $command = $_ + $metadata = New-Object -TypeName System.Management.Automation.CommandMetaData ` + -ArgumentList $command + $definition = [System.Management.Automation.ProxyCommand]::Create($metadata) + foreach ($line in $definition -split "`n") { - break + if ($line.Trim() -eq 'begin') + { + break + } + $signature += $line } - $signature += $line - } - "function $($command.Name) { `n $signature `n } `n" - }) | Out-String + "function $($command.Name) { `n $signature `n } `n" + }) | Out-String foreach ($line in $SPStubContent.Split([Environment]::NewLine)) { From 15fdac56d314983801d0ecc26453e9a3f84ce914 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 9 Jun 2021 19:18:07 +0200 Subject: [PATCH 8/8] Incorporated review comments --- .../MSFT_SPSearchServiceApp.psm1 | 39 +++++++++---------- ...SharePointDsc.SPSearchServiceApp.Tests.ps1 | 2 +- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 index 4c79d433f..b32237e40 100644 --- a/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 @@ -149,52 +149,49 @@ function Get-TargetResource } Write-Verbose -Message "Checking Farm account permissions" - $correctFarmAccountPermissions = $true + $farmAccountPermissionsNeedCorrecting = $false $farmAccount = (Get-SPFarm).DefaultServiceAccount.Name $dbServer = $serviceApp.SearchAdminDatabase.NormalizedDataSource Write-Verbose -Message "Checking Admin Database" $adminDB = $serviceApp.SearchAdminDatabase.Name - if ($correctFarmAccountPermissions -eq $true) - { - $correctFarmAccountPermissions = Confirm-UserIsDBOwner -SQLServer $dbServer ` + $farmAccountPermissionsNeedCorrecting = (Confirm-UserIsDBOwner -SQLServer $dbServer ` -Database $adminDB ` - -User $farmAccount - } + -User $farmAccount) -eq $false Write-Verbose -Message "Checking Analytics reporting Database" $analyticsDB = "$($adminDB)_AnalyticsReportingStore" - if ($correctFarmAccountPermissions -eq $true) + if ($farmAccountPermissionsNeedCorrecting -eq $false) { - $correctFarmAccountPermissions = Confirm-UserIsDBOwner -SQLServer $dbServer ` - -Database $analyticsDB ` - -User $farmAccount + $farmAccountPermissionsNeedCorrecting = (Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $analyticsDB ` + -User $farmAccount) -eq $false } Write-Verbose -Message "Checking Crawl Database(s)" - if ($correctFarmAccountPermissions -eq $true) + if ($farmAccountPermissionsNeedCorrecting -eq $false) { foreach ($database in (Get-SPEnterpriseSearchCrawlDatabase -SearchApplication $serviceApp)) { $crawlDB = $database.Database.Name $dbServer = $database.Database.NormalizedDataSource - $correctFarmAccountPermissions = Confirm-UserIsDBOwner -SQLServer $dbServer ` - -Database $crawlDB ` - -User $farmAccount + $farmAccountPermissionsNeedCorrecting = (Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $crawlDB ` + -User $farmAccount) -eq $false } } Write-Verbose -Message "Checking Links Database(s)" - if ($correctFarmAccountPermissions -eq $true) + if ($farmAccountPermissionsNeedCorrecting -eq $false) { foreach ($database in (Get-SPEnterpriseSearchLinksDatabase -SearchApplication $serviceApp)) { $linksDB = $database.Database.Name $dbServer = $database.Database.NormalizedDataSource - $correctFarmAccountPermissions = Confirm-UserIsDBOwner -SQLServer $dbServer ` - -Database $linksDB ` - -User $farmAccount + $farmAccountPermissionsNeedCorrecting = (Confirm-UserIsDBOwner -SQLServer $dbServer ` + -Database $linksDB ` + -User $farmAccount) -eq $false } } @@ -209,7 +206,7 @@ function Get-TargetResource DefaultContentAccessAccount = $defaultAccount CloudIndex = $cloudIndex AlertsEnabled = $serviceApp.AlertsEnabled - FixFarmAccountPermissions = $correctFarmAccountPermissions + FixFarmAccountPermissions = $farmAccountPermissionsNeedCorrecting } return $returnVal } @@ -510,7 +507,7 @@ function Set-TargetResource # Only check and correct when Ensure=Present, FixFarmAccountPermissions=True and the permissions are incorrect if ($Ensure -eq "Present" -and ` $FixFarmAccountPermissions -eq $true -and ` - $result.FixFarmAccountPermissions -eq $false) + $result.FixFarmAccountPermissions -eq $true) { Write-Verbose -Message "Fixing database permissions for Search Service Application $Name" Invoke-SPDscCommand -Credential $InstallAccount ` @@ -708,7 +705,7 @@ function Test-TargetResource if ($FixFarmAccountPermissions -eq $true) { - if ($CurrentValues.FixFarmAccountPermissions -eq $false) + if ($CurrentValues.FixFarmAccountPermissions -eq $true) { $message = ("FixFarmAccountPermissions is set to True, but the Search databases " + ` "do not have the correct permissions") diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 index 0b050ba58..afeaa68a7 100644 --- a/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 @@ -332,7 +332,7 @@ try } It "Should return FixFarmAccountPermissions=False from the get method" { - (Get-TargetResource @testParams).FixFarmAccountPermissions | Should -Be $false + (Get-TargetResource @testParams).FixFarmAccountPermissions | Should -Be $true Assert-MockCalled Confirm-UserIsDBOwner }