From eacaf4f57df1737280730da8c1f378d3cec11045 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 25 Jul 2018 09:54:34 +0200 Subject: [PATCH 01/23] Updated version number to 2.5 in appveyor.yml file --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 112cc3c7d..a2c4d7949 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.4.0.{build} +version: 2.5.0.{build} install: - git clone https://github.com/PowerShell/DscResource.Tests From 1977b79580fa59c12a50326ba88d8914490e0de9 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 17 Aug 2018 09:20:15 +0200 Subject: [PATCH 02/23] Fixed issues #834, #845, #848 and #849 --- CHANGELOG.md | 11 ++++++++ .../MSFT_SPLogLevel/MSFT_SPLogLevel.psm1 | 8 +++--- .../MSFT_SPLogLevel.schema.mof | 2 +- .../MSFT_SPSearchTopology.psm1 | 15 ++++++++++- ...stedIdentityTokenIssuerProviderRealms.psm1 | 25 +++++++++++++++---- .../SharePointDsc.SPLogLevel.Tests.ps1 | 2 +- ...dentityTokenIssuerProviderRealms.Tests.ps1 | 2 +- 7 files changed, 52 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9bd40ed0..ae1cb1d7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Change log for SharePointDsc +## Unreleased + +* SPLogLevel + * Added High as TraceLevel, which was not included yet +* SPSearchTopology + * Fixed issue where Get method threw an error when the specified service + application didn't exist yet + * Fixed issue where the resource would fail is the FQDN was specified +* SPTrustedIdentityTokenIssuerProviderRealm + * Fixed issue where Get method threw an error when the realm didn't exist yet + ## 2.4 * SPCacheAccounts diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.psm1 index c4012e190..ca2d41df1 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.psm1 @@ -47,9 +47,9 @@ function Get-TargetResource } } - if ($null -ne $DesiredSetting.TraceLevel -and @("None","Unexpected","Monitorable","Medium","Verbose","VerboseEx","Default") -notcontains $DesiredSetting.TraceLevel) + if ($null -ne $DesiredSetting.TraceLevel -and @("None","Unexpected","Monitorable","High","Medium","Verbose","VerboseEx","Default") -notcontains $DesiredSetting.TraceLevel) { - Write-Verbose -Message "TraceLevel $($DesiredSetting.TraceLevel) is not valid, must specify exactly one of None,Unexpected,Monitorable,Medium,Verbose,VerboseEx, or Default" + Write-Verbose -Message "TraceLevel $($DesiredSetting.TraceLevel) is not valid, must specify exactly one of None,Unexpected,Monitorable,High,Medium,Verbose,VerboseEx, or Default" return @{ Name = $Name SPLogLevelSetting = $null @@ -194,9 +194,9 @@ function Set-TargetResource throw "TraceLevel and / or EventLevel must be provided for each Area" } - if ($null -ne $DesiredSetting.TraceLevel -and @("None","Unexpected","Monitorable","Medium","Verbose","VerboseEx","Default") -notcontains $DesiredSetting.TraceLevel) + if ($null -ne $DesiredSetting.TraceLevel -and @("None","Unexpected","Monitorable","High","Medium","Verbose","VerboseEx","Default") -notcontains $DesiredSetting.TraceLevel) { - throw "TraceLevel $($DesiredSetting.TraceLevel) is not valid, must specify exactly one of None,Unexpected,Monitorable,Medium,Verbose,VerboseEx, or Default" + throw "TraceLevel $($DesiredSetting.TraceLevel) is not valid, must specify exactly one of None,Unexpected,Monitorable,High,Medium,Verbose,VerboseEx, or Default" } if ($null -ne $DesiredSetting.EventLevel -and @("None","ErrorCritical","Error","Warning","Information","Verbose","Default") -notcontains $DesiredSetting.EventLevel) diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof b/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof index 91a7113bd..8c86f9797 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof @@ -3,7 +3,7 @@ Class MSFT_SPLogLevelItem { [Key, Description("Log Item Area")] String Area; [Key, Description("Log Item Name")] String Name; - [Write, Description("Minimum severity to capture in the trace logs "), ValueMap{"None","Unexpected","Monitorable","Medium","Verbose","VerboseEx","Default"}, Values{"None","Unexpected","Monitorable","Medium","Verbose","VerboseEx","Default"}] String TraceLevel; + [Write, Description("Minimum severity to capture in the trace logs "), ValueMap{"None","Unexpected","Monitorable","High","Medium","Verbose","VerboseEx","Default"}, Values{"None","Unexpected","Monitorable","Medium","Verbose","VerboseEx","Default"}] String TraceLevel; [Write, Description("Minimum severity to capture in the event logs"), ValueMap{"None","ErrorCritical","Error","Warning","Information","Verbose","Default"}, Values{"None","ErrorCritical","Error","Warning","Information","Verbose","Default"}] String EventLevel; }; diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 index 355ab2373..a899a9d34 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 @@ -49,7 +49,8 @@ function Get-TargetResource $params = $args[0] $ConfirmPreference = 'None' - $ssa = Get-SPEnterpriseSearchServiceApplication -Identity $params.ServiceAppName + $ssa = Get-SPEnterpriseSearchServiceApplication -Identity $params.ServiceAppName ` + -ErrorAction SilentlyContinue if ($null -eq $ssa) { @@ -248,6 +249,12 @@ function Set-TargetResource # Ensure the search service instance is running on all servers foreach($searchServer in $AllSearchServers) { + if($searchServer -like '*.*') + { + Write-Verbose -Message "Server name specified in FQDN, extracting just server name." + $searchServer = $searchServer.Split('.')[0] + } + $searchService = Get-SPEnterpriseSearchServiceInstance -Identity $searchServer ` -ErrorAction SilentlyContinue if ($null -eq $searchService) @@ -295,6 +302,12 @@ function Set-TargetResource $AllSearchServiceInstances = @{} foreach ($server in $AllSearchServers) { + if($server -like '*.*') + { + Write-Verbose -Message "Server name specified in FQDN, extracting just server name." + $server = $server.Split('.')[0] + } + $serverName = $server $serviceToAdd = Get-SPEnterpriseSearchServiceInstance -Identity $server ` -ErrorAction SilentlyContinue diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPTrustedIdentityTokenIssuerProviderRealms/MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPTrustedIdentityTokenIssuerProviderRealms/MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 index e32ba1696..43d61cd12 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPTrustedIdentityTokenIssuerProviderRealms/MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPTrustedIdentityTokenIssuerProviderRealms/MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 @@ -79,7 +79,8 @@ function Get-TargetResource if ($null -eq $spTrust) { - throw ("SPTrustedIdentityTokenIssuer '$($params.IssuerName)' not found") + Write-Verbose -Message "SPTrustedIdentityTokenIssuer '$($params.IssuerName)' not found" + return $null } if ($spTrust.ProviderRealms.Count -gt 0) @@ -91,9 +92,23 @@ function Get-TargetResource return $currentRealms } - $currentStatus = Get-ProviderRealmsStatus -currentRealms $result -desiredRealms $paramRealms ` - -includeRealms $includeRealms -excludeRealms $excludeRealms ` - -Ensure $Ensure + if ($null -eq $result) + { + return @{ + IssuerName = $IssuerName + ProviderRealms = $null + ProviderRealmsToInclude = $null + ProviderRealmsToExclude = $null + CurrentRealms = $null + RealmsToAdd = $null + Ensure = $null + } + } + $currentStatus = Get-ProviderRealmsStatus -currentRealms $result ` + -desiredRealms $paramRealms ` + -includeRealms $includeRealms ` + -excludeRealms $excludeRealms ` + -Ensure $Ensure return @{ IssuerName = $IssuerName @@ -154,7 +169,7 @@ function Set-TargetResource if ($null -eq $trust) { - throw ("SPTrustedIdentityTokenIssuer '$($params.IssuerName)' not found") + throw ("SPTrustedIdentityTokenIssuer '$($params.IssuerName)' not found") } $trust.ProviderRealms.Clear() diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPLogLevel.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPLogLevel.Tests.ps1 index 92e007ffa..fc26ff582 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPLogLevel.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPLogLevel.Tests.ps1 @@ -121,7 +121,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should throw an error from the set method" { - { Set-TargetResource @testParams } | Should throw "TraceLevel detailed is not valid, must specify exactly one of None,Unexpected,Monitorable,Medium,Verbose,VerboseEx, or Default" + { Set-TargetResource @testParams } | Should throw "TraceLevel detailed is not valid, must specify exactly one of None,Unexpected,Monitorable,High,Medium,Verbose,VerboseEx, or Default" } } diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 index e32dbc601..846b497cf 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 @@ -34,7 +34,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Mock -CommandName Get-SPTrustedIdentityTokenIssuer -MockWith { return $null } It "Should get Error message SPTrustedIdentityTokenIssuer 'Contoso' not found" { - { Get-TargetResource @testParams } | Should -Throw "SPTrustedIdentityTokenIssuer 'Contoso' not found" + (Get-TargetResource @testParams).Ensure | Should Be $null } } From f211564d7d6d11a1135c12d87ec40b7c660820a1 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 17 Aug 2018 17:22:10 +0200 Subject: [PATCH 03/23] Fixed issue #846 and improvements to SPSearchServiceApp and SPRemoteFarmTrust --- CHANGELOG.md | 7 + .../MSFT_SPDiagnosticsProvider.psm1 | 12 +- .../MSFT_SPRemoteFarmTrust.psm1 | 26 +- .../MSFT_SPRemoteFarmTrust/readme.md | 3 +- .../MSFT_SPSearchServiceApp.psm1 | 14 + ...rePointDsc.SPDiagnosticsProvider.Tests.ps1 | 3 + ...SharePointDsc.SPSearchServiceApp.Tests.ps1 | 319 +++++++++--------- 7 files changed, 216 insertions(+), 168 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae1cb1d7f..f1c74efb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,15 @@ ## Unreleased +* SPDiagnosticsProvider + * Fixed issue where enabling providers did not work * SPLogLevel * Added High as TraceLevel, which was not included yet +* SPSearchServiceApp + * Updated Set method to check if service application pool exists. Resource + will throw an error if it does not exist +* SPRemoteFarmTrust + * Updated readme.md file to add a link that was lost during earlier updates * SPSearchTopology * Fixed issue where Get method threw an error when the specified service application didn't exist yet diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPDiagnosticsProvider/MSFT_SPDiagnosticsProvider.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPDiagnosticsProvider/MSFT_SPDiagnosticsProvider.psm1 index 74dd11706..e2300cc79 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPDiagnosticsProvider/MSFT_SPDiagnosticsProvider.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPDiagnosticsProvider/MSFT_SPDiagnosticsProvider.psm1 @@ -112,22 +112,26 @@ function Set-TargetResource throw "The specified Diagnostic Provider {" + $params.Name + "} could not be found." } + $newParams = @{ + Identity = $params.Name + } + if($params.ContainsKey("Retention")) { - $diagnosticProvider.Retention = $params.Retention + $newParams.DaysRetained = $params.Retention } if($params.ContainsKey("MaxTotalSizeInBytes")) { - $diagnosticProvider.MaxTotalSizeInBytes = $params.MaxTotalSizeInBytes + $newParams.MaxTotalSizeInBytes = $params.MaxTotalSizeInBytes } if($params.ContainsKey("Enabled")) { - $diagnosticProvider.Enabled = $params.Enabled + $newParams.Enable = $params.Enabled } - $diagnosticProvider.Update() + Set-SPDiagnosticsProvider @newParams } } diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPRemoteFarmTrust/MSFT_SPRemoteFarmTrust.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPRemoteFarmTrust/MSFT_SPRemoteFarmTrust.psm1 index 1f651f929..091c66a62 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPRemoteFarmTrust/MSFT_SPRemoteFarmTrust.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPRemoteFarmTrust/MSFT_SPRemoteFarmTrust.psm1 @@ -15,8 +15,8 @@ function Get-TargetResource() [System.String] $LocalWebAppUrl, - [Parameter()] - [ValidateSet("Present","Absent")] + [Parameter()] + [ValidateSet("Present","Absent")] [System.String] $Ensure = "Present", [Parameter()] @@ -63,7 +63,7 @@ function Get-TargetResource() $returnValue.Ensure = "Present" return $returnValue } - return $result + return $result } function Set-TargetResource() @@ -82,8 +82,8 @@ function Set-TargetResource() [System.String] $LocalWebAppUrl, - [Parameter()] - [ValidateSet("Present","Absent")] + [Parameter()] + [ValidateSet("Present","Absent")] [System.String] $Ensure = "Present", [Parameter()] @@ -110,7 +110,8 @@ function Set-TargetResource() $endpoint = "$remoteWebApp/_layouts/15/metadata/json/1" $issuer = New-SPTrustedSecurityTokenIssuer -Name $params.Name ` -IsTrustBroker:$false ` - -MetadataEndpoint $endpoint + -MetadataEndpoint $endpoint ` + -Confirm:$false } $rootAuthority = Get-SPTrustedRootAuthority -Identity $params.Name ` @@ -119,7 +120,8 @@ function Set-TargetResource() { $endpoint = "$remoteWebApp/_layouts/15/metadata/json/1/rootcertificate" New-SPTrustedRootAuthority -Name $params.Name ` - -MetadataEndPoint $endpoint + -MetadataEndPoint $endpoint ` + -Confirm:$false } $realm = $issuer.NameId.Split("@") $site = Get-SPSite -Identity $params.LocalWebAppUrl @@ -129,7 +131,7 @@ function Set-TargetResource() if ($realm[1] -ne $currentRealm) { - Set-SPAuthenticationRealm -ServiceContext $serviceContext -Realm $realm[1] + Set-SPAuthenticationRealm -ServiceContext $serviceContext -Realm $realm[1] } $appPrincipal = Get-SPAppPrincipal -Site $params.LocalWebAppUrl ` @@ -141,7 +143,7 @@ function Set-TargetResource() -Right FullControl } } - + if ($Ensure -eq "Absent") { Write-Verbose -Message "Removing remote farm trust '$Name'" @@ -163,7 +165,7 @@ function Set-TargetResource() -Scope SiteCollection ` -Confirm:$false } - + Get-SPTrustedRootAuthority -Identity $params.Name ` -ErrorAction SilentlyContinue ` | Remove-SPTrustedRootAuthority -Confirm:$false @@ -192,8 +194,8 @@ function Test-TargetResource() [System.String] $LocalWebAppUrl, - [Parameter()] - [ValidateSet("Present","Absent")] + [Parameter()] + [ValidateSet("Present","Absent")] [System.String] $Ensure = "Present", [Parameter()] diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPRemoteFarmTrust/readme.md b/Modules/SharePointDsc/DSCResources/MSFT_SPRemoteFarmTrust/readme.md index a05c09641..110dcf5c6 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPRemoteFarmTrust/readme.md +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPRemoteFarmTrust/readme.md @@ -4,7 +4,8 @@ This resource is used to trust a remote SharePoint farm. This is used when federating search results between two different SharePoint farms. The -technique is described at +technique is described at: +https://technet.microsoft.com/en-us/library/dn133749.aspx The default value for the Ensure parameter is Present. When not specifying this parameter, the remote farm trust is created. diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 index eda711acb..5cc2961c9 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/MSFT_SPSearchServiceApp.psm1 @@ -69,6 +69,13 @@ function Get-TargetResource [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.Search") [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server") + $serviceAppPool = Get-SPServiceApplicationPool $params.ApplicationPool + if ($null -eq $serviceAppPool) + { + Write-Verbose -Message ("Specified service application pool $($params.ApplicationPool) " + ` + "does not exist.") + } + $serviceApps = Get-SPServiceApplication -Name $params.Name -ErrorAction SilentlyContinue $nullReturn = @{ @@ -207,6 +214,13 @@ function Set-TargetResource Invoke-SPDSCCommand -Credential $InstallAccount -Arguments $PSBoundParameters -ScriptBlock { $params = $args[0] + $serviceAppPool = Get-SPServiceApplicationPool $params.ApplicationPool + if ($null -eq $serviceAppPool) + { + throw ("Specified service application pool $($params.ApplicationPool) does not " + ` + "exist. Please make sure it exists before continuing.") + } + $serviceInstance = Get-SPEnterpriseSearchServiceInstance -Local Start-SPEnterpriseSearchServiceInstance -Identity $serviceInstance ` -ErrorAction SilentlyContinue diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPDiagnosticsProvider.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPDiagnosticsProvider.Tests.ps1 index 62a63d6a5..3aeda64bd 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPDiagnosticsProvider.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPDiagnosticsProvider.Tests.ps1 @@ -28,6 +28,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } -PassThru } + Mock -CommandName Set-SPDiagnosticsProvider -MockWith {} + Context -Name "When the Diagnostics Provider passed doesn't exist" -Fixture { $testParams = @{ @@ -67,6 +69,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should properly configure the provider" { Set-TargetResource @testParams + Assert-MockCalled Set-SPDiagnosticsProvider } It "Should return a Retention period of 14 from the Get method" { diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 index 77b11c49c..a1eeb0344 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPSearchServiceApp.Tests.ps1 @@ -2,7 +2,7 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] param( [Parameter()] - [string] + [string] $SharePointCmdletModule = (Join-Path -Path $PSScriptRoot ` -ChildPath "..\Stubs\SharePoint\15.0.4805.1000\Microsoft.SharePoint.PowerShell.psm1" ` -Resolve) @@ -31,44 +31,44 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } "@ - + $mockPassword = ConvertTo-SecureString -String "password" -AsPlainText -Force $mockCredential = New-Object -TypeName System.Management.Automation.PSCredential ` -ArgumentList @("DOMAIN\username", $mockPassword) - # Mocks for all contexts + # Mocks for all contexts Mock -CommandName Start-SPEnterpriseSearchServiceInstance -MockWith {} - Mock -CommandName Remove-SPServiceApplication -MockWith {} + Mock -CommandName Remove-SPServiceApplication -MockWith {} Mock -CommandName New-SPEnterpriseSearchServiceApplicationProxy -MockWith {} - Mock -CommandName Set-SPEnterpriseSearchServiceApplication -MockWith {} + Mock -CommandName Set-SPEnterpriseSearchServiceApplication -MockWith {} Mock -CommandName New-SPBusinessDataCatalogServiceApplication -MockWith { } - Mock -CommandName Set-SPEnterpriseSearchServiceApplication -MockWith { } + Mock -CommandName Set-SPEnterpriseSearchServiceApplication -MockWith { } Mock -CommandName Set-SPEnterpriseSearchService -MockWith {} - - Mock -CommandName Get-SPEnterpriseSearchServiceInstance -MockWith { - return @{} + + Mock -CommandName Get-SPEnterpriseSearchServiceInstance -MockWith { + return @{} } - Mock -CommandName New-SPEnterpriseSearchServiceApplication -MockWith { - return @{} + Mock -CommandName New-SPEnterpriseSearchServiceApplication -MockWith { + return @{} } - Mock -CommandName Get-SPServiceApplicationPool -MockWith { - return @{ - Name = $testParams.ApplicationPool - } + Mock -CommandName Get-SPServiceApplicationPool -MockWith { + return @{ + Name = $testParams.ApplicationPool + } } Mock -CommandName New-Object -MockWith { return @{ DefaultGatheringAccount = "Domain\username" } - } -ParameterFilter { - $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" + } -ParameterFilter { + $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" } Mock -CommandName Get-SPEnterpriseSearchService -MockWith { return @{ ProcessIdentity = "DOMAIN\username" } } - + Mock Import-Module -MockWith {} -ParameterFilter { $_.Name -eq $ModuleName } # Test contexts @@ -80,12 +80,29 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { WindowsServiceAccount = $mockCredential } - Mock -CommandName Get-SPServiceApplication -MockWith { - return $null + Mock -CommandName Get-SPServiceApplicationPool -MockWith { + return $null } - + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should Throw "Specified service application pool" + } + } + + Context -Name "When no service applications exist in the current farm" -Fixture { + $testParams = @{ + Name = "Search Service Application" + ApplicationPool = "SharePoint Search Services" + Ensure = "Present" + WindowsServiceAccount = $mockCredential + } + + Mock -CommandName Get-SPServiceApplication -MockWith { + return $null + } + It "Should return absent from the Get method" { - (Get-TargetResource @testParams).Ensure | Should Be "Absent" + (Get-TargetResource @testParams).Ensure | Should Be "Absent" } It "Should return false when the Test method is called" { @@ -94,7 +111,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should create a new service application in the set method" { Set-TargetResource @testParams - Assert-MockCalled New-SPEnterpriseSearchServiceApplication + Assert-MockCalled New-SPEnterpriseSearchServiceApplication } } @@ -105,22 +122,22 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Present" } - Mock -CommandName Get-SPServiceApplication -MockWith { - $spServiceApp = [PSCustomObject]@{ - DisplayName = $testParams.Name - } + Mock -CommandName Get-SPServiceApplication -MockWith { + $spServiceApp = [PSCustomObject]@{ + DisplayName = $testParams.Name + } $spServiceApp | Add-Member -MemberType ScriptMethod ` -Name GetType ` - -Value { - return @{ - FullName = "Microsoft.Office.UnKnownWebServiceApplication" - } - } -PassThru -Force - return $spServiceApp + -Value { + return @{ + FullName = "Microsoft.Office.UnKnownWebServiceApplication" + } + } -PassThru -Force + return $spServiceApp } It "Should return absent from the Get method" { - (Get-TargetResource @testParams).Ensure | Should Be "Absent" + (Get-TargetResource @testParams).Ensure | Should Be "Absent" } It "Should return false when the Test method is called" { @@ -129,7 +146,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should create a new service application in the set method" { Set-TargetResource @testParams - Assert-MockCalled New-SPEnterpriseSearchServiceApplication + Assert-MockCalled New-SPEnterpriseSearchServiceApplication } } @@ -139,8 +156,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { ApplicationPool = "SharePoint Search Services" Ensure = "Present" } - - Mock -CommandName Get-SPServiceApplication -MockWith { + + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name @@ -150,15 +167,15 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } It "Should return present from the get method" { (Get-TargetResource @testParams).Ensure | Should Be "Present" - Assert-MockCalled Get-SPServiceApplication -ParameterFilter { $Name -eq $testParams.Name } + Assert-MockCalled Get-SPServiceApplication -ParameterFilter { $Name -eq $testParams.Name } } It "Should return true when the Test method is called" { @@ -173,7 +190,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Present" } - Mock -CommandName Get-SPServiceApplication -MockWith { + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name @@ -183,17 +200,17 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } - Mock -CommandName Get-SPServiceApplicationPool -MockWith { - return @{ - Name = $testParams.ApplicationPool - } - } + Mock -CommandName Get-SPServiceApplicationPool -MockWith { + return @{ + Name = $testParams.ApplicationPool + } + } It "Should return false when the Test method is called" { Test-TargetResource @testParams | Should Be $false @@ -206,8 +223,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Assert-MockCalled Set-SPEnterpriseSearchServiceApplication } } - - Context -Name "When the default content access account does not match" -Fixture { + + Context -Name "When the default content access account does not match" -Fixture { $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" @@ -215,7 +232,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { DefaultContentAccessAccount = $mockCredential } - Mock -CommandName Get-SPServiceApplication -MockWith { + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name @@ -225,33 +242,33 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } - + Mock -CommandName New-Object -MockWith { return @{ DefaultGatheringAccount = "WRONG\username" } - } -ParameterFilter { - $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" + } -ParameterFilter { + $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" } It "Should return false from the test method" { Test-TargetResource @testParams | Should Be $false } - + It "changes the content access account" { - Set-TargetResource @testParams + Set-TargetResource @testParams Assert-MockCalled Get-SPServiceApplicationPool Assert-MockCalled Set-SPEnterpriseSearchServiceApplication } } - - Context -Name "When the default content access account does match" -Fixture { + + Context -Name "When the default content access account does match" -Fixture { $testParams = @{ Name = "Search Service Application" ApplicationPool = "SharePoint Search Services" @@ -259,37 +276,37 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { DefaultContentAccessAccount = $mockCredential } - Mock -CommandName Get-SPServiceApplication -MockWith { + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name - ApplicationPool = @{ - Name = $testParams.ApplicationPool + ApplicationPool = @{ + Name = $testParams.ApplicationPool } Database = @{ Name = $testParams.DatabaseName NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } - + Mock -CommandName New-Object -MockWith { return @{ DefaultGatheringAccount = "DOMAIN\username" } - } -ParameterFilter { - $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" + } -ParameterFilter { + $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" } - + It "Should return true from the test method" { Test-TargetResource @testParams | Should Be $true } } - + Context -Name "When the search center URL does not match" -Fixture { $testParams = @{ Name = "Search Service Application" @@ -300,7 +317,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { $Global:SPDscSearchURLUpdated = $false - Mock -CommandName Get-SPServiceApplication -MockWith { + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name @@ -314,36 +331,36 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { $spServiceApp = $spServiceApp | Add-Member ScriptMethod Update { $Global:SPDscSearchURLUpdated = $true } -PassThru - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } - Mock -CommandName Get-SPServiceApplicationPool -MockWith { - return @{ - Name = $testParams.ApplicationPool - } + Mock -CommandName Get-SPServiceApplicationPool -MockWith { + return @{ + Name = $testParams.ApplicationPool + } } - + Mock -CommandName New-Object -MockWith { return @{ DefaultGatheringAccount = "Domain\username" } - } -ParameterFilter { - $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" + } -ParameterFilter { + $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" } - + It "Should return false from the test method" { Test-TargetResource @testParams | Should Be $false } - + It "Should update the service app in the set method" { Set-TargetResource @testParams $Global:SPDscSearchURLUpdated | Should Be $true } } - + Context -Name "When the search center URL does match" -Fixture { $testParams = @{ Name = "Search Service Application" @@ -351,13 +368,13 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Present" } - Mock -CommandName Get-SPServiceApplicationPool -MockWith { - return @{ - Name = $testParams.ApplicationPool - } + Mock -CommandName Get-SPServiceApplicationPool -MockWith { + return @{ + Name = $testParams.ApplicationPool + } } - Mock -CommandName Get-SPServiceApplication -MockWith { + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name @@ -368,25 +385,25 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } - + Mock -CommandName New-Object { return @{ DefaultGatheringAccount = "Domain\username" } - } -ParameterFilter { - $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" + } -ParameterFilter { + $TypeName -eq "Microsoft.Office.Server.Search.Administration.Content" } - + It "Should return true from the test method" { Test-TargetResource @testParams | Should Be $true } } - + Context -Name "When the service app exists but it shouldn't" -Fixture { $testParams = @{ Name = "Search Service Application" @@ -394,38 +411,38 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Absent" } - Mock -CommandName Get-SPServiceApplication -MockWith { + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name - ApplicationPool = @{ - Name = $testParams.ApplicationPool + ApplicationPool = @{ + Name = $testParams.ApplicationPool } Database = @{ Name = $testParams.DatabaseName NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } - + It "Should return present from the Get method" { - (Get-TargetResource @testParams).Ensure | Should Be "Present" + (Get-TargetResource @testParams).Ensure | Should Be "Present" } - + It "Should return false from the test method" { Test-TargetResource @testParams | Should Be $false } - + It "Should remove the service application in the set method" { Set-TargetResource @testParams Assert-MockCalled Remove-SPServiceApplication } } - + Context -Name "When the service app doesn't exist and shouldn't" -Fixture { $testParams = @{ Name = "Search Service Application" @@ -433,19 +450,19 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Absent" } - Mock -CommandName Get-SPServiceApplication -MockWith { - return $null + Mock -CommandName Get-SPServiceApplication -MockWith { + return $null } - + It "Should return absent from the Get method" { - (Get-TargetResource @testParams).Ensure | Should Be "Absent" + (Get-TargetResource @testParams).Ensure | Should Be "Absent" } - + It "Should return false from the test method" { Test-TargetResource @testParams | Should Be $true } } - + Context -Name "When the service app exists and is cloud enabled" -Fixture { $testParams = @{ Name = "Search Service Application" @@ -453,8 +470,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Present" CloudIndex = $true } - - Mock -CommandName Get-SPServiceApplication -MockWith { + + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name @@ -465,35 +482,35 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } - Mock -CommandName Get-SPDSCInstalledProductVersion -MockWith { - return @{ + Mock -CommandName Get-SPDSCInstalledProductVersion -MockWith { + return @{ FileMajorPart = 15 - FileBuildPart = 0 - } + FileBuildPart = 0 + } } - + It "Should return false if the version is too low" { (Get-TargetResource @testParams).CloudIndex | Should Be $false } - - Mock -CommandName Get-SPDSCInstalledProductVersion -MockWith { - return @{ + + Mock -CommandName Get-SPDSCInstalledProductVersion -MockWith { + return @{ FileMajorPart = 15 - FileBuildPart = 5000 - } + FileBuildPart = 5000 + } } - + It "Should return that the web app is hybrid enabled from the get method" { (Get-TargetResource @testParams).CloudIndex | Should Be $true } } - + Context -Name "When the service doesn't exist and it should be cloud enabled" -Fixture { $testParams = @{ Name = "Search Service Application" @@ -501,29 +518,29 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Present" CloudIndex = $true } - - Mock -CommandName Get-SPServiceApplication -MockWith { - return $null + + Mock -CommandName Get-SPServiceApplication -MockWith { + return $null } - - Mock -CommandName Get-SPDSCInstalledProductVersion -MockWith { - return @{ + + Mock -CommandName Get-SPDSCInstalledProductVersion -MockWith { + return @{ FileMajorPart = 15 - FileBuildPart = 5000 + FileBuildPart = 5000 } } - + It "Should create the service app in the set method" { Set-TargetResource @testParams } - - Mock -CommandName Get-SPDSCInstalledProductVersion -MockWith { - return @{ + + Mock -CommandName Get-SPDSCInstalledProductVersion -MockWith { + return @{ FileMajorPart = 15 - FileBuildPart = 0 - } + FileBuildPart = 0 + } } - + It "Should throw an error in the set method if the version of SharePoint isn't high enough" { { Set-TargetResource @testParams } | Should Throw } @@ -536,8 +553,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Present" WindowsServiceAccount = $mockCredential } - - Mock -CommandName Get-SPServiceApplication -MockWith { + + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name @@ -547,14 +564,14 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } it "Should return the current value in the get method" { - (Get-TargetResource @testParams).WindowsServiceAccount | Should Not BeNullOrEmpty + (Get-TargetResource @testParams).WindowsServiceAccount | Should Not BeNullOrEmpty } it "Should return true in the test method" { @@ -569,8 +586,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Ensure = "Present" WindowsServiceAccount = $mockCredential } - - Mock -CommandName Get-SPServiceApplication -MockWith { + + Mock -CommandName Get-SPServiceApplication -MockWith { $spServiceApp = [PSCustomObject]@{ TypeName = "Search Service Application" DisplayName = $testParams.Name @@ -580,8 +597,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { NormalizedDataSource = $testParams.DatabaseServer } } - $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { - return @{ FullName = $getTypeFullName } + $spServiceApp = $spServiceApp | Add-Member -MemberType ScriptMethod -Name GetType -Value { + return @{ FullName = $getTypeFullName } } -PassThru -Force return $spServiceApp } @@ -591,7 +608,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { ProcessIdentity = "WrongUserName" } } - + it "Should return the current value in the get method" { (Get-TargetResource @testParams).WindowsServiceAccount | Should Not BeNullOrEmpty } From d65f0ac85335d6a84e44393098e3ec64722f8f46 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Sun, 19 Aug 2018 20:46:37 +0200 Subject: [PATCH 04/23] Updated readme of SPDatabaseAAG with important info --- CHANGELOG.md | 3 +++ .../SharePointDsc/DSCResources/MSFT_SPDatabaseAAG/Readme.md | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1c74efb3..7f1939d00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* SPDatabaseAAG + * Updated readme.md to specify that this resource also updates the database + connection string * SPDiagnosticsProvider * Fixed issue where enabling providers did not work * SPLogLevel diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPDatabaseAAG/Readme.md b/Modules/SharePointDsc/DSCResources/MSFT_SPDatabaseAAG/Readme.md index c66256bae..45dc99089 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPDatabaseAAG/Readme.md +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPDatabaseAAG/Readme.md @@ -17,3 +17,9 @@ cmdlets have been added in this CU: http://support.microsoft.com/kb/2880551 The default value for the Ensure parameter is Present. When not specifying this parameter, the content database is added to the AAG. + +Note: +By design the Add-DatabaseToAvailabilityGroup cmdlet updates the database +connection string to the specified availability group. If this is NOT what +you want (for example: You are using SQL aliasses which point to the AG +listener), you should NOT use this resource. From 5a5998537ef4884dd54f4f0083366860d34dccfe Mon Sep 17 00:00:00 2001 From: Nick Reilingh Date: Sun, 19 Aug 2018 19:16:15 -0400 Subject: [PATCH 05/23] PsDscRunAsAccount should be PsDscRunAsCredential MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed a mistake in the documentation — assuming the wiki is generated from this; if not, someone with access should update it. --- .../MSFT_SPServiceIdentity/MSFT_SPServiceIdentity.schema.mof | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPServiceIdentity/MSFT_SPServiceIdentity.schema.mof b/Modules/SharePointDsc/DSCResources/MSFT_SPServiceIdentity/MSFT_SPServiceIdentity.schema.mof index e245d3e7c..eb1e61307 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPServiceIdentity/MSFT_SPServiceIdentity.schema.mof +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPServiceIdentity/MSFT_SPServiceIdentity.schema.mof @@ -3,5 +3,5 @@ class MSFT_SPServiceIdentity : OMI_BaseResource { [Key, Description("The name of the service instance to manage")] string Name; [Required, Description("The user name of a managed account, LocalService, LocalSystem or NetworkService that will be used to run the service") ] string ManagedAccount; - [Write, Description("POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsAccount if using PowerShell 5"), EmbeddedInstance("MSFT_Credential")] String InstallAccount; + [Write, Description("POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsCredential if using PowerShell 5"), EmbeddedInstance("MSFT_Credential")] String InstallAccount; }; From 204279960149deb45759e20073c8390f7253ca4d Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Mon, 20 Aug 2018 12:14:38 +0200 Subject: [PATCH 06/23] Add pull request template and issue templates --- .github/ISSUE_TEMPLATE.md | 21 ------- .github/ISSUE_TEMPLATE/General.md | 7 +++ .../ISSUE_TEMPLATE/Problem_with_resource.md | 57 +++++++++++++++++++ .github/ISSUE_TEMPLATE/Resource_proposal.md | 21 +++++++ .github/PULL_REQUEST_TEMPLATE.md | 57 ++++++++++++++----- 5 files changed, 127 insertions(+), 36 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/General.md create mode 100644 .github/ISSUE_TEMPLATE/Problem_with_resource.md create mode 100644 .github/ISSUE_TEMPLATE/Resource_proposal.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 0e90fb22a..000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,21 +0,0 @@ -_Please provide the following information regarding your issue (place N/A if certain fields don't apply in your case:_ - -**DELETE THIS LINE AND ABOVE** - -**Details of the scenario you try and problem that is occurring:** - -**The DSC configuration that is using the resource:** - -**Version of the Operating System and PowerShell the DSC Target Node is running:** - -**Version of SharePoint that is used (e.g. SharePoint 2016):** - -**Version of the DSC module you're using:** - - -**DELETE THIS LINE AND BELOW** - -_Your feedback and support is greatly appreciated._ - -_If you are able to resolve this issue or add new features, you may submit a Pull Request against this project._ -_Please see the [Contribution Guideliness](https://github.com/powershell/xSharePoint/wiki/Contributing%20to%20xSharePoint) for information on how to contribute._ diff --git a/.github/ISSUE_TEMPLATE/General.md b/.github/ISSUE_TEMPLATE/General.md new file mode 100644 index 000000000..fbcdf2405 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/General.md @@ -0,0 +1,7 @@ +--- +name: General question or documentation update +about: If you have a general question or documentation update suggestion around the resource module. +--- + diff --git a/.github/ISSUE_TEMPLATE/Problem_with_resource.md b/.github/ISSUE_TEMPLATE/Problem_with_resource.md new file mode 100644 index 000000000..2431f65c0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Problem_with_resource.md @@ -0,0 +1,57 @@ +--- +name: Problem with a resource +about: If you have a problem, bug, or enhancement with a resource in this resource module. +--- + +#### Details of the scenario you tried and the problem that is occurring + +#### Verbose logs showing the problem + +#### Suggested solution to the issue + +#### The DSC configuration that is used to reproduce the issue (as detailed as possible) +```powershell +# insert configuration here +``` + +#### The operating system the target node is running + + +#### Version and build of PowerShell the target node is running + + +#### Version of the DSC module that was used ('dev' if using current dev branch) diff --git a/.github/ISSUE_TEMPLATE/Resource_proposal.md b/.github/ISSUE_TEMPLATE/Resource_proposal.md new file mode 100644 index 000000000..9f2a069a0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Resource_proposal.md @@ -0,0 +1,21 @@ +--- +name: New resource proposal +about: If you have a new resource proposal that you think should be added to this resource module. +--- + +### Description + +### Proposed properties + +### Special considerations or limitations diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f426db79b..84e1ea82f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,20 +1,47 @@ -Thanks for submitting a Pull Request to this project. -This template will help you create your pull request. + +#### Pull Request (PR) description + -**DELETE THIS LINE AND ABOVE** +#### This Pull Request (PR) fixes the following issues + -[Replace this with a description of your pull request] +#### Task list + +- [ ] Added an entry under the Unreleased section of the change log in the README.md. + Entry should say what was changed, and how that affects users (if applicable). +- [ ] Resource documentation added/updated in README.md. +- [ ] Resource parameter descriptions added/updated in README.md, schema.mof + and comment-based help. +- [ ] Comment-based help added/updated. +- [ ] Localization strings added/updated in all localization files as appropriate. +- [ ] Examples appropriately added/updated. +- [ ] Unit tests added/updated. See [DSC Resource Testing Guidelines](https://github.com/PowerShell/DscResources/blob/master/TestsGuidelines.md). +- [ ] Integration tests added/updated (where possible). See [DSC Resource Testing Guidelines](https://github.com/PowerShell/DscResources/blob/master/TestsGuidelines.md). +- [ ] New/changed code adheres to [DSC Resource Style Guidelines](https://github.com/PowerShell/DscResources/blob/master/StyleGuidelines.md) and [Best Practices](https://github.com/PowerShell/DscResources/blob/master/BestPractices.md). From bed0e894aee9884f24207769927761d3eb13670d Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 21 Aug 2018 11:19:55 +0200 Subject: [PATCH 07/23] Fix mistake with SPLogLevel update --- .../DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof b/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof index 8c86f9797..413dea9fc 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPLogLevel/MSFT_SPLogLevel.schema.mof @@ -3,7 +3,7 @@ Class MSFT_SPLogLevelItem { [Key, Description("Log Item Area")] String Area; [Key, Description("Log Item Name")] String Name; - [Write, Description("Minimum severity to capture in the trace logs "), ValueMap{"None","Unexpected","Monitorable","High","Medium","Verbose","VerboseEx","Default"}, Values{"None","Unexpected","Monitorable","Medium","Verbose","VerboseEx","Default"}] String TraceLevel; + [Write, Description("Minimum severity to capture in the trace logs "), ValueMap{"None","Unexpected","Monitorable","High","Medium","Verbose","VerboseEx","Default"}, Values{"None","Unexpected","Monitorable","High","Medium","Verbose","VerboseEx","Default"}] String TraceLevel; [Write, Description("Minimum severity to capture in the event logs"), ValueMap{"None","ErrorCritical","Error","Warning","Information","Verbose","Default"}, Values{"None","ErrorCritical","Error","Warning","Information","Verbose","Default"}] String EventLevel; }; From 078d4313f9e9d8fd7f3d3d6ae7069f56e4b649ed Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Wed, 22 Aug 2018 11:09:23 +0200 Subject: [PATCH 08/23] Update with SharePoint specific content --- .github/ISSUE_TEMPLATE/Problem_with_resource.md | 2 ++ .github/PULL_REQUEST_TEMPLATE.md | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Problem_with_resource.md b/.github/ISSUE_TEMPLATE/Problem_with_resource.md index 2431f65c0..2eb4c771a 100644 --- a/.github/ISSUE_TEMPLATE/Problem_with_resource.md +++ b/.github/ISSUE_TEMPLATE/Problem_with_resource.md @@ -48,6 +48,8 @@ about: If you have a problem, bug, or enhancement with a resource in this resour 'OsMuiLanguages') --> +#### Version of SharePoint that is used (e.g. SharePoint 2016) + #### Version and build of PowerShell the target node is running -- [ ] Added an entry under the Unreleased section of the change log in the README.md. +- [ ] Added an entry under the Unreleased section of the change log in the CHANGELOG.md. Entry should say what was changed, and how that affects users (if applicable). - [ ] Resource documentation added/updated in README.md. -- [ ] Resource parameter descriptions added/updated in README.md, schema.mof +- [ ] Resource parameter descriptions added/updated in schema.mof and comment-based help. - [ ] Comment-based help added/updated. - [ ] Localization strings added/updated in all localization files as appropriate. From 7172456d3ec23872ccb52d4f054fc16420dc2379 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Thu, 23 Aug 2018 11:59:18 +0200 Subject: [PATCH 09/23] Fix text for entry --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 63a98a604..17d3a6734 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -38,7 +38,7 @@ --> - [ ] Added an entry under the Unreleased section of the change log in the CHANGELOG.md. Entry should say what was changed, and how that affects users (if applicable). -- [ ] Resource documentation added/updated in README.md. +- [ ] Resource documentation added/updated in README.md in the resource folder. - [ ] Resource parameter descriptions added/updated in schema.mof and comment-based help. - [ ] Comment-based help added/updated. From 3c4b275f4304f573663224519408105b635425eb Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 24 Aug 2018 09:43:56 +0200 Subject: [PATCH 10/23] Fix issue with SPSearchTopology --- .../MSFT_SPSearchTopology.psm1 | 2 +- .../SharePointDsc.SPSearchTopology.Tests.ps1 | 171 ++++++++++++------ 2 files changed, 113 insertions(+), 60 deletions(-) diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 index a899a9d34..426eca67e 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPSearchTopology/MSFT_SPSearchTopology.psm1 @@ -321,7 +321,7 @@ function Set-TargetResource { throw "Unable to locate a search service instance on $serverName" } - $AllSearchServiceInstances.Add($serverName, $serviceToAdd) + $AllSearchServiceInstances.Add($server, $serviceToAdd) } # Get current topology and prepare a new one diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPSearchTopology.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPSearchTopology.Tests.ps1 index 127e72ce9..9a212b9cf 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPSearchTopology.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPSearchTopology.Tests.ps1 @@ -1,7 +1,7 @@ [CmdletBinding()] param( [Parameter()] - [string] + [string] $SharePointCmdletModule = (Join-Path -Path $PSScriptRoot ` -ChildPath "..\Stubs\SharePoint\15.0.4805.1000\Microsoft.SharePoint.PowerShell.psm1" ` -Resolve) @@ -55,7 +55,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { $indexComponent.ServerId = $serverId $indexComponent.IndexPartitionOrdinal = 0 - # Mocks for all contexts + # Mocks for all contexts Mock -CommandName Start-Sleep -MockWith {} Mock -CommandName New-Item -MockWith { return @{} } Mock -CommandName Get-SPEnterpriseSearchServiceInstance -MockWith { @@ -71,35 +71,35 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { ActiveTopology = @{} } } - Mock -CommandName Start-SPEnterpriseSearchServiceInstance -MockWith { - return $null + Mock -CommandName Start-SPEnterpriseSearchServiceInstance -MockWith { + return $null } - Mock -CommandName New-SPEnterpriseSearchTopology -MockWith { - return @{} + Mock -CommandName New-SPEnterpriseSearchTopology -MockWith { + return @{} } - Mock -CommandName New-SPEnterpriseSearchAdminComponent -MockWith { - return @{} - } - Mock -CommandName New-SPEnterpriseSearchCrawlComponent -MockWith { - return @{} + Mock -CommandName New-SPEnterpriseSearchAdminComponent -MockWith { + return @{} } - Mock -CommandName New-SPEnterpriseSearchContentProcessingComponent -MockWith { - return @{} + Mock -CommandName New-SPEnterpriseSearchCrawlComponent -MockWith { + return @{} } - Mock -CommandName New-SPEnterpriseSearchAnalyticsProcessingComponent -MockWith { - return @{} + Mock -CommandName New-SPEnterpriseSearchContentProcessingComponent -MockWith { + return @{} } - Mock -CommandName New-SPEnterpriseSearchQueryProcessingComponent -MockWith { - return @{} + Mock -CommandName New-SPEnterpriseSearchAnalyticsProcessingComponent -MockWith { + return @{} } - Mock -CommandName New-SPEnterpriseSearchIndexComponent -MockWith { - return @{} + Mock -CommandName New-SPEnterpriseSearchQueryProcessingComponent -MockWith { + return @{} } - Mock -CommandName Set-SPEnterpriseSearchTopology -MockWith { - return @{} + Mock -CommandName New-SPEnterpriseSearchIndexComponent -MockWith { + return @{} } - Mock -CommandName Remove-SPEnterpriseSearchComponent -MockWith { - return $null + Mock -CommandName Set-SPEnterpriseSearchTopology -MockWith { + return @{} + } + Mock -CommandName Remove-SPEnterpriseSearchComponent -MockWith { + return $null } Mock -CommandName Get-SPServer -MockWith { return @( @@ -143,7 +143,60 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should set the desired topology for the current server" { Set-TargetResource @testParams } - } + } + + Context -Name "No search topology has been applied, with servers specified as FQDN" -Fixture { + $testParams = @{ + ServiceAppName = "Search Service Application" + Admin = @("$($env:COMPUTERNAME).domain.com") + Crawler = @("$($env:COMPUTERNAME).domain.com") + ContentProcessing = @("$($env:COMPUTERNAME).domain.com") + AnalyticsProcessing = @("$($env:COMPUTERNAME).domain.com") + QueryProcessing = @("$($env:COMPUTERNAME).domain.com") + IndexPartition = @("$($env:COMPUTERNAME).domain.com") + FirstPartitionDirectory = "I:\SearchIndexes\0" + } + + Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { + return @{} + } + + Mock -CommandName Get-SPEnterpriseSearchServiceInstance -MockWith { + return @{ + Server = @{ + Address = "$($env:COMPUTERNAME).domain.com" + } + Status = "Online" + } + } -ParameterFilter { $Identity -eq "$($env:COMPUTERNAME).domain.com" } + + Mock -CommandName Get-CimInstance -MockWith { + return @{ + Domain = "domain.com" + } + } + + Mock -CommandName Get-SPEnterpriseSearchServiceInstance -MockWith { + return $null + } -ParameterFilter { $Identity -ne "$($env:COMPUTERNAME).domain.com" } + + It "Should return empty values from the get method" { + $result = Get-TargetResource @testParams + $result.Admin | Should BeNullOrEmpty + $result.Crawler | Should BeNullOrEmpty + $result.ContentProcessing | Should BeNullOrEmpty + $result.AnalyticsProcessing | Should BeNullOrEmpty + $result.QueryProcessing | Should BeNullOrEmpty + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should Be $false + } + + It "Should set the desired topology for the current server" { + Set-TargetResource @testParams + } + } Context -Name "No search topology exist and the search service instance isnt running" -Fixture { $testParams = @{ @@ -156,7 +209,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { IndexPartition = @($env:COMPUTERNAME) FirstPartitionDirectory = "I:\SearchIndexes\0" } - + Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @{} } @@ -192,7 +245,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { IndexPartition = @($env:COMPUTERNAME) FirstPartitionDirectory = "I:\SearchIndexes\0" } - + Mock -CommandName Get-SPEnterpriseSearchServiceInstance -MockWith { return @{ Server = @{ @@ -201,13 +254,13 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Status = "Online" } } - + It "Should add a missing admin component" { Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @( - $crawlComponent, - $contentProcessingComponent, - $analyticsProcessingComponent, + $crawlComponent, + $contentProcessingComponent, + $analyticsProcessingComponent, $queryProcessingComponent) } Set-TargetResource @testParams @@ -217,9 +270,9 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should add a missing crawl component" { Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @( - $adminComponent, - $contentProcessingComponent, - $analyticsProcessingComponent, + $adminComponent, + $contentProcessingComponent, + $analyticsProcessingComponent, $queryProcessingComponent) } Set-TargetResource @testParams @@ -229,9 +282,9 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should add a missing content processing component" { Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @( - $adminComponent, - $crawlComponent, - $analyticsProcessingComponent, + $adminComponent, + $crawlComponent, + $analyticsProcessingComponent, $queryProcessingComponent) } Set-TargetResource @testParams @@ -241,9 +294,9 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should add a missing analytics processing component" { Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @( - $adminComponent, + $adminComponent, $crawlComponent, - $contentProcessingComponent, + $contentProcessingComponent, $queryProcessingComponent) } Set-TargetResource @testParams @@ -253,9 +306,9 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should add a missing query processing component" { Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @( - $adminComponent, - $crawlComponent, - $contentProcessingComponent, + $adminComponent, + $crawlComponent, + $contentProcessingComponent, $analyticsProcessingComponent) } Set-TargetResource @testParams @@ -272,13 +325,13 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { IndexPartition = @("sharepoint2") FirstPartitionDirectory = "I:\SearchIndexes\0" } - + Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @( - $adminComponent, - $crawlComponent, - $contentProcessingComponent, - $analyticsProcessingComponent, + $adminComponent, + $crawlComponent, + $contentProcessingComponent, + $analyticsProcessingComponent, $queryProcessingComponent) } @@ -302,11 +355,11 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @( - $adminComponent, - $crawlComponent, - $contentProcessingComponent, - $analyticsProcessingComponent, - $queryProcessingComponent, + $adminComponent, + $crawlComponent, + $contentProcessingComponent, + $analyticsProcessingComponent, + $queryProcessingComponent, $indexComponent) } @@ -344,8 +397,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { FirstPartitionDirectory = "I:\SearchIndexes\0" } - Mock -CommandName Get-SPEnterpriseSearchServiceApplication -MockWith { - return $null + Mock -CommandName Get-SPEnterpriseSearchServiceApplication -MockWith { + return $null } Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @{} @@ -360,7 +413,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should set the desired topology for the current server" { - { Set-TargetResource @testParams } | Should Throw + { Set-TargetResource @testParams } | Should Throw } } @@ -409,11 +462,11 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Mock -CommandName Get-SPEnterpriseSearchComponent -MockWith { return @( - $adminComponent, - $crawlComponent, - $contentProcessingComponent, - $analyticsProcessingComponent, - $queryProcessingComponent, + $adminComponent, + $crawlComponent, + $contentProcessingComponent, + $analyticsProcessingComponent, + $queryProcessingComponent, $indexComponent) } From 61230e34c3e4ac50437afd9f3a3f4529ad4c7b20 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 24 Aug 2018 15:31:22 +0200 Subject: [PATCH 11/23] Incorporated review comments --- .../MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 | 2 +- ...ntDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPTrustedIdentityTokenIssuerProviderRealms/MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPTrustedIdentityTokenIssuerProviderRealms/MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 index 43d61cd12..b25b9bd33 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPTrustedIdentityTokenIssuerProviderRealms/MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPTrustedIdentityTokenIssuerProviderRealms/MSFT_SPTrustedIdentityTokenIssuerProviderRealms.psm1 @@ -101,7 +101,7 @@ function Get-TargetResource ProviderRealmsToExclude = $null CurrentRealms = $null RealmsToAdd = $null - Ensure = $null + Ensure = "Absent" } } $currentStatus = Get-ProviderRealmsStatus -currentRealms $result ` diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 index 846b497cf..f80f878b9 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPTrustedIdentityTokenIssuerProviderRealms.Tests.ps1 @@ -33,8 +33,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Mock -CommandName Get-SPTrustedIdentityTokenIssuer -MockWith { return $null } - It "Should get Error message SPTrustedIdentityTokenIssuer 'Contoso' not found" { - (Get-TargetResource @testParams).Ensure | Should Be $null + It "Ensure should be Absent, since SPTrustedIdentityTokenIssuer 'Contoso' was not found" { + (Get-TargetResource @testParams).Ensure | Should Be "Absent" } } From b17d011eea65e0752bb24a72a9768bbd9d37cc9a Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 29 Aug 2018 16:54:19 +0200 Subject: [PATCH 12/23] Implemented fix for #858: Check for different Central Admin Port --- CHANGELOG.md | 2 + .../DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 | 399 +++++++++--------- .../SharePointDsc.SPFarm.Tests.ps1 | 105 +++++ 3 files changed, 316 insertions(+), 190 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f1939d00..d7cbe4f9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ connection string * SPDiagnosticsProvider * Fixed issue where enabling providers did not work +* SPFarm + * Added ability to check and update CentralAdministrationPort * SPLogLevel * Added High as TraceLevel, which was not included yet * SPSearchServiceApp diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 index f2fb5707a..9ccd614e3 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPFarm/MSFT_SPFarm.psm1 @@ -62,6 +62,15 @@ function Get-TargetResource Write-Verbose -Message "Getting the settings of the current local SharePoint Farm (if any)" + if ($PSBoundParameters.ContainsKey("CentralAdministrationPort")) + { + if ($CentralAdministrationPort -notin 1..65535) + { + throw ("An invalid value for CentralAdministrationPort is specified: " + ` + "$CentralAdministrationPort") + } + } + if ($Ensure -eq "Absent") { throw ("SharePointDsc does not support removing a server from a farm, please set the " + ` @@ -329,6 +338,7 @@ function Set-TargetResource { $PSBoundParameters.Add("CentralAdministrationPort", 9999) } + if (-not $PSBoundParameters.ContainsKey("CentralAdministrationAuth")) { $PSBoundParameters.Add("CentralAdministrationAuth", "NTLM") @@ -383,243 +393,250 @@ function Set-TargetResource } if ($null -eq $serviceInstance) { - throw [Exception] "Unable to locate Central Admin service instance on this server" + throw "Unable to locate Central Admin service instance on this server" } Stop-SPServiceInstance -Identity $serviceInstance } } - return } - else + if ($CurrentValues.CentralAdministrationPort -ne $CentralAdministrationPort) { - throw ("This server is already connected to a farm. " + ` - "Please manually remove it to apply this change.") + Invoke-SPDSCCommand -Credential $InstallAccount ` + -Arguments $PSBoundParameters ` + -ScriptBlock { + $params = $args[0] + + Set-SPCentralAdministration -Port $params.CentralAdministrationPort + } } + return } + else + { + $actionResult = Invoke-SPDSCCommand -Credential $InstallAccount ` + -Arguments @($PSBoundParameters, $PSScriptRoot) ` + -ScriptBlock { + $params = $args[0] + $scriptRoot = $args[1] - $actionResult = Invoke-SPDSCCommand -Credential $InstallAccount ` - -Arguments @($PSBoundParameters, $PSScriptRoot) ` - -ScriptBlock { - $params = $args[0] - $scriptRoot = $args[1] - - $modulePath = "..\..\Modules\SharePointDsc.Farm\SPFarm.psm1" - Import-Module -Name (Join-Path -Path $scriptRoot -ChildPath $modulePath -Resolve) - $dbStatus = Get-SPDSCConfigDBStatus -SQLServer $params.DatabaseServer ` - -Database $params.FarmConfigDatabaseName - - while ($dbStatus.Locked -eq $true) - { - Write-Verbose -Message ("[$([DateTime]::Now.ToShortTimeString())] The configuration " + ` - "database is currently being provisioned by a remote " + ` - "server, this server will wait for this to complete") - Start-Sleep -Seconds 30 + $modulePath = "..\..\Modules\SharePointDsc.Farm\SPFarm.psm1" + Import-Module -Name (Join-Path -Path $scriptRoot -ChildPath $modulePath -Resolve) $dbStatus = Get-SPDSCConfigDBStatus -SQLServer $params.DatabaseServer ` -Database $params.FarmConfigDatabaseName - } - if ($dbStatus.ValidPermissions -eq $false) - { - throw "The current user does not have sufficient permissions to SQL Server" - return - } + while ($dbStatus.Locked -eq $true) + { + Write-Verbose -Message ("[$([DateTime]::Now.ToShortTimeString())] The configuration " + ` + "database is currently being provisioned by a remote " + ` + "server, this server will wait for this to complete") + Start-Sleep -Seconds 30 + $dbStatus = Get-SPDSCConfigDBStatus -SQLServer $params.DatabaseServer ` + -Database $params.FarmConfigDatabaseName + } - $executeArgs = @{ - DatabaseServer = $params.DatabaseServer - DatabaseName = $params.FarmConfigDatabaseName - Passphrase = $params.Passphrase.Password - SkipRegisterAsDistributedCacheHost = $true - } + if ($dbStatus.ValidPermissions -eq $false) + { + throw "The current user does not have sufficient permissions to SQL Server" + return + } - switch((Get-SPDSCInstalledProductVersion).FileMajorPart) - { - 15 { - Write-Verbose -Message "Detected Version: SharePoint 2013" + $executeArgs = @{ + DatabaseServer = $params.DatabaseServer + DatabaseName = $params.FarmConfigDatabaseName + Passphrase = $params.Passphrase.Password + SkipRegisterAsDistributedCacheHost = $true } - 16 { - if ($params.ContainsKey("ServerRole") -eq $true) - { - Write-Verbose -Message ("Detected Version: SharePoint 2016 - " + ` - "configuring server as $($params.ServerRole)") - $executeArgs.Add("LocalServerRole", $params.ServerRole) + + switch((Get-SPDSCInstalledProductVersion).FileMajorPart) + { + 15 { + Write-Verbose -Message "Detected Version: SharePoint 2013" } - else - { - Write-Verbose -Message ("Detected Version: SharePoint 2016 - no server " + ` - "role provided, configuring server without a " + ` - "specific role") - $executeArgs.Add("ServerRoleOptional", $true) + 16 { + if ($params.ContainsKey("ServerRole") -eq $true) + { + Write-Verbose -Message ("Detected Version: SharePoint 2016 - " + ` + "configuring server as $($params.ServerRole)") + $executeArgs.Add("LocalServerRole", $params.ServerRole) + } + else + { + Write-Verbose -Message ("Detected Version: SharePoint 2016 - no server " + ` + "role provided, configuring server without a " + ` + "specific role") + $executeArgs.Add("ServerRoleOptional", $true) + } + } + Default { + throw [Exception] ("An unknown version of SharePoint (Major version $_) " + ` + "was detected. Only versions 15 (SharePoint 2013) or " + ` + "16 (SharePoint 2016) are supported.") } } - Default { - throw [Exception] ("An unknown version of SharePoint (Major version $_) " + ` - "was detected. Only versions 15 (SharePoint 2013) or " + ` - "16 (SharePoint 2016) are supported.") - } - } - if ($dbStatus.DatabaseExists -eq $true) - { - Write-Verbose -Message ("The SharePoint config database " + ` - "'$($params.FarmConfigDatabaseName)' already exists, so " + ` - "this server will join the farm.") - $createFarm = $false - } - elseif ($dbStatus.DatabaseExists -eq $false -and $params.RunCentralAdmin -eq $false) - { - # Only allow the farm to be created by a server that will run central admin - # to avoid a ghost CA site appearing on this server and causing issues - Write-Verbose -Message ("The SharePoint config database " + ` - "'$($params.FarmConfigDatabaseName)' does not exist, but " + ` - "this server will not be running the central admin " + ` - "website, so it will wait to join the farm rather than " + ` - "create one.") - $createFarm = $false - } - else - { - Write-Verbose -Message ("The SharePoint config database " + ` - "'$($params.FarmConfigDatabaseName)' does not exist, so " + ` - "this server will create the farm.") - $createFarm = $true - } - - $farmAction = "" - if ($createFarm -eq $false) - { - # The database exists, so attempt to join the farm to the server - - - # Remove the server role optional attribute as it is only used when creating - # a new farm - if ($executeArgs.ContainsKey("ServerRoleOptional") -eq $true) + if ($dbStatus.DatabaseExists -eq $true) { - $executeArgs.Remove("ServerRoleOptional") + Write-Verbose -Message ("The SharePoint config database " + ` + "'$($params.FarmConfigDatabaseName)' already exists, so " + ` + "this server will join the farm.") + $createFarm = $false } - - Write-Verbose -Message ("The server will attempt to join the farm now once every " + ` - "60 seconds for the next 15 minutes.") - $loopCount = 0 - $connectedToFarm = $false - $lastException = $null - while ($connectedToFarm -eq $false -and $loopCount -lt 15) + elseif ($dbStatus.DatabaseExists -eq $false -and $params.RunCentralAdmin -eq $false) { - try - { - Connect-SPConfigurationDatabase @executeArgs | Out-Null - $connectedToFarm = $true - } - catch - { - $lastException = $_.Exception - Write-Verbose -Message ("$([DateTime]::Now.ToShortTimeString()) - An error " + ` - "occured joining config database " + ` - "'$($params.FarmConfigDatabaseName)' on " + ` - "'$($params.DatabaseServer)'. This resource will " + ` - "wait and retry automatically for up to 15 minutes. " + ` - "(waited $loopCount of 15 minutes)") - $loopCount++ - Start-Sleep -Seconds 60 - } + # Only allow the farm to be created by a server that will run central admin + # to avoid a ghost CA site appearing on this server and causing issues + Write-Verbose -Message ("The SharePoint config database " + ` + "'$($params.FarmConfigDatabaseName)' does not exist, but " + ` + "this server will not be running the central admin " + ` + "website, so it will wait to join the farm rather than " + ` + "create one.") + $createFarm = $false } - - if ($connectedToFarm -eq $false) + else { - Write-Verbose -Message ("Unable to join config database. Throwing exception.") - throw $lastException - return + Write-Verbose -Message ("The SharePoint config database " + ` + "'$($params.FarmConfigDatabaseName)' does not exist, so " + ` + "this server will create the farm.") + $createFarm = $true } - $farmAction = "JoinedFarm" - } - else - { - Add-SPDscConfigDBLock -SQLServer $params.DatabaseServer ` - -Database $params.FarmConfigDatabaseName - try + $farmAction = "" + if ($createFarm -eq $false) { - $executeArgs += @{ - FarmCredentials = $params.FarmAccount - AdministrationContentDatabaseName = $params.AdminContentDatabaseName + # The database exists, so attempt to join the farm to the server + + + # Remove the server role optional attribute as it is only used when creating + # a new farm + if ($executeArgs.ContainsKey("ServerRoleOptional") -eq $true) + { + $executeArgs.Remove("ServerRoleOptional") } - New-SPConfigurationDatabase @executeArgs + Write-Verbose -Message ("The server will attempt to join the farm now once every " + ` + "60 seconds for the next 15 minutes.") + $loopCount = 0 + $connectedToFarm = $false + $lastException = $null + while ($connectedToFarm -eq $false -and $loopCount -lt 15) + { + try + { + Connect-SPConfigurationDatabase @executeArgs | Out-Null + $connectedToFarm = $true + } + catch + { + $lastException = $_.Exception + Write-Verbose -Message ("$([DateTime]::Now.ToShortTimeString()) - An error " + ` + "occured joining config database " + ` + "'$($params.FarmConfigDatabaseName)' on " + ` + "'$($params.DatabaseServer)'. This resource will " + ` + "wait and retry automatically for up to 15 minutes. " + ` + "(waited $loopCount of 15 minutes)") + $loopCount++ + Start-Sleep -Seconds 60 + } + } - $farmAction = "CreatedFarm" + if ($connectedToFarm -eq $false) + { + Write-Verbose -Message ("Unable to join config database. Throwing exception.") + throw $lastException + return + } + $farmAction = "JoinedFarm" } - finally + else { - Remove-SPDscConfigDBLock -SQLServer $params.DatabaseServer ` - -Database $params.FarmConfigDatabaseName - } - } + Add-SPDscConfigDBLock -SQLServer $params.DatabaseServer ` + -Database $params.FarmConfigDatabaseName - # Run common tasks for a new server - Install-SPHelpCollection -All | Out-Null - Initialize-SPResourceSecurity | Out-Null - Install-SPService | Out-Null - Install-SPFeature -AllExistingFeatures -Force | Out-Null - - # Provision central administration - if ($params.RunCentralAdmin -eq $true) - { - $centralAdminSite = Get-SPWebApplication -IncludeCentralAdministration ` - | Where-Object -FilterScript { - $_.IsAdministrationWebApplication -eq $true - } + try + { + $executeArgs += @{ + FarmCredentials = $params.FarmAccount + AdministrationContentDatabaseName = $params.AdminContentDatabaseName + } + New-SPConfigurationDatabase @executeArgs - $centralAdminProvisioned = $false - if ((New-Object -TypeName System.Uri $centralAdminSite.Url).Port -eq $params.CentralAdministrationPort) - { - $centralAdminProvisioned = $true + $farmAction = "CreatedFarm" + } + finally + { + Remove-SPDscConfigDBLock -SQLServer $params.DatabaseServer ` + -Database $params.FarmConfigDatabaseName + } } - if ($centralAdminProvisioned -eq $false) - { - New-SPCentralAdministration -Port $params.CentralAdministrationPort ` - -WindowsAuthProvider $params.CentralAdministrationAuth - } - else + # Run common tasks for a new server + Install-SPHelpCollection -All | Out-Null + Initialize-SPResourceSecurity | Out-Null + Install-SPService | Out-Null + Install-SPFeature -AllExistingFeatures -Force | Out-Null + + # Provision central administration + if ($params.RunCentralAdmin -eq $true) { - $serviceInstance = Get-SPServiceInstance -Server $env:COMPUTERNAME ` - | Where-Object -FilterScript { - $_.TypeName -eq "Central Administration" - } - if ($null -eq $serviceInstance) + $centralAdminSite = Get-SPWebApplication -IncludeCentralAdministration ` + | Where-Object -FilterScript { + $_.IsAdministrationWebApplication -eq $true + } + + + $centralAdminProvisioned = $false + if ((New-Object -TypeName System.Uri $centralAdminSite.Url).Port -eq $params.CentralAdministrationPort) { - $domain = (Get-CimInstance -ClassName Win32_ComputerSystem).Domain - $fqdn = "$($env:COMPUTERNAME).$domain" - $serviceInstance = Get-SPServiceInstance -Server $fqdn ` - | Where-Object -FilterScript { - $_.TypeName -eq "Central Administration" - } + $centralAdminProvisioned = $true } - if ($null -eq $serviceInstance) + + if ($centralAdminProvisioned -eq $false) { - throw [Exception] "Unable to locate Central Admin service instance on this server" + New-SPCentralAdministration -Port $params.CentralAdministrationPort ` + -WindowsAuthProvider $params.CentralAdministrationAuth + } + else + { + $serviceInstance = Get-SPServiceInstance -Server $env:COMPUTERNAME ` + | Where-Object -FilterScript { + $_.TypeName -eq "Central Administration" + } + if ($null -eq $serviceInstance) + { + $domain = (Get-CimInstance -ClassName Win32_ComputerSystem).Domain + $fqdn = "$($env:COMPUTERNAME).$domain" + $serviceInstance = Get-SPServiceInstance -Server $fqdn ` + | Where-Object -FilterScript { + $_.TypeName -eq "Central Administration" + } + } + if ($null -eq $serviceInstance) + { + throw [Exception] "Unable to locate Central Admin service instance on this server" + } + Start-SPServiceInstance -Identity $serviceInstance } - Start-SPServiceInstance -Identity $serviceInstance } - } - Install-SPApplicationContent | Out-Null + Install-SPApplicationContent | Out-Null - return $farmAction - } + return $farmAction + } - if ($actionResult -eq "JoinedFarm") - { - Write-Verbose -Message "Starting timer service" - Start-Service -Name sptimerv4 + if ($actionResult -eq "JoinedFarm") + { + Write-Verbose -Message "Starting timer service" + Start-Service -Name sptimerv4 - Write-Verbose -Message ("Pausing for 5 minutes to allow the timer service to " + ` - "fully provision the server") - Start-Sleep -Seconds 300 - Write-Verbose -Message ("Join farm complete. Restarting computer to allow " + ` - "configuration to continue") + Write-Verbose -Message ("Pausing for 5 minutes to allow the timer service to " + ` + "fully provision the server") + Start-Sleep -Seconds 300 + Write-Verbose -Message ("Join farm complete. Restarting computer to allow " + ` + "configuration to continue") - $global:DSCMachineStatus = 1 + $global:DSCMachineStatus = 1 + } } } @@ -691,7 +708,9 @@ function Test-TargetResource return Test-SPDscParameterState -CurrentValues $CurrentValues ` -DesiredValues $PSBoundParameters ` - -ValuesToCheck @("Ensure", "RunCentralAdmin") + -ValuesToCheck @("Ensure", + "RunCentralAdmin", + "CentralAdministrationPort") } Export-ModuleMember -Function *-TargetResource diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 index 79b1ffce7..fa7d39fa5 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPFarm.Tests.ps1 @@ -45,6 +45,31 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Mock -CommandName "Start-SPServiceInstance" -MockWith { } # Test Contexts + Context -Name "No config databaes exists, and this server should be connected to one" -Fixture { + $testParams = @{ + Ensure = "Present" + FarmConfigDatabaseName = "SP_Config" + CentralAdministrationPort = 80000 + DatabaseServer = "sql.contoso.com" + FarmAccount = $mockFarmAccount + Passphrase = $mockPassphrase + AdminContentDatabaseName = "SP_AdminContent" + RunCentralAdmin = $true + } + + It "Should throw exception in the get method" { + { Get-TargetResource @testParams } | Should Throw "An invalid value for CentralAdministrationPort is specified:" + } + + It "Should throw exception in the test method" { + { Test-TargetResource @testParams } | Should Throw "An invalid value for CentralAdministrationPort is specified:" + } + + It "Should throw exception in the set method" { + { Set-TargetResource @testParams } | Should Throw "An invalid value for CentralAdministrationPort is specified:" + } + } + Context -Name "No config databaes exists, and this server should be connected to one" -Fixture { $testParams = @{ Ensure = "Present" @@ -411,6 +436,86 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } + Context -Name "Server is connected to farm, but CentralAdminPort is different" -Fixture { + $testParams = @{ + Ensure = "Present" + FarmConfigDatabaseName = "SP_Config" + DatabaseServer = "sql.contoso.com" + FarmAccount = $mockFarmAccount + Passphrase = $mockPassphrase + AdminContentDatabaseName = "SP_AdminContent" + RunCentralAdmin = $true + CentralAdministrationPort = 8080 + } + + Mock -CommandName Get-SPDSCRegistryKey -MockWith { + return "Connection string example" + } + + Mock -CommandName Get-SPFarm -MockWith { + return @{ + Name = $testParams.FarmConfigDatabaseName + DatabaseServer = @{ + Name = $testParams.DatabaseServer + } + AdminContentDatabaseName = $testParams.AdminContentDatabaseName + } + } + Mock -CommandName Get-SPDSCConfigDBStatus -MockWith { + return @{ + Locked = $false + ValidPermissions = $true + DatabaseExists = $true + } + } + Mock -CommandName Get-SPDatabase -MockWith { + return @(@{ + Name = $testParams.FarmConfigDatabaseName + Type = "Configuration Database" + NormalizedDataSource = $testParams.DatabaseServer + }) + } + Mock -CommandName Get-SPWebApplication -MockWith { + return @{ + IsAdministrationWebApplication = $true + ContentDatabases = @(@{ + Name = $testParams.AdminContentDatabaseName + }) + IISSettings = @(@{ + DisableKerberos = $true + }) + Url = "http://localhost:9999" + } + } + Mock -CommandName Get-CimInstance -MockWith { + return @{ + Domain = "domain.com" + } + } + + Mock -CommandName Get-SPServiceInstance -MockWith { + return @(@{ + TypeName = "Central Administration" + Status = "Online" + }) + } + + Mock -CommandName Set-SPCentralAdministration -MockWith {} + + It "Should return 9999 as CA Port from the get method" { + (Get-TargetResource @testParams).CentralAdministrationPort | Should Be 9999 + } + + It "Should update the central administration port" { + Set-TargetResource @testParams + Assert-MockCalled -CommandName "Set-SPCentralAdministration" + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should be $false + } + } + Context -Name "This server is connected to the farm and is running CA, but shouldn't" -Fixture { $testParams = @{ Ensure = "Present" From 4de17e01f5f5bf2e616abc329befb8fbc063a8b2 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 29 Aug 2018 17:35:15 +0200 Subject: [PATCH 13/23] Fix for issue #856: Resolve update conflict --- CHANGELOG.md | 3 +++ .../MSFT_SPUserProfileServiceApp.psm1 | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7cbe4f9e..5118b68a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ * Fixed issue where the resource would fail is the FQDN was specified * SPTrustedIdentityTokenIssuerProviderRealm * Fixed issue where Get method threw an error when the realm didn't exist yet +* SPUserProfileServiceApp + * Fix for issue where an update conflict error was thrown when new service + application was created. ## 2.4 diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.psm1 index 6d71d5db0..09f2c402c 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.psm1 @@ -381,13 +381,16 @@ function Set-TargetResource $app = $serviceApps | Select-Object -First 1 if ($null -eq $serviceApps) { - $app = New-SPProfileServiceApplication @params + New-SPProfileServiceApplication @params | Out-Null if ($null -ne $app) { New-SPProfileServiceApplicationProxy -Name $pName ` -ServiceApplication $app ` -DefaultProxyGroup } + + $app = Get-SPServiceApplication -Name $params.Name ` + -ErrorAction SilentlyContinue } if (($updateEnableNetBIOS -eq $true) -or ($updateNoILMUsed -eq $true)) From c7d60c02ee0508823af23f1e9f57fd173c587d8f Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 29 Aug 2018 20:40:29 +0200 Subject: [PATCH 14/23] Fix issue #855: Retrieve Farm account automatically --- CHANGELOG.md | 3 + .../MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 | 109 ++++++++++++++---- .../DSCResources/MSFT_SPAppCatalog/readme.md | 6 +- .../SharePointDsc.SPAppCatalog.Tests.ps1 | 62 ++++++++-- 4 files changed, 147 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5118b68a7..8ec7e1708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* SPAppCatalog + * Updated resource to retrieve the Farm account instead of requiring it + to be specifically used. * SPDatabaseAAG * Updated readme.md to specify that this resource also updates the database connection string diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 index bb19ea7c4..b514f22a0 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 @@ -4,12 +4,12 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( - [Parameter(Mandatory = $true)] - [System.String] + [Parameter(Mandatory = $true)] + [System.String] $SiteUrl, - [Parameter()] - [System.Management.Automation.PSCredential] + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) @@ -25,20 +25,20 @@ function Get-TargetResource SiteUrl = $null InstallAccount = $params.InstallAccount } - if ($null -eq $site) + if ($null -eq $site) { return $nullreturn } $wa = $site.WebApplication $feature = $wa.Features.Item([Guid]::Parse("f8bea737-255e-4758-ab82-e34bb46f5828")) - if($null -eq $feature) + if ($null -eq $feature) { return $nullreturn } - if ($site.ID -ne $feature.Properties["__AppCatSiteId"].Value) + if ($site.ID -ne $feature.Properties["__AppCatSiteId"].Value) { return $nullreturn - } + } return @{ SiteUrl = $site.Url InstallAccount = $params.InstallAccount @@ -53,30 +53,99 @@ function Set-TargetResource param ( [Parameter(Mandatory = $true)] - [System.String] + [System.String] $SiteUrl, - [Parameter()] - [System.Management.Automation.PSCredential] + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) Write-Verbose -Message "Setting app catalog status of $SiteUrl" - Invoke-SPDSCCommand -Credential $InstallAccount ` + Write-Verbose -Message "Retrieving farm account" + $farmAccount = Invoke-SPDSCCommand -Credential $InstallAccount ` + -Arguments $PSBoundParameters ` + -ScriptBlock { + return Get-SPDscFarmAccount + } + + Write-Verbose -Message "Check if InstallAccount or PsDscRunAsCredential is the farm account" + if ($null -ne $farmAccount) + { + if ($PSBoundParameters.ContainsKey("InstallAccount") -eq $true) + { + # InstallAccount used + if ($InstallAccount.UserName -eq $farmAccount.UserName) + { + throw ("Specified InstallAccount ($($InstallAccount.UserName)) is the Farm " + ` + "Account. Make sure the specified InstallAccount isn't the Farm Account " + ` + "and try again") + } + } + else + { + # PSDSCRunAsCredential or System + if (-not $Env:USERNAME.Contains("$")) + { + # PSDSCRunAsCredential used + $localaccount = "$($Env:USERDOMAIN)\$($Env:USERNAME)" + if ($localaccount -eq $farmAccount.UserName) + { + throw ("Specified PSDSCRunAsCredential ($localaccount) is the Farm " + ` + "Account. Make sure the specified PSDSCRunAsCredential isn't the " + ` + "Farm Account and try again") + } + } + } + } + else + { + throw ("Unable to retrieve the Farm Account. Check if the farm exists.") + } + + # Add the FarmAccount to the local Administrators group, if it's not already there + $isLocalAdmin = Test-SPDSCUserIsLocalAdmin -UserName $farmAccount.UserName + + if (!$isLocalAdmin) + { + Write-Verbose -Message "Adding farm account to Local Administrators group" + Add-SPDSCUserToLocalAdmin -UserName $farmAccount.UserName + + # Cycle the Timer Service and flush Kerberos tickets + # so that it picks up the local Admin token + Restart-Service -Name "SPTimerV4" + + Clear-SPDscKerberosToken -Account $farmAccount.UserName + } + + Invoke-SPDSCCommand -Credential $FarmAccount ` -Arguments $PSBoundParameters ` -ScriptBlock { $params = $args[0] - try + try { - Update-SPAppCatalogConfiguration -Site $params.SiteUrl -Confirm:$false + Update-SPAppCatalogConfiguration -Site $params.SiteUrl -Confirm:$false } - catch [System.UnauthorizedAccessException] + catch [System.UnauthorizedAccessException] { throw ("This resource must be run as the farm account (not a setup account). " + ` "Please ensure either the PsDscRunAsCredential or InstallAccount " + ` "credentials are set to the farm account and run this resource again") } + } | Out-Null + + # Remove the InstallAccount from the local Administrators group, if it was added above + if (!$isLocalAdmin) + { + Write-Verbose -Message "Removing farm account from Local Administrators group" + Remove-SPDSCUserToLocalAdmin -UserName $farmAccount.UserName + + # Cycle the Timer Service and flush Kerberos tickets + # so that it picks up the local Admin token + Restart-Service -Name "SPTimerV4" + + Clear-SPDscKerberosToken -Account $farmAccount.UserName } } @@ -86,12 +155,12 @@ function Test-TargetResource [OutputType([System.Boolean])] param ( - [Parameter(Mandatory = $true)] - [System.String] + [Parameter(Mandatory = $true)] + [System.String] $SiteUrl, - [Parameter()] - [System.Management.Automation.PSCredential] + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) @@ -99,7 +168,7 @@ function Test-TargetResource return Test-SPDscParameterState -CurrentValues (Get-TargetResource @PSBoundParameters) ` -DesiredValues $PSBoundParameters ` - -ValuesToCheck @("SiteUrl") + -ValuesToCheck @("SiteUrl") } Export-ModuleMember -Function *-TargetResource diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/readme.md b/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/readme.md index 41df77d02..1c85d9a80 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/readme.md +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/readme.md @@ -6,6 +6,6 @@ This resource will ensure that a specific site collection is marked as the app catalog for the web application that the site is in. The catalog site needs to have been created using the correct template (APPCATALOG#0). -This resource should be run using the farm account, and not another specific -setup account. Running this with the setup account you have used in your -configuration may relate to access denied errors. +This resource should NOT be run using the farm account. The resource will +retrieve the farm credentials from SharePoint and use that to update the +AppCatalog. This does mean it requires CredSSP to be setup! diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPAppCatalog.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPAppCatalog.Tests.ps1 index 9510d1b9e..b79042ac9 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPAppCatalog.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPAppCatalog.Tests.ps1 @@ -1,7 +1,7 @@ [CmdletBinding()] param( [Parameter()] - [string] + [string] $SharePointCmdletModule = (Join-Path -Path $PSScriptRoot ` -ChildPath "..\Stubs\SharePoint\15.0.4805.1000\Microsoft.SharePoint.PowerShell.psm1" ` -Resolve) @@ -19,8 +19,50 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope $mockSiteId = [Guid]::NewGuid() - - # Test contexts + + $mockPassword = ConvertTo-SecureString -String "password" -AsPlainText -Force + $mockCredential = New-Object -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @("$($Env:USERDOMAIN)\$($Env:USERNAME)", $mockPassword) + $mockFarmCredential = New-Object -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @("DOMAIN\sp_farm", $mockPassword) + + # Mocks for all contexts + Mock -CommandName Get-SPDSCFarmAccount -MockWith { + return $mockFarmCredential + } + Mock -CommandName Add-SPDSCUserToLocalAdmin -MockWith { } + Mock -CommandName Test-SPDSCUserIsLocalAdmin -MockWith { return $false } + Mock -CommandName Remove-SPDSCUserToLocalAdmin -MockWith { } + Mock -CommandName Restart-Service {} + + # Test contexts + Context -Name "The PsDscRunAsCredential is the Farm account" -Fixture { + $testParams = @{ + SiteUrl = "https://content.sharepoint.contoso.com/sites/AppCatalog" + } + + Mock -CommandName Update-SPAppCatalogConfiguration -MockWith {} + Mock -CommandName Get-SPSite -MockWith { + return @{ + WebApplication = @{ + Features = @( @{} ) | Add-Member -MemberType ScriptMethod ` + -Name "Item" ` + -Value { return $null } ` + -PassThru ` + -Force + } + ID = $mockSiteId + } + } + Mock -CommandName Get-SPDSCFarmAccount -MockWith { + return $mockCredential + } + + It "Should throw exception when executed" { + { Set-TargetResource @testParams } | Should Throw "Specified PSDSCRunAsCredential" + } + } + Context -Name "The specified site exists, but cannot be set as an app catalog as it is of the wrong template" -Fixture { $testParams = @{ SiteUrl = "https://content.sharepoint.contoso.com/sites/AppCatalog" @@ -86,7 +128,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } - + Context -Name "The specified site exists and is the current app catalog already" -Fixture { $testParams = @{ SiteUrl = "https://content.sharepoint.contoso.com/sites/AppCatalog" @@ -97,13 +139,13 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { WebApplication = @{ Features = @( @{} ) | Add-Member -MemberType ScriptMethod ` -Name "Item" ` - -Value { - return @{ + -Value { + return @{ ID = [guid]::NewGuid() Properties = @{ - "__AppCatSiteId" = @{Value = $mockSiteId} + "__AppCatSiteId" = @{Value = $mockSiteId} } - } + } } ` -PassThru ` -Force @@ -128,7 +170,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { SiteUrl = "https://content.sharepoint.contoso.com/sites/AppCatalog" } - Mock -CommandName Update-SPAppCatalogConfiguration -MockWith { + Mock -CommandName Update-SPAppCatalogConfiguration -MockWith { throw [System.UnauthorizedAccessException] "ACCESS IS DENIED" } Mock -CommandName Get-SPSite -MockWith { @@ -157,7 +199,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { ("This resource must be run as the farm account (not a setup account). " + ` "Please ensure either the PsDscRunAsCredential or InstallAccount " + ` "credentials are set to the farm account and run this resource again") - } + } } } } From 16dcbc10da17e13405eb3397cab10b951c5abbf6 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 30 Aug 2018 11:21:09 +0200 Subject: [PATCH 15/23] Fixed issue #857: Added SiteNamingConflictResolution parameter to SPUserProfileServiceApp --- CHANGELOG.md | 1 + .../MSFT_SPUserProfileServiceApp.psm1 | 66 +++++++--- .../MSFT_SPUserProfileServiceApp.schema.mof | 1 + .../MSFT_SPUserProfileServiceApp/readme.md | 5 + .../Examples/Resources/SPSite/2-SiteQuota.ps1 | 27 ++++ .../3-SiteNamingConflictResolution.ps1 | 37 ++++++ ...PointDsc.SPUserProfileServiceApp.Tests.ps1 | 121 ++++++++++++++++++ 7 files changed, 243 insertions(+), 15 deletions(-) create mode 100644 Modules/SharePointDsc/Examples/Resources/SPSite/2-SiteQuota.ps1 create mode 100644 Modules/SharePointDsc/Examples/Resources/SPUserProfileServiceApp/3-SiteNamingConflictResolution.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ec7e1708..f9bfd8b0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ * SPUserProfileServiceApp * Fix for issue where an update conflict error was thrown when new service application was created. + * Added SiteNamingConflictResolution parameter to the resource. ## 2.4 diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.psm1 index 09f2c402c..1552deb9f 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.psm1 @@ -56,6 +56,11 @@ function Get-TargetResource [System.Boolean] $NoILMUsed = $false, + [Parameter()] + [ValidateSet("Username_CollisionError","Username_CollisionDomain","Domain_Username")] + [System.String] + $SiteNamingConflictResolution, + [Parameter()] [ValidateSet("Present","Absent")] [System.String] @@ -165,6 +170,7 @@ function Get-TargetResource } $upMySiteLocation = $null $upMySiteManagedPath = $null + $upSiteConflictNaming = $null try { $ca = Get-SPWebApplication -IncludeCentralAdministration | Where-Object -FilterScript {$_.IsAdministrationWebApplication} @@ -173,6 +179,7 @@ function Get-TargetResource $userProfileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($serviceContext) $upMySiteLocation = $userProfileManager.MySiteHostUrl $upMySiteManagedPath = $userProfileManager.PersonalSiteInclusion + $upSiteConflictNaming = $userProfileManager.PersonalSiteFormat } catch { @@ -180,21 +187,22 @@ function Get-TargetResource } return @{ - Name = $serviceApp.DisplayName - ProxyName = $proxyName - ApplicationPool = $serviceApp.ApplicationPool.Name - MySiteHostLocation = $upMySiteLocation - MySiteManagedPath = $upMySiteManagedPath - ProfileDBName = $databases.ProfileDatabase.Name - ProfileDBServer = $databases.ProfileDatabase.NormalizedDataSource - SocialDBName = $databases.SocialDatabase.Name - SocialDBServer = $databases.SocialDatabase.NormalizedDataSource - SyncDBName = $databases.SynchronizationDatabase.Name - SyncDBServer = $databases.SynchronizationDatabase.NormalizedDataSource - InstallAccount = $params.InstallAccount - EnableNetBIOS = $serviceApp.NetBIOSDomainNamesEnabled - NoILMUsed = $serviceApp.NoILMUsed - Ensure = "Present" + Name = $serviceApp.DisplayName + ProxyName = $proxyName + ApplicationPool = $serviceApp.ApplicationPool.Name + MySiteHostLocation = $upMySiteLocation + MySiteManagedPath = $upMySiteManagedPath + ProfileDBName = $databases.ProfileDatabase.Name + ProfileDBServer = $databases.ProfileDatabase.NormalizedDataSource + SocialDBName = $databases.SocialDatabase.Name + SocialDBServer = $databases.SocialDatabase.NormalizedDataSource + SyncDBName = $databases.SynchronizationDatabase.Name + SyncDBServer = $databases.SynchronizationDatabase.NormalizedDataSource + InstallAccount = $params.InstallAccount + EnableNetBIOS = $serviceApp.NetBIOSDomainNamesEnabled + NoILMUsed = $serviceApp.NoILMUsed + SiteNamingConflictResolution = $upSiteConflictNaming + Ensure = "Present" } } } @@ -258,6 +266,11 @@ function Set-TargetResource [System.Boolean] $NoILMUsed = $false, + [Parameter()] + [ValidateSet("Username_CollisionError","Username_CollisionDomain","Domain_Username")] + [System.String] + $SiteNamingConflictResolution, + [Parameter()] [ValidateSet("Present","Absent")] [System.String] @@ -349,6 +362,14 @@ function Set-TargetResource $params.Remove("NoILMUsed") | Out-Null } + $updateSiteNamingConflict = $false + if ($params.ContainsKey("SiteNamingConflictResolution")) + { + $updateSiteNamingConflict = $true + $SiteNamingConflictResolution = $params.SiteNamingConflictResolution + $params.Remove("SiteNamingConflictResolution") | Out-Null + } + if ($params.ContainsKey("InstallAccount")) { $params.Remove("InstallAccount") | Out-Null @@ -408,6 +429,15 @@ function Set-TargetResource } $app.Update() } + + if ($updateSiteNamingConflict -eq $true) + { + $ca = Get-SPWebApplication -IncludeCentralAdministration | Where-Object -FilterScript {$_.IsAdministrationWebApplication} + $caSite = $ca.Sites[0] + $serviceContext = Get-SPServiceContext($caSite) + $userProfileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($serviceContext) + $userProfileManager.PersonalSiteFormat = $SiteNamingConflictResolution + } } # Remove the InstallAccount from the local Administrators group, if it was added above @@ -510,6 +540,11 @@ function Test-TargetResource [System.Boolean] $NoILMUsed = $false, + [Parameter()] + [ValidateSet("Username_CollisionError","Username_CollisionDomain","Domain_Username")] + [System.String] + $SiteNamingConflictResolution, + [Parameter()] [ValidateSet("Present","Absent")] [System.String] @@ -533,6 +568,7 @@ function Test-TargetResource -ValuesToCheck @("Name", "EnableNetBIOS", "NoILMUsed", + "SiteNamingConflictResolution", "Ensure") } else diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.schema.mof b/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.schema.mof index 1df4a1880..346802fa6 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.schema.mof +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/MSFT_SPUserProfileServiceApp.schema.mof @@ -14,6 +14,7 @@ class MSFT_SPUserProfileServiceApp : OMI_BaseResource [Write, Description("The name of the database server to host the sync database")] string SyncDBServer; [Write, Description("Whether Farm should resolve NetBIOS domain names")] boolean EnableNetBIOS; [Write, Description("Specifies if the service application should be configured to use AD Import")] boolean NoILMUsed; + [Write, Description("Specifies which SiteNamingConflictResolution should be used"), ValueMap{"Username_CollisionError","Username_CollisionDomain","Domain_Username"}, Values{"Username_CollisionError","Username_CollisionDomain","Domain_Username"}] string SiteNamingConflictResolution; [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; }; diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/readme.md b/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/readme.md index 86ba9f9c9..76d204c5b 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/readme.md +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPUserProfileServiceApp/readme.md @@ -18,6 +18,11 @@ and remove it again later on. The default value for the Ensure parameter is Present. When not specifying this parameter, the service application is provisioned. +The parameter SiteNamingConflictResolution accepts three values: Username_CollisionError, +Username_CollisionDomain and Domain_Username. More information on each of these +parameters can be found at: +https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.server.userprofiles.sitenameformat?view=sharepoint-server + NOTE: Due to the fact that SharePoint requires certain User Profile components to be provisioned as the Farm account, this resource and SPUserProfileSyncService diff --git a/Modules/SharePointDsc/Examples/Resources/SPSite/2-SiteQuota.ps1 b/Modules/SharePointDsc/Examples/Resources/SPSite/2-SiteQuota.ps1 new file mode 100644 index 000000000..1451c6e6a --- /dev/null +++ b/Modules/SharePointDsc/Examples/Resources/SPSite/2-SiteQuota.ps1 @@ -0,0 +1,27 @@ +<# +.EXAMPLE + This example creates a site collection with the provided details +#> + + Configuration Example + { + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + Import-DscResource -ModuleName SharePointDsc + + node localhost { + SPSite TeamSite + { + Url = "http://sharepoint.contoso.com" + OwnerAlias = "CONTOSO\ExampleUser" + HostHeaderWebApplication = "http://spsites.contoso.com" + Name = "Team Sites" + Template = "STS#0" + QuotaTemplate = "Teamsite" + PsDscRunAsCredential = $SetupAccount + } + } + } diff --git a/Modules/SharePointDsc/Examples/Resources/SPUserProfileServiceApp/3-SiteNamingConflictResolution.ps1 b/Modules/SharePointDsc/Examples/Resources/SPUserProfileServiceApp/3-SiteNamingConflictResolution.ps1 new file mode 100644 index 000000000..8574a2a39 --- /dev/null +++ b/Modules/SharePointDsc/Examples/Resources/SPUserProfileServiceApp/3-SiteNamingConflictResolution.ps1 @@ -0,0 +1,37 @@ +<# +.EXAMPLE + This example adds a new user profile service application to the local farm +#> + + Configuration Example + { + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount, + + [Parameter(Mandatory = $true)] + [PSCredential] + $FarmAccount + ) + Import-DscResource -ModuleName SharePointDsc + + node localhost { + SPUserProfileServiceApp UserProfileServiceApp + { + Name = "User Profile Service Application" + ApplicationPool = "SharePoint Service Applications" + MySiteHostLocation = "http://my.sharepoint.contoso.local" + MySiteManagedPath = "personal" + ProfileDBName = "SP_UserProfiles" + ProfileDBServer = "SQL.contoso.local\SQLINSTANCE" + SocialDBName = "SP_Social" + SocialDBServer = "SQL.contoso.local\SQLINSTANCE" + SyncDBName = "SP_ProfileSync" + SyncDBServer = "SQL.contoso.local\SQLINSTANCE" + EnableNetBIOS = $false + SiteNamingConflictResolution = "Domain_Username" + PsDscRunAsCredential = $SetupAccount + } + } + } diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPUserProfileServiceApp.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPUserProfileServiceApp.Tests.ps1 index bf8721290..3b1e10f34 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPUserProfileServiceApp.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPUserProfileServiceApp.Tests.ps1 @@ -36,6 +36,17 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { public UserProfileManager(System.Object a) { } + + public string PersonalSiteFormat + { + get + { + return "Domain_Username"; + } + set + { + } + } } } "@ -ErrorAction SilentlyContinue @@ -529,6 +540,116 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } + Context -Name "When service applications exist in the current farm and SiteNamingConflictResolution is incorrect" -Fixture { + $testParams = @{ + Name = "User Profile Service App" + ApplicationPool = "SharePoint Service Applications" + SiteNamingConflictResolution = "Username_CollisionDomain" + Ensure = "Present" + } + + Mock -CommandName Restart-Service -MockWith {} + Mock -CommandName Get-SPServiceApplication -MockWith { + return @( + New-Object -TypeName "Object" | + Add-Member -MemberType NoteProperty ` + -Name TypeName ` + -Value "User Profile Service Application" ` + -PassThru | + Add-Member -MemberType NoteProperty ` + -Name DisplayName ` + -Value $testParams.Name ` + -PassThru | + Add-Member -MemberType NoteProperty ` + -Name "NoILMUsed" ` + -Value $false ` + -PassThru | + Add-Member -MemberType ScriptMethod ` + -Name Update ` + -Value { + $Global:SPDscUPSAUpdateCalled = $true + } -PassThru | + Add-Member -MemberType NoteProperty ` + -Name ApplicationPool ` + -Value @{ + Name = $testParams.ApplicationPool + } -PassThru | + Add-Member -MemberType ScriptMethod ` + -Name GetType ` + -Value { + New-Object -TypeName "Object" | + Add-Member -MemberType NoteProperty ` + -Name FullName ` + -Value $getTypeFullName ` + -PassThru | + Add-Member -MemberType ScriptMethod ` + -Name GetProperties ` + -Value { + param($x) + return @( + (New-Object -TypeName "Object" | + Add-Member -MemberType NoteProperty ` + -Name Name ` + -Value "SocialDatabase" ` + -PassThru | + Add-Member -MemberType ScriptMethod ` + -Name GetValue ` + -Value { + param($x) + return @{ + Name = "SP_SocialDB" + NormalizedDataSource = "SQL.domain.local" + } + } -PassThru + ), + (New-Object -TypeName "Object" | + Add-Member -MemberType NoteProperty ` + -Name Name ` + -Value "ProfileDatabase" ` + -PassThru | + Add-Member -MemberType ScriptMethod ` + -Name GetValue ` + -Value { + return @{ + Name = "SP_ProfileDB" + NormalizedDataSource = "SQL.domain.local" + } + } -PassThru + ), + (New-Object -TypeName "Object" | + Add-Member -MemberType NoteProperty ` + -Name Name ` + -Value "SynchronizationDatabase" ` + -PassThru | + Add-Member -MemberType ScriptMethod ` + -Name GetValue ` + -Value { + return @{ + Name = "SP_ProfileSyncDB" + NormalizedDataSource = "SQL.domain.local" + } + } -PassThru + ) + ) + } -PassThru + } -PassThru -Force + ) + } + + It "Should return SiteNamingConflictResolution=Domain_Username from the Get method" { + (Get-TargetResource @testParams).SiteNamingConflictResolution | Should Be "Domain_Username" + } + + It "Should call Get-SPWebApplication before finishing set method" { + Set-TargetResource @testParams + Assert-MockCalled Get-SPWebApplication + } + + It "Should return false when the Test method is called" { + Test-TargetResource @testParams | Should Be $false + } + } + Context -Name "When a service application exists and is configured correctly" -Fixture { $testParams = @{ Name = "User Profile Service App" From a0b3fc974d89fc0e3661412049dcc7309e4c4f02 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 30 Aug 2018 12:36:49 +0200 Subject: [PATCH 16/23] Updated SPSite to allow updating of Quota template, owner and secondary owner, issue #829 --- CHANGELOG.md | 8 +- .../DSCResources/MSFT_SPSite/MSFT_SPSite.psm1 | 266 ++++++++++-------- .../SharePointDsc.SPSite.Tests.ps1 | 126 ++++++--- 3 files changed, 252 insertions(+), 148 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9bfd8b0f..7996349bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * SPAppCatalog * Updated resource to retrieve the Farm account instead of requiring it - to be specifically used. + to be specifically used * SPDatabaseAAG * Updated readme.md to specify that this resource also updates the database connection string @@ -23,12 +23,14 @@ * Fixed issue where Get method threw an error when the specified service application didn't exist yet * Fixed issue where the resource would fail is the FQDN was specified +* SPSite + * Added ability to check and update QuotaTemplate, OwnerAlias and SecondaryOwnerAlias * SPTrustedIdentityTokenIssuerProviderRealm * Fixed issue where Get method threw an error when the realm didn't exist yet * SPUserProfileServiceApp * Fix for issue where an update conflict error was thrown when new service - application was created. - * Added SiteNamingConflictResolution parameter to the resource. + application was created + * Added SiteNamingConflictResolution parameter to the resource ## 2.4 diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPSite/MSFT_SPSite.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPSite/MSFT_SPSite.psm1 index 87dd49e90..56da297a7 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPSite/MSFT_SPSite.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPSite/MSFT_SPSite.psm1 @@ -4,60 +4,60 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( - [Parameter(Mandatory = $true)] - [System.String] + [Parameter(Mandatory = $true)] + [System.String] $Url, - [Parameter(Mandatory = $true)] - [System.String] + [Parameter(Mandatory = $true)] + [System.String] $OwnerAlias, - [Parameter()] - [System.UInt32] + [Parameter()] + [System.UInt32] $CompatibilityLevel, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $ContentDatabase, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Description, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $HostHeaderWebApplication, - [Parameter()] - [System.UInt32] + [Parameter()] + [System.UInt32] $Language, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Name, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $OwnerEmail, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $QuotaTemplate, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $SecondaryEmail, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $SecondaryOwnerAlias, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Template, - [Parameter()] - [System.Management.Automation.PSCredential] + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) @@ -70,47 +70,47 @@ function Get-TargetResource $site = Get-SPSite -Identity $params.Url ` -ErrorAction SilentlyContinue - - if ($null -eq $site) + + if ($null -eq $site) { - return $null - } - else + return $null + } + else { - if ($site.HostHeaderIsSiteName) + if ($site.HostHeaderIsSiteName) { - $HostHeaderWebApplication = $site.WebApplication.Url - } + $HostHeaderWebApplication = $site.WebApplication.Url + } - if ($null -eq $site.Owner) + if ($null -eq $site.Owner) { $owner = $null - } - else + } + else { - if ($site.WebApplication.UseClaimsAuthentication) + if ($site.WebApplication.UseClaimsAuthentication) { $owner = (New-SPClaimsPrincipal -Identity $site.Owner.UserLogin ` -IdentityType "EncodedClaim").Value - } - else + } + else { $owner = $site.Owner.UserLogin } } - - if ($null -eq $site.SecondaryContact) + + if ($null -eq $site.SecondaryContact) { $secondaryOwner = $null - } - else + } + else { - if ($site.WebApplication.UseClaimsAuthentication) + if ($site.WebApplication.UseClaimsAuthentication) { $secondaryOwner = (New-SPClaimsPrincipal -Identity $site.SecondaryContact.UserLogin ` -IdentityType "EncodedClaim").Value - } - else + } + else { $secondaryOwner = $site.SecondaryContact.UserLogin } @@ -121,7 +121,7 @@ function Get-TargetResource Where-Object -FilterScript { $_.QuotaID -eq $site.Quota.QuotaID }).Name - + return @{ Url = $site.Url OwnerAlias = $owner @@ -148,78 +148,117 @@ function Set-TargetResource [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [System.String] + [Parameter(Mandatory = $true)] + [System.String] $Url, - [Parameter(Mandatory = $true)] - [System.String] + [Parameter(Mandatory = $true)] + [System.String] $OwnerAlias, - [Parameter()] - [System.UInt32] + [Parameter()] + [System.UInt32] $CompatibilityLevel, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $ContentDatabase, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Description, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $HostHeaderWebApplication, - [Parameter()] - [System.UInt32] + [Parameter()] + [System.UInt32] $Language, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Name, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $OwnerEmail, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $QuotaTemplate, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $SecondaryEmail, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $SecondaryOwnerAlias, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Template, - [Parameter()] - [System.Management.Automation.PSCredential] + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) Write-Verbose -Message "Setting site collection $Url" + $CurrentValues = Get-TargetResource @PSBoundParameters + $result = Invoke-SPDSCCommand -Credential $InstallAccount ` - -Arguments $PSBoundParameters ` + -Arguments @($PSBoundParameters,$CurrentValues) ` -ScriptBlock { $params = $args[0] - + $CurrentValues = $args[1] + $params.Remove("InstallAccount") | Out-Null $site = Get-SPSite -Identity $params.Url -ErrorAction SilentlyContinue - if ($null -eq $site) + if ($null -eq $site) { New-SPSite @params | Out-Null } + else + { + $newParams = @{ + Identity = $params.Url + } + + if ($params.ContainsKey("QuotaTemplate") -eq $true) + { + if ($params.QuotaTemplate -ne $CurrentValues.QuotaTemplate) + { + $newParams.QuotaTemplate = $params.QuotaTemplate + } + } + + if ($params.ContainsKey("OwnerAlias") -eq $true) + { + if ($params.OwnerAlias -ne $CurrentValues.OwnerAlias) + { + $newParams.OwnerAlias = $params.OwnerAlias + } + } + + if ($params.ContainsKey("SecondaryOwnerAlias") -eq $true) + { + if ($params.SecondaryOwnerAlias -ne $CurrentValues.SecondaryOwnerAlias) + { + $newParams.SecondaryOwnerAlias = $params.SecondaryOwnerAlias + } + } + + if ($newParams.Count -gt 1) + { + Write-Verbose -Message "Updating existing site collection" + Set-SPSite @newParams + } + } } } @@ -229,60 +268,60 @@ function Test-TargetResource [OutputType([System.Boolean])] param ( - [Parameter(Mandatory = $true)] - [System.String] + [Parameter(Mandatory = $true)] + [System.String] $Url, - [Parameter(Mandatory = $true)] - [System.String] + [Parameter(Mandatory = $true)] + [System.String] $OwnerAlias, - [Parameter()] - [System.UInt32] + [Parameter()] + [System.UInt32] $CompatibilityLevel, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $ContentDatabase, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Description, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $HostHeaderWebApplication, - [Parameter()] - [System.UInt32] + [Parameter()] + [System.UInt32] $Language, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Name, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $OwnerEmail, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $QuotaTemplate, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $SecondaryEmail, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $SecondaryOwnerAlias, - [Parameter()] - [System.String] + [Parameter()] + [System.String] $Template, - [Parameter()] - [System.Management.Automation.PSCredential] + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) @@ -290,13 +329,16 @@ function Test-TargetResource $CurrentValues = Get-TargetResource @PSBoundParameters - if ($null -eq $CurrentValues) + if ($null -eq $CurrentValues) { - return $false + return $false } return Test-SPDscParameterState -CurrentValues $CurrentValues ` -DesiredValues $PSBoundParameters ` - -ValuesToCheck @("Url") + -ValuesToCheck @("Url", + "QuotaTemplate", + "OwnerAlias", + "SecondaryOwnerAlias") } Export-ModuleMember -Function *-TargetResource diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPSite.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPSite.Tests.ps1 index 4f8594524..b3596e8ea 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPSite.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPSite.Tests.ps1 @@ -1,7 +1,7 @@ [CmdletBinding()] param( [Parameter()] - [string] + [string] $SharePointCmdletModule = (Join-Path -Path $PSScriptRoot ` -ChildPath "..\Stubs\SharePoint\15.0.4805.1000\Microsoft.SharePoint.PowerShell.psm1" ` -Resolve) @@ -18,7 +18,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { InModuleScope -ModuleName $Global:SPDscHelper.ModuleName -ScriptBlock { Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope - # Mocks for all contexts + # Mocks for all contexts Mock -CommandName New-SPSite -MockWith { } Mock -CommandName Get-SPDSCContentService -MockWith { $quotaTemplates = @(@{ @@ -26,16 +26,16 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { QuotaId = 65000 } }) - $quotaTemplatesCol = {$quotaTemplates}.Invoke() + $quotaTemplatesCol = {$quotaTemplates}.Invoke() $contentService = @{ QuotaTemplates = $quotaTemplatesCol - } + } $contentService = $contentService | Add-Member -MemberType ScriptMethod ` -Name Update ` - -Value { - $Global:SPDscQuotaTemplatesUpdated = $true + -Value { + $Global:SPDscQuotaTemplatesUpdated = $true } -PassThru return $contentService } @@ -64,17 +64,77 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } + Context -Name "The site exists, but has incorrect owner alias and quota" -Fixture { + $testParams = @{ + Url = "http://site.sharepoint.com" + OwnerAlias = "DEMO\User" + SecondaryOwnerAlias = "DEMO\SecondUser" + QuotaTemplate = "Test" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + WebApplication = @{ + Url = $testParams.Url + UseClaimsAuthentication = $false + } + Url = $testParams.Url + Owner = @{ UserLogin = "DEMO\owner" } + SecondaryContact = @{ UserLogin = "DEMO\secondowner" } + Quota = @{ + QuotaId = 1 + } + } + } + Mock -CommandName Set-SPSite -MockWith {} + Mock -CommandName Get-SPDSCContentService -MockWith { + $quotaTemplates = @(@{ + QuotaId = 1 + Name = "WrongTemplate" + WrongTemplate = @{ + StorageMaximumLevel = 512 + StorageWarningLevel = 256 + UserCodeMaximumLevel = 400 + UserCodeWarningLevel = 200 + } + }) + $quotaTemplatesCol = {$quotaTemplates}.Invoke() + + $contentService = @{ + QuotaTemplates = $quotaTemplatesCol + } + return $contentService + } + + It "Should return the site data from the get method" { + $result = Get-TargetResource @testParams + $result.OwnerAlias | Should Be "DEMO\owner" + $result.SecondaryOwnerAlias | Should Be "DEMO\SecondOwner" + $result.QuotaTemplate | Should Be "WrongTemplate" + } + + It "Should update owner and quota in the set method" { + Set-TargetResource @testParams + Assert-MockCalled Set-SPSite + } + + It "Should return true from the test method" { + Test-TargetResource @testParams | Should Be $false + } + } + Context -Name "The site exists and is a host named site collection" -Fixture { $testParams = @{ Url = "http://site.sharepoint.com" - OwnerAlias = "DEMO\User" + OwnerAlias = "DEMO\owner" } - - Mock -CommandName Get-SPSite -MockWith { + + Mock -CommandName Get-SPSite -MockWith { return @{ HostHeaderIsSiteName = $true - WebApplication = @{ - Url = $testParams.Url + WebApplication = @{ + Url = $testParams.Url UseClaimsAuthentication = $false } Url = $testParams.Url @@ -96,12 +156,12 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Url = "http://site.sharepoint.com" OwnerAlias = "DEMO\User" } - - Mock -CommandName Get-SPSite -MockWith { + + Mock -CommandName Get-SPSite -MockWith { return @{ HostHeaderIsSiteName = $false - WebApplication = @{ - Url = $testParams.Url + WebApplication = @{ + Url = $testParams.Url UseClaimsAuthentication = $true } Url = $testParams.Url @@ -110,9 +170,9 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } - Mock -CommandName New-SPClaimsPrincipal -MockWith { - return @{ - Value = $testParams.OwnerAlias + Mock -CommandName New-SPClaimsPrincipal -MockWith { + return @{ + Value = $testParams.OwnerAlias } } @@ -124,11 +184,11 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Test-TargetResource @testParams | Should Be $true } - Mock -CommandName Get-SPSite -MockWith { + Mock -CommandName Get-SPSite -MockWith { return @{ HostHeaderIsSiteName = $false - WebApplication = @{ - Url = $testParams.Url + WebApplication = @{ + Url = $testParams.Url UseClaimsAuthentication = $true } Url = $testParams.Url @@ -139,12 +199,12 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { It "Should return the site data from the get method where a valid site collection admin does not exist" { Get-TargetResource @testParams | Should Not BeNullOrEmpty } - - Mock -CommandName Get-SPSite -MockWith { + + Mock -CommandName Get-SPSite -MockWith { return @{ HostHeaderIsSiteName = $false - WebApplication = @{ - Url = $testParams.Url + WebApplication = @{ + Url = $testParams.Url UseClaimsAuthentication = $true } Url = $testParams.Url @@ -162,14 +222,14 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Context -Name "The site exists and uses classic authentication" -Fixture { $testParams = @{ Url = "http://site.sharepoint.com" - OwnerAlias = "DEMO\User" + OwnerAlias = "DEMO\owner" } - - Mock -CommandName Get-SPSite -MockWith { + + Mock -CommandName Get-SPSite -MockWith { return @{ HostHeaderIsSiteName = $false - WebApplication = @{ - Url = $testParams.Url + WebApplication = @{ + Url = $testParams.Url UseClaimsAuthentication = $false } Url = $testParams.Url @@ -186,11 +246,11 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Test-TargetResource @testParams | Should Be $true } - Mock -CommandName Get-SPSite -MockWith { + Mock -CommandName Get-SPSite -MockWith { return @{ HostHeaderIsSiteName = $false - WebApplication = @{ - Url = $testParams.Url + WebApplication = @{ + Url = $testParams.Url UseClaimsAuthentication = $false } Url = $testParams.Url From f358705e4fec759e240893c137889e819add4a26 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 30 Aug 2018 13:16:32 +0200 Subject: [PATCH 17/23] Implemented ExcludeDatabases parameter #797 --- CHANGELOG.md | 2 + .../MSFT_SPShellAdmins.psm1 | 531 ++++++++++-------- .../MSFT_SPShellAdmins.schema.mof | 1 + .../SPShellAdmins/3-ExcludeDatabases.ps1 | 25 + .../SharePointDsc.SPShellAdmins.Tests.ps1 | 248 ++++---- 5 files changed, 454 insertions(+), 353 deletions(-) create mode 100644 Modules/SharePointDsc/Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7996349bd..5cf582120 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ * Fixed issue where Get method threw an error when the specified service application didn't exist yet * Fixed issue where the resource would fail is the FQDN was specified +* SPShellAdmins + * Added ExcludeDatabases parameter for AllDatabases * SPSite * Added ability to check and update QuotaTemplate, OwnerAlias and SecondaryOwnerAlias * SPTrustedIdentityTokenIssuerProviderRealm diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 index 002844a3c..56cf971f0 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.psm1 @@ -4,7 +4,7 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $Name, @@ -21,7 +21,7 @@ function Get-TargetResource $MembersToExclude, [Parameter()] - [Microsoft.Management.Infrastructure.CimInstance[]] + [Microsoft.Management.Infrastructure.CimInstance[]] $Databases, [Parameter()] @@ -29,58 +29,73 @@ function Get-TargetResource $AllDatabases, [Parameter()] - [System.Management.Automation.PSCredential] + [System.String[]] + $ExcludeDatabases, + + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) Write-Verbose -Message "Getting Shell Admins config" - if ($Members -and (($MembersToInclude) -or ($MembersToExclude))) + $nullreturn = @{ + Name = $null + } + + if ($Members -and (($MembersToInclude) -or ($MembersToExclude))) { Write-Verbose -Message ("Cannot use the Members parameter together with the " + ` "MembersToInclude or MembersToExclude parameters") - return $null + return $nullreturn } - if ($Databases) + if ($Databases) { - foreach ($database in $Databases) + foreach ($database in $Databases) { if ($database.Members -and (($database.MembersToInclude) ` - -or ($database.MembersToExclude))) + -or ($database.MembersToExclude))) { Write-Verbose -Message ("Databases: Cannot use the Members parameter " + ` "together with the MembersToInclude or " + ` "MembersToExclude parameters") - return $null + return $nullreturn } if (!$database.Members ` -and !$database.MembersToInclude ` - -and !$database.MembersToExclude) + -and !$database.MembersToExclude) { Write-Verbose -Message ("Databases: At least one of the following " + ` "parameters must be specified: Members, " + ` "MembersToInclude, MembersToExclude") - return $null + return $nullreturn } } - } - else + } + else { - if (!$Members -and !$MembersToInclude -and !$MembersToExclude) + if (!$Members -and !$MembersToInclude -and !$MembersToExclude) { Write-Verbose -Message ("At least one of the following parameters must be " + ` "specified: Members, MembersToInclude, MembersToExclude") - return $null + return $nullreturn } } - if ($Databases -and $AllDatabases) + if ($Databases -and $AllDatabases) { Write-Verbose -Message ("Cannot use the Databases parameter together with the " + ` "AllDatabases parameter") - return $null + return $nullreturn + } + + if ($Databases -and $ExcludeDatabases) + { + Write-Verbose -Message ("Cannot use the Databases parameter together with the " + ` + "ExcludeDatabases parameter") + return $nullreturn } $result = Invoke-SPDSCCommand -Credential $InstallAccount ` @@ -88,34 +103,41 @@ function Get-TargetResource -ScriptBlock { $params = $args[0] $scriptRoot = $args[1] - + Import-Module -Name (Join-Path -Path $scriptRoot -ChildPath "MSFT_SPShellAdmins.psm1") - - try + + try { $spFarm = Get-SPFarm - } - catch + } + catch { Write-Verbose -Message ("No local SharePoint farm was detected. Shell admin " + ` "settings will not be applied") - return $null + return $nullreturn } $shellAdmins = Get-SPShellAdmin $cdbPermissions = @() $databases = Get-SPDatabase - foreach ($database in $databases) + if ($params.ContainsKey("ExcludeDatabases")) + { + $databases = $databases | Where-Object -FilterScript { + $_.Name -notin $params.ExcludeDatabases + } + } + + foreach ($database in $databases) { $cdbPermission = @{} - + $cdbPermission.Name = $database.Name $dbShellAdmins = Get-SPShellAdmin -Database $database.Id $cdbPermission.Members = $dbShellAdmins.UserName - - $cdbPermissions += $cdbPermission - } + + $cdbPermissions += $cdbPermission + } return @{ Name = $params.Name @@ -136,7 +158,7 @@ function Set-TargetResource [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $Name, @@ -153,7 +175,7 @@ function Set-TargetResource $MembersToExclude, [Parameter()] - [Microsoft.Management.Infrastructure.CimInstance[]] + [Microsoft.Management.Infrastructure.CimInstance[]] $Databases, [Parameter()] @@ -161,24 +183,28 @@ function Set-TargetResource $AllDatabases, [Parameter()] - [System.Management.Automation.PSCredential] + [System.String[]] + $ExcludeDatabases, + + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) Write-Verbose -Message "Setting Shell Admin config" - - if ($Members -and (($MembersToInclude) -or ($MembersToExclude))) + + if ($Members -and (($MembersToInclude) -or ($MembersToExclude))) { throw ("Cannot use the Members parameter together with the " + ` "MembersToInclude or MembersToExclude parameters") } - if ($Databases) + if ($Databases) { - foreach ($database in $Databases) + foreach ($database in $Databases) { if ($database.Members -and (($database.MembersToInclude) ` - -or ($database.MembersToExclude))) + -or ($database.MembersToExclude))) { throw ("Databases: Cannot use the Members parameter " + ` "together with the MembersToInclude or " + ` @@ -187,42 +213,48 @@ function Set-TargetResource if (!$database.Members ` -and !$database.MembersToInclude ` - -and !$database.MembersToExclude) + -and !$database.MembersToExclude) { throw ("Databases: At least one of the following " + ` "parameters must be specified: Members, " + ` "MembersToInclude, MembersToExclude") } } - } - else + } + else { - if (!$Members -and !$MembersToInclude -and !$MembersToExclude) + if (!$Members -and !$MembersToInclude -and !$MembersToExclude) { throw ("At least one of the following parameters must be " + ` "specified: Members, MembersToInclude, MembersToExclude") } } - if ($Databases -and $AllDatabases) + if ($Databases -and $AllDatabases) { throw ("Cannot use the Databases parameter together with the " + ` "AllDatabases parameter") } + if ($Databases -and $ExcludeDatabases) + { + throw ("Cannot use the Databases parameter together with the " + ` + "ExcludeDatabases parameter") + } + $result = Invoke-SPDSCCommand -Credential $InstallAccount ` -Arguments @($PSBoundParameters, $PSScriptRoot) ` -ScriptBlock { $params = $args[0] $scriptRoot = $args[1] - + Import-Module -Name (Join-Path -Path $scriptRoot -ChildPath "MSFT_SPShellAdmins.psm1") - try + try { $spFarm = Get-SPFarm - } - catch + } + catch { throw ("No local SharePoint farm was detected. Shell admin " + ` "settings will not be applied") @@ -230,49 +262,49 @@ function Set-TargetResource $shellAdmins = Get-SPShellAdmin - if ($params.Members) + if ($params.Members) { Write-Verbose -Message "Processing Members" - if ($shellAdmins) + if ($shellAdmins) { $differences = Compare-Object -ReferenceObject $shellAdmins.UserName ` -DifferenceObject $params.Members - if ($null -eq $differences) + if ($null -eq $differences) { Write-Verbose -Message ("Shell Admins group matches. No further " + ` "processing required") - } - else + } + else { Write-Verbose -Message ("Shell Admins group does not match. Perform " + ` "corrective action") - foreach ($difference in $differences) + foreach ($difference in $differences) { - if ($difference.SideIndicator -eq "=>") + if ($difference.SideIndicator -eq "=>") { $user = $difference.InputObject - try + try { Add-SPShellAdmin -UserName $user - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell " + ` "Admin permissions will not be applied. Error " + ` "details: $($_.Exception.Message)") return } - } - elseif ($difference.SideIndicator -eq "<=") + } + elseif ($difference.SideIndicator -eq "<=") { $user = $difference.InputObject - try + try { Remove-SPShellAdmin -UserName $user -Confirm:$false - } - catch + } + catch { throw ("Error while removing the Shell Admin. The Shell Admin " + ` "permissions will not be revoked. Error details: " + ` @@ -282,16 +314,16 @@ function Set-TargetResource } } } - } - else + } + else { - foreach ($member in $params.Members) + foreach ($member in $params.Members) { - try + try { Add-SPShellAdmin -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell Admin " + ` "permissions will not be applied. Error details: " + ` @@ -302,20 +334,20 @@ function Set-TargetResource } } - if ($params.MembersToInclude) + if ($params.MembersToInclude) { Write-Verbose -Message "Processing MembersToInclude" - if ($shellAdmins) + if ($shellAdmins) { - foreach ($member in $params.MembersToInclude) + foreach ($member in $params.MembersToInclude) { - if (-not $shellAdmins.UserName.Contains($member)) + if (-not $shellAdmins.UserName.Contains($member)) { - try + try { Add-SPShellAdmin -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell Admin " + ` "permissions will not be applied. Error details: " + ` @@ -324,16 +356,16 @@ function Set-TargetResource } } } - } - else + } + else { - foreach ($member in $params.MembersToInclude) + foreach ($member in $params.MembersToInclude) { - try + try { Add-SPShellAdmin -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell Admin " + ` "permissions will not be applied. Error details: $($_.Exception.Message)") @@ -343,20 +375,20 @@ function Set-TargetResource } } - if ($params.MembersToExclude) + if ($params.MembersToExclude) { Write-Verbose -Message "Processing MembersToExclude" - if ($shellAdmins) + if ($shellAdmins) { - foreach ($member in $params.MembersToExclude) + foreach ($member in $params.MembersToExclude) { - if ($shellAdmins.UserName.Contains($member)) + if ($shellAdmins.UserName.Contains($member)) { - try + try { Remove-SPShellAdmin -UserName $member -Confirm:$false - } - catch + } + catch { throw ("Error while removing the Shell Admin. The Shell Admin " + ` "permissions will not be revoked. Error details: " + ` @@ -368,58 +400,58 @@ function Set-TargetResource } } - if ($params.Databases) + if ($params.Databases) { Write-Verbose -Message "Processing Databases parameter" # The Databases parameter is set # Compare the configuration against the actual set and correct any issues - foreach ($database in $params.Databases) + foreach ($database in $params.Databases) { # Check if configured database exists, throw error if not Write-Verbose -Message "Processing Database: $($database.Name)" $currentCDB = Get-SPDatabase | Where-Object -FilterScript { - $_.Name -eq $database.Name + $_.Name -eq $database.Name } - if ($null -ne $currentCDB) + if ($null -ne $currentCDB) { $dbShellAdmins = Get-SPShellAdmin -database $currentCDB.Id - if ($database.Members) + if ($database.Members) { Write-Verbose -Message "Processing Members" - if ($dbShellAdmins) + if ($dbShellAdmins) { $differences = Compare-Object -ReferenceObject $database.Members ` -DifferenceObject $dbShellAdmins.UserName - foreach ($difference in $differences) + foreach ($difference in $differences) { - if ($difference.SideIndicator -eq "<=") + if ($difference.SideIndicator -eq "<=") { $user = $difference.InputObject - try + try { Add-SPShellAdmin -database $currentCDB.Id -UserName $user - } - catch + } + catch { throw ("Error while setting the Shell Admin. The " + ` "Shell Admin permissions will not be applied. " + ` "Error details: $($_.Exception.Message)") return } - } - elseif ($difference.SideIndicator -eq "=>") + } + elseif ($difference.SideIndicator -eq "=>") { $user = $difference.InputObject - try + try { Remove-SPShellAdmin -Database $currentCDB.Id ` -UserName $user ` -Confirm:$false - } - catch + } + catch { throw ("Error while removing the Shell Admin. The " + ` "Shell Admin permissions will not be revoked. " + ` @@ -428,16 +460,16 @@ function Set-TargetResource } } } - } - else + } + else { - foreach ($member in $database.Members) + foreach ($member in $database.Members) { - try + try { Add-SPShellAdmin -database $currentCDB.Id -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell " + ` "Admin permissions will not be applied. Error " + ` @@ -448,20 +480,20 @@ function Set-TargetResource } } - if ($database.MembersToInclude) + if ($database.MembersToInclude) { Write-Verbose -Message "Processing MembersToInclude" - if ($dbShellAdmins) + if ($dbShellAdmins) { - foreach ($member in $database.MembersToInclude) + foreach ($member in $database.MembersToInclude) { - if (-not $dbShellAdmins.UserName.Contains($member)) + if (-not $dbShellAdmins.UserName.Contains($member)) { - try + try { Add-SPShellAdmin -database $currentCDB.Id -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The " + ` "Shell Admin permissions will not be applied. " + ` @@ -470,16 +502,16 @@ function Set-TargetResource } } } - } - else + } + else { - foreach ($member in $database.MembersToInclude) + foreach ($member in $database.MembersToInclude) { - try + try { Add-SPShellAdmin -database $currentCDB.Id -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell " + ` "Admin permissions will not be applied. Error " + ` @@ -490,22 +522,22 @@ function Set-TargetResource } } - if ($database.MembersToExclude) + if ($database.MembersToExclude) { Write-Verbose -Message "Processing MembersToExclude" - if ($dbShellAdmins) + if ($dbShellAdmins) { - foreach ($member in $database.MembersToExclude) + foreach ($member in $database.MembersToExclude) { - if ($dbShellAdmins.UserName.Contains($member)) + if ($dbShellAdmins.UserName.Contains($member)) { - try + try { Remove-SPShellAdmin -Database $currentCDB.Id ` -UserName $member ` -Confirm:$false - } - catch + } + catch { throw ("Error while removing the Shell Admin. The " + ` "Shell Admin permissions will not be revoked. " + ` @@ -516,66 +548,73 @@ function Set-TargetResource } } } - } - else + } + else { throw "Specified database does not exist: $($database.Name)" } } } - if ($params.AllDatabases) + if ($params.AllDatabases) { Write-Verbose -Message "Processing AllDatabases parameter" - foreach ($database in (Get-SPDatabase)) + $databases = Get-SPDatabase + if ($params.ContainsKey("ExcludeDatabases")) + { + $databases = $databases | Where-Object -FilterScript { + $_.Name -notin $params.ExcludeDatabases + } + } + foreach ($database in $databases) { $dbShellAdmins = Get-SPShellAdmin -database $database.Id - if ($params.Members) + if ($params.Members) { Write-Verbose -Message "Processing Database: $($database.Name)" - if ($dbShellAdmins) + if ($dbShellAdmins) { $differences = Compare-Object -ReferenceObject $dbShellAdmins.UserName ` -DifferenceObject $params.Members - if ($null -eq $differences) + if ($null -eq $differences) { Write-Verbose -Message ("Shell Admins group matches. No further " + ` "processing required") - } - else + } + else { Write-Verbose -Message ("Shell Admins group does not match. Perform " + ` "corrective action") - foreach ($difference in $differences) + foreach ($difference in $differences) { - if ($difference.SideIndicator -eq "=>") + if ($difference.SideIndicator -eq "=>") { $user = $difference.InputObject - try + try { Add-SPShellAdmin -database $database.Id -UserName $user - } - catch + } + catch { throw ("Error while setting the Shell Admin. The " + ` "Shell Admin permissions will not be applied. " + ` "Error details: $($_.Exception.Message)") return } - } - elseif ($difference.SideIndicator -eq "<=") + } + elseif ($difference.SideIndicator -eq "<=") { $user = $difference.InputObject - try + try { Remove-SPShellAdmin -Database $database.Id ` -UserName $user ` -Confirm:$false } - catch + catch { throw ("Error while removing the Shell Admin. The " + ` "Shell Admin permissions will not be revoked. " + ` @@ -585,16 +624,16 @@ function Set-TargetResource } } } - } - else + } + else { - foreach ($member in $params.Members) + foreach ($member in $params.Members) { - try + try { Add-SPShellAdmin -database $database.Id -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell Admin " + ` "permissions will not be applied. Error details: " + ` @@ -605,19 +644,19 @@ function Set-TargetResource } } - if ($params.MembersToInclude) + if ($params.MembersToInclude) { - if ($dbShellAdmins) + if ($dbShellAdmins) { - foreach ($member in $params.MembersToInclude) + foreach ($member in $params.MembersToInclude) { - if (-not $dbShellAdmins.UserName.Contains($member)) + if (-not $dbShellAdmins.UserName.Contains($member)) { - try + try { Add-SPShellAdmin -database $database.Id -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell " + ` "Admin permissions will not be applied. Error " + ` @@ -626,16 +665,16 @@ function Set-TargetResource } } } - } - else + } + else { - foreach ($member in $params.MembersToInclude) + foreach ($member in $params.MembersToInclude) { - try + try { Add-SPShellAdmin -database $database.Id -UserName $member - } - catch + } + catch { throw ("Error while setting the Shell Admin. The Shell Admin " + ` "permissions will not be applied. Error details: " + ` @@ -647,21 +686,21 @@ function Set-TargetResource } } - if ($params.MembersToExclude) + if ($params.MembersToExclude) { - if ($dbShellAdmins) + if ($dbShellAdmins) { - foreach ($member in $params.MembersToExclude) + foreach ($member in $params.MembersToExclude) { - if ($dbShellAdmins.UserName.Contains($member)) + if ($dbShellAdmins.UserName.Contains($member)) { - try + try { Remove-SPShellAdmin -Database $database.Id ` -UserName $member ` -Confirm:$false - } - catch + } + catch { throw ("Error while removing the Shell Admin. The Shell " + ` "Admin permissions will not be revoked. Error " + ` @@ -672,7 +711,7 @@ function Set-TargetResource } } } - } + } } } } @@ -683,7 +722,7 @@ function Test-TargetResource [OutputType([System.Boolean])] param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $Name, @@ -700,7 +739,7 @@ function Test-TargetResource $MembersToExclude, [Parameter()] - [Microsoft.Management.Infrastructure.CimInstance[]] + [Microsoft.Management.Infrastructure.CimInstance[]] $Databases, [Parameter()] @@ -708,7 +747,11 @@ function Test-TargetResource $AllDatabases, [Parameter()] - [System.Management.Automation.PSCredential] + [System.String[]] + $ExcludeDatabases, + + [Parameter()] + [System.Management.Automation.PSCredential] $InstallAccount ) @@ -717,140 +760,140 @@ function Test-TargetResource # Start checking $CurrentValues = Get-TargetResource @PSBoundParameters - if ($null -eq $CurrentValues) + if ($null -eq $CurrentValues.Name) { - return $false + return $false } - if ($Members) + if ($Members) { Write-Verbose -Message "Processing Members parameter" - if (-not $CurrentValues.Members) + if (-not $CurrentValues.Members) { - return $false + return $false } $differences = Compare-Object -ReferenceObject $CurrentValues.Members ` -DifferenceObject $Members - if ($null -eq $differences) + if ($null -eq $differences) { Write-Verbose -Message "Shell Admins group matches" - } - else + } + else { Write-Verbose -Message "Shell Admins group does not match" return $false } } - if ($MembersToInclude) + if ($MembersToInclude) { Write-Verbose -Message "Processing MembersToInclude parameter" - if (-not $CurrentValues.Members) + if (-not $CurrentValues.Members) { - return $false + return $false } - foreach ($member in $MembersToInclude) + foreach ($member in $MembersToInclude) { - if (-not($CurrentValues.Members.Contains($member))) + if (-not($CurrentValues.Members.Contains($member))) { Write-Verbose -Message "$member is not a Shell Admin. Set result to false" return $false - } - else + } + else { Write-Verbose -Message "$member is already a Shell Admin. Skipping" } } } - if ($MembersToExclude) + if ($MembersToExclude) { Write-Verbose -Message "Processing MembersToExclude parameter" - if ($CurrentValues.Members) + if ($CurrentValues.Members) { - foreach ($member in $MembersToExclude) + foreach ($member in $MembersToExclude) { - if ($CurrentValues.Members.Contains($member)) + if ($CurrentValues.Members.Contains($member)) { Write-Verbose -Message "$member is a Shell Admin. Set result to false" return $false - } - else + } + else { Write-Verbose -Message "$member is not a Shell Admin. Skipping" } } } } - - if ($AllDatabases) + + if ($AllDatabases) { # The AllDatabases parameter is set # Check the Members group against all databases Write-Verbose -Message "Processing AllDatabases parameter" - foreach ($database in $CurrentValues.Databases) + foreach ($database in $CurrentValues.Databases) { # Check if configured database exists, throw error if not Write-Verbose -Message "Processing Database: $($database.Name)" - if ($Members) + if ($Members) { - if (-not $database.Members) + if (-not $database.Members) { - return $false + return $false } $differences = Compare-Object -ReferenceObject $database.Members ` -DifferenceObject $Members - if ($null -eq $differences) + if ($null -eq $differences) { Write-Verbose -Message "Shell Admins group matches" - } - else + } + else { Write-Verbose -Message "Shell Admins group does not match" return $false } } - if ($MembersToInclude) + if ($MembersToInclude) { if (-not $database.Members) { - return $false + return $false } - foreach ($member in $MembersToInclude) + foreach ($member in $MembersToInclude) { - if (-not($database.Members.Contains($member))) + if (-not($database.Members.Contains($member))) { Write-Verbose -Message "$member is not a Shell Admin. Set result to false" return $false - } - else + } + else { Write-Verbose -Message "$member is already a Shell Admin. Skipping" } } } - if ($MembersToExclude) + if ($MembersToExclude) { - if ($database.Members) + if ($database.Members) { - foreach ($member in $MembersToExclude) + foreach ($member in $MembersToExclude) { - if ($database.Members.Contains($member)) + if ($database.Members.Contains($member)) { Write-Verbose -Message "$member is a Shell Admin. Set result to false" return $false - } - else + } + else { Write-Verbose -Message "$member is not a Shell Admin. Skipping" } @@ -860,88 +903,88 @@ function Test-TargetResource } } - if ($Databases) + if ($Databases) { # The Databases parameter is set # Compare the configuration against the actual set Write-Verbose -Message "Processing Databases parameter" - foreach ($database in $Databases) + foreach ($database in $Databases) { # Check if configured database exists, throw error if not Write-Verbose -Message "Processing Database: $($database.Name)" $currentCDB = $CurrentValues.Databases | Where-Object -FilterScript { - $_.Name -eq $database.Name + $_.Name -eq $database.Name } - - if ($null -ne $currentCDB) + + if ($null -ne $currentCDB) { - if ($database.Members) + if ($database.Members) { Write-Verbose -Message "Processing Members parameter" - if (-not $currentCDB.Members) + if (-not $currentCDB.Members) { - return $false + return $false } $differences = Compare-Object -ReferenceObject $currentCDB.Members ` -DifferenceObject $database.Members - if ($null -eq $differences) + if ($null -eq $differences) { Write-Verbose -Message "Shell Admins group matches" - } - else + } + else { Write-Verbose -Message "Shell Admins group does not match" return $false } } - if ($database.MembersToInclude) + if ($database.MembersToInclude) { Write-Verbose -Message "Processing MembersToInclude parameter" - if (-not $currentCDB.Members) + if (-not $currentCDB.Members) { - return $false + return $false } - foreach ($member in $database.MembersToInclude) + foreach ($member in $database.MembersToInclude) { - if (-not($currentCDB.Members.Contains($member))) + if (-not($currentCDB.Members.Contains($member))) { Write-Verbose -Message "$member is not a Shell Admin. Set result to false" return $false - } - else + } + else { Write-Verbose -Message "$member is already a Shell Admin. Skipping" } } } - if ($database.MembersToExclude) + if ($database.MembersToExclude) { Write-Verbose -Message "Processing MembersToExclude parameter" - if ($currentCDB.Members) + if ($currentCDB.Members) { - foreach ($member in $database.MembersToExclude) + foreach ($member in $database.MembersToExclude) { - if ($currentCDB.Members.Contains($member)) + if ($currentCDB.Members.Contains($member)) { Write-Verbose -Message "$member is a Shell Admin. Set result to false" return $false - } - else + } + else { Write-Verbose -Message "$member is not a Shell Admin. Skipping" } } } } - } - else + } + else { throw "Specified database does not exist: $($database.Name)" } diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.schema.mof b/Modules/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.schema.mof index ce60d6631..ad4d630ba 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.schema.mof +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPShellAdmins/MSFT_SPShellAdmins.schema.mof @@ -15,6 +15,7 @@ class MSFT_SPShellAdmins : OMI_BaseResource [Write, Description("List of all accounts that are not allowed to have Shell Admin permissions")] String MembersToExclude[]; [Write, Description("Shell Admin configuration of Databases"), EmbeddedInstance("MSFT_SPDatabasePermissions")] String Databases[]; [Write, Description("Specify if all databases must get the same config as the general config")] Boolean AllDatabases; + [Write, Description("Specify all databases that must be excluded from AllDatabases")] String ExcludeDatabases[]; [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/Modules/SharePointDsc/Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 b/Modules/SharePointDsc/Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 new file mode 100644 index 000000000..a815f6012 --- /dev/null +++ b/Modules/SharePointDsc/Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 @@ -0,0 +1,25 @@ +<# +.EXAMPLE + This example gives admin access to the specified users for the local farm as well as + all content databases in the local farm. +#> + + Configuration Example + { + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + Import-DscResource -ModuleName SharePointDsc + + node localhost { + SPShellAdmins ShellAdmins + { + Name = "Shell Admins" + Members = "CONTOSO\user1", "CONTOSO\user2" + AllDatabases = $true + ExcludeDatabases = "WSS_Content_Portal" + } + } + } diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPShellAdmins.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPShellAdmins.Tests.ps1 index f9930f436..3fdb48fef 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPShellAdmins.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPShellAdmins.Tests.ps1 @@ -1,7 +1,7 @@ [CmdletBinding()] param( [Parameter()] - [string] + [string] $SharePointCmdletModule = (Join-Path -Path $PSScriptRoot ` -ChildPath "..\Stubs\SharePoint\15.0.4805.1000\Microsoft.SharePoint.PowerShell.psm1" ` -Resolve) @@ -18,7 +18,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { InModuleScope -ModuleName $Global:SPDscHelper.ModuleName -ScriptBlock { Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope - # Mocks for all contexts + # Mocks for all contexts Mock -CommandName Add-SPShellAdmin -MockWith {} Mock -CommandName Remove-SPShellAdmin -MockWith {} @@ -29,12 +29,12 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Members = "contoso\user1", "contoso\user2" } - Mock -CommandName Get-SPFarm -MockWith { - throw "Unable to detect local farm" + Mock -CommandName Get-SPFarm -MockWith { + throw "Unable to detect local farm" } It "Should return null from the get method" { - Get-TargetResource @testParams | Should Be $null + (Get-TargetResource @testParams).Name | Should BeNullOrEmpty } It "Should return false from the test method" { @@ -46,7 +46,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } - Context -Name "ContentDatabases and AllContentDatabases parameters used simultaniously" -Fixture { + Context -Name "ContentDatabases and AllContentDatabases parameters used simultaneously" -Fixture { $testParams = @{ Name = "ShellAdmins" Members = "contoso\user1", "contoso\user2" @@ -60,7 +60,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should return null from the get method" { - Get-TargetResource @testParams | Should BeNullOrEmpty + (Get-TargetResource @testParams).Name | Should BeNullOrEmpty } It "Should return false from the test method" { @@ -71,8 +71,8 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { { Set-TargetResource @testParams } | Should throw "Cannot use the Databases parameter together with the AllDatabases parameter" } } - - Context -Name "Members and MembersToInclude parameters used simultaniously - General permissions" -Fixture { + + Context -Name "Members and MembersToInclude parameters used simultaneously - General permissions" -Fixture { $testParams = @{ Name = "ShellAdmins" Members = "contoso\user1", "contoso\user2" @@ -80,7 +80,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should return null from the get method" { - Get-TargetResource @testParams | Should Be $null + (Get-TargetResource @testParams).Name | Should BeNullOrEmpty } It "Should return false from the test method" { @@ -98,7 +98,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should return null from the get method" { - Get-TargetResource @testParams | Should Be $null + (Get-TargetResource @testParams).Name | Should BeNullOrEmpty } It "Should return false from the test method" { @@ -110,7 +110,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } - Context -Name "Members and MembersToInclude parameters used simultaniously - Database permissions" -Fixture { + Context -Name "Members and MembersToInclude parameters used simultaneously - Database permissions" -Fixture { $testParams = @{ Name = "ShellAdmins" Databases = @( @@ -123,7 +123,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should return null from the get method" { - Get-TargetResource @testParams | Should Be $null + (Get-TargetResource @testParams).Name | Should BeNullOrEmpty } It "Should return false from the test method" { @@ -135,6 +135,31 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } + Context -Name "Databases and ExcludeDatabases parameters used simultaneously" -Fixture { + $testParams = @{ + Name = "ShellAdmins" + Databases = @( + (New-CimInstance -ClassName MSFT_SPDatabasePermissions -Property @{ + Name = "SharePoint_Content_Contoso1" + Members = "contoso\user1", "contoso\user2" + } -ClientOnly) + ) + ExcludeDatabases = "SharePoint_Content_Contoso2" + } + + It "Should return null from the get method" { + (Get-TargetResource @testParams).Name | Should BeNullOrEmpty + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should Be $false + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should throw "Cannot use the Databases parameter together with the ExcludeDatabases parameter" + } + } + Context -Name "None of the Members, MembersToInclude and MembersToExclude parameters are used - Database permissions" -Fixture { $testParams = @{ Name = "ShellAdmins" @@ -146,7 +171,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should return null from the get method" { - Get-TargetResource @testParams | Should Be $null + (Get-TargetResource @testParams).Name | Should BeNullOrEmpty } It "Should return false from the test method" { @@ -203,18 +228,18 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions - return @{ - UserName = "contoso\user3","contoso\user4" + return @{ + UserName = "contoso\user1","contoso\user2" } - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } @@ -237,36 +262,31 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should return false from the test method" { - Test-TargetResource @testParams | Should Be $false - } - - It "Should throw an exception in the set method" { - Set-TargetResource @testParams - Assert-MockCalled Add-SPShellAdmin - Assert-MockCalled Remove-SPShellAdmin + Test-TargetResource @testParams | Should Be $true } } - Context -Name "AllDatabases parameter is used and permissions do not match" -Fixture { + Context -Name "AllDatabases parameter is used with ExcludeDatabases and permissions do not match" -Fixture { $testParams = @{ Name = "ShellAdmins" Members = "contoso\user1", "contoso\user2" - AllDatabases = $true + AllDatabases = $true + ExcludeDatabases = "SharePoint_Content_Contoso3" } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user3","contoso\user4" } - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } @@ -280,6 +300,10 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { @{ Name = "SharePoint_Content_Contoso2" Id = "936DA01F-9ABD-4d9d-80C7-02AF85C822A8" + }, + @{ + Name = "SharePoint_Content_Contoso3" + Id = "936DA01F-9ABD-4d9d-80C7-02AF85C822A9" } ) } @@ -289,7 +313,13 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } It "Should return false from the test method" { - Test-TargetResource @testParams | Should Be $true + Test-TargetResource @testParams | Should Be $false + } + + It "Should throw an exception in the set method" { + Set-TargetResource @testParams + Assert-MockCalled Add-SPShellAdmin + Assert-MockCalled Remove-SPShellAdmin } } @@ -300,12 +330,12 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions return @{} - } - else + } + else { # Database parameter not used, return general permissions return @{ UserName = "contoso\user3","contoso\user4" } @@ -334,16 +364,16 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions return @{} - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1", "contoso\user2" + return @{ + UserName = "contoso\user1", "contoso\user2" } } } @@ -371,20 +401,20 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } -ClientOnly) ) } - + Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions - return @{ - UserName = "contoso\user3","contoso\user4" + return @{ + UserName = "contoso\user3","contoso\user4" } - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } @@ -433,18 +463,18 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } @@ -478,16 +508,16 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions return @{} - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user3","contoso\user4" + return @{ + UserName = "contoso\user3","contoso\user4" } } } @@ -513,16 +543,16 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions return @{} - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1", "contoso\user2", "contoso\user3" + return @{ + UserName = "contoso\user1", "contoso\user2", "contoso\user3" } } } @@ -552,18 +582,18 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions - return @{ - UserName = "contoso\user3","contoso\user4" + return @{ + UserName = "contoso\user3","contoso\user4" } - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } @@ -580,7 +610,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } ) } - + It "Should return null from the get method" { Get-TargetResource @testParams | Should Not BeNullOrEmpty } @@ -611,18 +641,18 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions - return @{ - UserName = "contoso\user1","contoso\user2", "contoso\user3" + return @{ + UserName = "contoso\user1","contoso\user2", "contoso\user3" } - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } @@ -656,16 +686,16 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions return @{} } - else + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } @@ -691,16 +721,16 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions return @{} - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user3", "contoso\user4" + return @{ + UserName = "contoso\user3", "contoso\user4" } } } @@ -730,18 +760,18 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } @@ -789,18 +819,18 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPShellAdmin -MockWith { - if ($database) + if ($database) { # Database parameter used, return database permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } - } - else + } + else { # Database parameter not used, return general permissions - return @{ - UserName = "contoso\user1","contoso\user2" + return @{ + UserName = "contoso\user1","contoso\user2" } } } From b5bcd7cf9d14f452b30b2af1b1ef2ddca81adafc Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Thu, 30 Aug 2018 20:18:32 +0200 Subject: [PATCH 18/23] Incorporated review comments --- .../DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 | 4 ++-- .../Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 index b514f22a0..5c39bb5c3 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPAppCatalog/MSFT_SPAppCatalog.psm1 @@ -119,7 +119,7 @@ function Set-TargetResource Clear-SPDscKerberosToken -Account $farmAccount.UserName } - Invoke-SPDSCCommand -Credential $FarmAccount ` + Invoke-SPDSCCommand -Credential $farmAccount ` -Arguments $PSBoundParameters ` -ScriptBlock { $params = $args[0] @@ -135,7 +135,7 @@ function Set-TargetResource } } | Out-Null - # Remove the InstallAccount from the local Administrators group, if it was added above + # Remove the FarmAccount from the local Administrators group, if it was added above if (!$isLocalAdmin) { Write-Verbose -Message "Removing farm account from Local Administrators group" diff --git a/Modules/SharePointDsc/Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 b/Modules/SharePointDsc/Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 index a815f6012..06a016404 100644 --- a/Modules/SharePointDsc/Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 +++ b/Modules/SharePointDsc/Examples/Resources/SPShellAdmins/3-ExcludeDatabases.ps1 @@ -1,7 +1,8 @@ <# .EXAMPLE - This example gives admin access to the specified users for the local farm as well as - all content databases in the local farm. + This example gives admin access to the specified users for the local farm as + well as all content databases in the local farm, with the exception of database + WSS_Content_Portal. #> Configuration Example From d1efbccdb345fb8e31f1cac18fa204bdc2ef435d Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 31 Aug 2018 15:01:21 +0200 Subject: [PATCH 19/23] Added new resource SPSiteUrl #808 --- CHANGELOG.md | 2 + .../MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 | 305 ++++++++++++++++++ .../MSFT_SPSiteUrl/MSFT_SPSiteUrl.schema.mof | 11 + .../DSCResources/MSFT_SPSiteUrl/readme.md | 15 + .../Resources/SPSiteUrl/1-Example.ps1 | 25 ++ .../SharePointDsc.SPSiteUrl.Tests.ps1 | 254 +++++++++++++++ 6 files changed, 612 insertions(+) create mode 100644 Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 create mode 100644 Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.schema.mof create mode 100644 Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/readme.md create mode 100644 Modules/SharePointDsc/Examples/Resources/SPSiteUrl/1-Example.ps1 create mode 100644 Tests/Unit/SharePointDsc/SharePointDsc.SPSiteUrl.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f1939d00..065a38e81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ * SPSearchServiceApp * Updated Set method to check if service application pool exists. Resource will throw an error if it does not exist +* SPSiteUrl + * New resource to manage site collection urls for host named site collections * SPRemoteFarmTrust * Updated readme.md file to add a link that was lost during earlier updates * SPSearchTopology diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 new file mode 100644 index 000000000..11fb3fcb5 --- /dev/null +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 @@ -0,0 +1,305 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Url, + + [Parameter()] + [System.String] + $Intranet, + + [Parameter()] + [System.String] + $Internet, + + [Parameter()] + [System.String] + $Extranet, + + [Parameter()] + [System.String] + $Custom, + + [Parameter()] + [System.Management.Automation.PSCredential] + $InstallAccount + ) + + Write-Verbose -Message "Getting site collection url for $Url" + + if ($PSBoundParameters.ContainsKey("Intranet") -eq $false -and + $PSBoundParameters.ContainsKey("Internet") -eq $false -and + $PSBoundParameters.ContainsKey("Extranet") -eq $false -and + $PSBoundParameters.ContainsKey("Custom") -eq $false) + { + Write-Verbose -Message "No zone is specified" + } + + $result = Invoke-SPDSCCommand -Credential $InstallAccount ` + -Arguments $PSBoundParameters ` + -ScriptBlock { + $params = $args[0] + + $nullreturn = @{ + Url = $params.Url + } + + $site = Get-SPSite -Identity $params.Url ` + -ErrorAction SilentlyContinue + + if ($null -eq $site) + { + Write-Verbose -Message "Specified site $($params.Url) does not exist" + return $nullreturn + } + + if ($site.HostHeaderIsSiteName -eq $false) + { + Write-Verbose -Message ("Specified site $($params.Url) is not a Host Named " + ` + "Site Collection") + return $nullreturn + } + + $intranetUrl = $null + $internetUrl = $null + $extranetUrl = $null + $customUrl = $null + + $siteurls = Get-SPSiteUrl -Identity $params.Url + foreach ($siteurl in $siteurls) + { + switch ($siteurl.Zone) + { + "Default" + { + Write-Verbose -Message "SiteUrl for Default zone is $($siteurl.Url)" + } + "Intranet" + { + Write-Verbose -Message "SiteUrl for Intranet zone is $($siteurl.Url)" + $intranetUrl = $siteurl.Url + } + "Internet" + { + Write-Verbose -Message "SiteUrl for Internet zone is $($siteurl.Url)" + $internetUrl = $siteurl.Url + } + "Extranet" + { + Write-Verbose -Message "SiteUrl for Extranet zone is $($siteurl.Url)" + $extranetUrl = $siteurl.Url + } + "Custom" + { + Write-Verbose -Message "SiteUrl for Custom zone is $($siteurl.Url)" + $customUrl = $siteurl.Url + } + } + } + return @{ + Url = $params.Url + Intranet = $intranetUrl + Internet = $internetUrl + Extranet = $extranetUrl + Custom = $customUrl + InstallAccount = $params.InstallAccount + } + } + return $result +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Url, + + [Parameter()] + [System.String] + $Intranet, + + [Parameter()] + [System.String] + $Internet, + + [Parameter()] + [System.String] + $Extranet, + + [Parameter()] + [System.String] + $Custom, + + [Parameter()] + [System.Management.Automation.PSCredential] + $InstallAccount + ) + + Write-Verbose -Message "Setting site collection url for $Url" + + if ($PSBoundParameters.ContainsKey("Intranet") -eq $false -and + $PSBoundParameters.ContainsKey("Internet") -eq $false -and + $PSBoundParameters.ContainsKey("Extranet") -eq $false -and + $PSBoundParameters.ContainsKey("Custom") -eq $false) + { + throw "No zone specified. Please specify a zone" + } + + Invoke-SPDSCCommand -Credential $InstallAccount ` + -Arguments $PSBoundParameters ` + -ScriptBlock { + $params = $args[0] + + $site = Get-SPSite -Identity $params.Url ` + -ErrorAction SilentlyContinue + + if ($null -eq $site) + { + throw "Specified site $($params.Url) does not exist" + } + + if ($site.HostHeaderIsSiteName -eq $false) + { + throw "Specified site $($params.Url) is not a Host Named Site Collection" + } + + $siteurls = Get-SPSiteUrl -Identity $params.Url + foreach ($siteurl in $siteurls) + { + switch ($siteurl.Zone) + { + "Default" + { + Write-Verbose -Message "SiteUrl for Default zone is $($siteurl.Url)" + } + "Intranet" + { + Write-Verbose -Message "SiteUrl for Intranet zone is $($siteurl.Url)" + if ($params.Intranet -ne $siteurl.Url) + { + Remove-SPSiteUrl -Url $siteurl.Url + } + } + "Internet" + { + Write-Verbose -Message "SiteUrl for Internet zone is $($siteurl.Url)" + if ($params.Internet -ne $siteurl.Url) + { + Remove-SPSiteUrl -Url $siteurl.Url + } + } + "Extranet" + { + Write-Verbose -Message "SiteUrl for Extranet zone is $($siteurl.Url)" + if ($params.Extranet -ne $siteurl.Url) + { + Remove-SPSiteUrl -Url $siteurl.Url + } + } + "Custom" + { + Write-Verbose -Message "SiteUrl for Custom zone is $($siteurl.Url)" + if ($params.Custom -ne $siteurl.Url) + { + Remove-SPSiteUrl -Url $siteurl.Url + } + } + } + } + + if ($null -ne $params.Intranet) + { + Set-SPSiteUrl -Identity $params.Url -Zone Intranet -Url $params.Intranet + } + + if ($null -ne $params.Internet) + { + Set-SPSiteUrl -Identity $params.Url -Zone Internet -Url $params.Internet + } + + if ($null -ne $params.Extranet) + { + Set-SPSiteUrl -Identity $params.Url -Zone Extranet -Url $params.Extranet + } + + if ($null -ne $params.Custom) + { + Set-SPSiteUrl -Identity $params.Url -Zone Custom -Url $params.Custom + } + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Url, + + [Parameter()] + [System.String] + $Intranet, + + [Parameter()] + [System.String] + $Internet, + + [Parameter()] + [System.String] + $Extranet, + + [Parameter()] + [System.String] + $Custom, + + [Parameter()] + [System.Management.Automation.PSCredential] + $InstallAccount + ) + + Write-Verbose -Message "Testing site collection url for $Url" + + $CurrentValues = Get-TargetResource @PSBoundParameters + + if ($null -eq $CurrentValues.Intranet -and + $null -eq $CurrentValues.Internet -and + $null -eq $CurrentValues.Extranet -and + $null -eq $CurrentValues.Custom) + { + return $false + } + + if ([String]$CurrentValues.Intranet -ne $Intranet) + { + return $false + } + + if ([String]$CurrentValues.Internet -ne $Internet) + { + return $false + } + + if ([String]$CurrentValues.Extranet -ne $Extranet) + { + return $false + } + + if ([String]$CurrentValues.Custom -ne $Custom) + { + return $false + } + + return $true +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.schema.mof b/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.schema.mof new file mode 100644 index 000000000..99073b701 --- /dev/null +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.schema.mof @@ -0,0 +1,11 @@ +[ClassVersion("1.0.0.0"), FriendlyName("SPSiteUrl")] +class MSFT_SPSiteUrl : OMI_BaseResource +{ + [Key, Description("The URL of the site collection")] string Url; + [Write, Description("The URL of the Intranet zone")] string Intranet; + [Write, Description("The URL of the Internet zone")] string Internet; + [Write, Description("The URL of the Extranet zone")] string Extranet; + [Write, Description("The URL of the Custom zone")] string Custom; + [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/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/readme.md b/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/readme.md new file mode 100644 index 000000000..b9c9af3e7 --- /dev/null +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/readme.md @@ -0,0 +1,15 @@ +# Description + +**Type:** Distributed + +This resource will configure the site url for a host named site collection. +There are four available zones to configure: Intranet, Internet, Extranet +and Custom. + +It is not possible to change the site url for the Default zone, since this +means changing the url that is used as identity. A site collection rename +is required for that: +$site = Get-SPSite "http://old.contoso.com" +$new = "http://new.contoso.com" +$site.Rename($new) +((Get-SPSite $new).contentdatabase).RefreshSitesInConfigurationDatabase diff --git a/Modules/SharePointDsc/Examples/Resources/SPSiteUrl/1-Example.ps1 b/Modules/SharePointDsc/Examples/Resources/SPSiteUrl/1-Example.ps1 new file mode 100644 index 000000000..80a2bb9e2 --- /dev/null +++ b/Modules/SharePointDsc/Examples/Resources/SPSiteUrl/1-Example.ps1 @@ -0,0 +1,25 @@ +<# +.EXAMPLE + This example configures the site collection urls for the specified + Host Named Site Collection +#> + + Configuration Example + { + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + Import-DscResource -ModuleName SharePointDsc + + node localhost { + SPSiteUrl TeamSite + { + Url = "http://sharepoint.contoso.intra" + Intranet = "http://sharepoint.contoso.com" + Internet = "https://sharepoint.contoso.com" + PsDscRunAsCredential = $SetupAccount + } + } + } diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPSiteUrl.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPSiteUrl.Tests.ps1 new file mode 100644 index 000000000..0a1f46f78 --- /dev/null +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPSiteUrl.Tests.ps1 @@ -0,0 +1,254 @@ +[CmdletBinding()] +param( + [Parameter()] + [string] + $SharePointCmdletModule = (Join-Path -Path $PSScriptRoot ` + -ChildPath "..\Stubs\SharePoint\15.0.4805.1000\Microsoft.SharePoint.PowerShell.psm1" ` + -Resolve) +) + +Import-Module -Name (Join-Path -Path $PSScriptRoot ` + -ChildPath "..\UnitTestHelper.psm1" ` + -Resolve) + +$Global:SPDscHelper = New-SPDscUnitTestHelper -SharePointStubModule $SharePointCmdletModule ` + -DscResource "SPSiteUrl" + +Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:SPDscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope + + # Mocks for all contexts + Mock -CommandName Remove-SPSiteUrl -MockWith { } + Mock -CommandName Set-SPSiteUrl -MockWith { } + Mock -CommandName Get-SPSiteUrl -MockWith { + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + }, + @{ + Url = "http://sharepoint.contoso.com" + Zone = "Intranet" + }, + @{ + Url = "https://sharepoint.contoso.com" + Zone = "Internet" + } + ) + } + + # Test contexts + Context -Name "No zones specified" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + } + + Mock -CommandName Get-SPSite -MockWith { return $null } + + It "Should return null for Intranet zone from the get method" { + (Get-TargetResource @testParams).Intranet | Should BeNullOrEmpty + } + + It "Should create a new site from the set method" { + { Set-TargetResource @testParams } | Should Throw "No zone specified. Please specify a zone" + } + } + + Context -Name "The site collection does not exist" -Fixture { + $testParams = @{ + Url = "http://site.sharepoint.com" + Intranet = "http://sharepoint.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return $null + } + + It "Should return null for Intranet zone from the get method" { + (Get-TargetResource @testParams).Intranet | Should BeNullOrEmpty + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should Be $false + } + + It "Should return true from the test method" { + { Set-TargetResource @testParams } | Should Throw "Specified site $($testParams.Url) does not exist" + } + } + + Context -Name "The site is not a host named site collection" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Intranet = "http://sharepoint.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $false + } + } + + It "Should return null for Intranet zone from the get method" { + (Get-TargetResource @testParams).Intranet | Should BeNullOrEmpty + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should Be $false + } + + It "Should throw exception from the set method" { + { Set-TargetResource @testParams } | Should Throw "Specified site $($testParams.Url) is not a Host Named Site Collection" + } + } + + Context -Name "The site exists and the Internet zone should not be configured" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Intranet = "http://sharepoint.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + } + } + + It "Should return values for the Intranet and Internet zones from the get method" { + $result = Get-TargetResource @testParams + $result.Intranet | Should Be "http://sharepoint.contoso.com" + $result.Internet | Should Be "https://sharepoint.contoso.com" + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should Be $false + } + + It "Should configure the specified values in the set method" { + Set-TargetResource @testParams + Assert-MockCalled Remove-SPSiteUrl + } + } + + Context -Name "The site exists, but the Internet and Intranet zones are not configured" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Intranet = "http://sharepoint.contoso.com" + Internet = "http://custom.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + } + } + + Mock -CommandName Get-SPSiteUrl -MockWith { + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + }, + @{ + Url = "http://sharepoint.contoso.com" + Zone = "Extranet" + }, + @{ + Url = "https://sharepoint.contoso.com" + Zone = "Custom" + } + ) + } + + It "Should return values for the Intranet and Internet zones from the get method" { + $result = Get-TargetResource @testParams + $result.Extranet | Should Be "http://sharepoint.contoso.com" + $result.Custom | Should Be "https://sharepoint.contoso.com" + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should Be $false + } + + It "Should configure the specified values in the set method" { + Set-TargetResource @testParams + Assert-MockCalled Remove-SPSiteUrl + Assert-MockCalled Set-SPSiteUrl + } + } + + Context -Name "The site exists, but the Extranet and Custom zones are not configured" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Extranet = "http://sharepoint.contoso.com" + Custom = "http://custom.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + } + } + + Mock -CommandName Get-SPSiteUrl -MockWith { + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + }, + @{ + Url = "http://sharepoint.contoso.com" + Zone = "Intranet" + }, + @{ + Url = "https://sharepoint.contoso.com" + Zone = "Internet" + } + ) + } + + It "Should return values for the Intranet and Internet zones from the get method" { + $result = Get-TargetResource @testParams + $result.Intranet | Should Be "http://sharepoint.contoso.com" + $result.Internet | Should Be "https://sharepoint.contoso.com" + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should Be $false + } + + It "Should configure the specified values in the set method" { + Set-TargetResource @testParams + Assert-MockCalled Remove-SPSiteUrl + Assert-MockCalled Set-SPSiteUrl + } + } + + Context -Name "The site exists and all zones are configured correctly" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Intranet = "http://sharepoint.contoso.com" + Internet = "https://sharepoint.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + } + } + + It "Should return values for the Intranet and Internet zones from the get method" { + $result = Get-TargetResource @testParams + $result.Intranet | Should Be "http://sharepoint.contoso.com" + $result.Internet | Should Be "https://sharepoint.contoso.com" + } + + It "Should return true from the test method" { + Test-TargetResource @testParams | Should Be $true + } + } + } +} + +Invoke-Command -ScriptBlock $Global:SPDscHelper.CleanupScript -NoNewScope From 44644f1081530d353d5e9172300c72edcb12dbf0 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 31 Aug 2018 15:03:03 +0200 Subject: [PATCH 20/23] Corrected alphabetical order of changelog --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a6ee0d9e..52a8ac354 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,13 +14,11 @@ * Added ability to check and update CentralAdministrationPort * SPLogLevel * Added High as TraceLevel, which was not included yet +* SPRemoteFarmTrust + * Updated readme.md file to add a link that was lost during earlier updates * SPSearchServiceApp * Updated Set method to check if service application pool exists. Resource will throw an error if it does not exist -* SPSiteUrl - * New resource to manage site collection urls for host named site collections -* SPRemoteFarmTrust - * Updated readme.md file to add a link that was lost during earlier updates * SPSearchTopology * Fixed issue where Get method threw an error when the specified service application didn't exist yet @@ -29,6 +27,8 @@ * Added ExcludeDatabases parameter for AllDatabases * SPSite * Added ability to check and update QuotaTemplate, OwnerAlias and SecondaryOwnerAlias +* SPSiteUrl + * New resource to manage site collection urls for host named site collections * SPTrustedIdentityTokenIssuerProviderRealm * Fixed issue where Get method threw an error when the realm didn't exist yet * SPUserProfileServiceApp From 0975db1ab27807f588c6b1e316b77f463db0f4d7 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Fri, 31 Aug 2018 20:24:23 +0200 Subject: [PATCH 21/23] Incorporated review comments --- .../MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 | 44 +++- .../SharePointDsc.SPSiteUrl.Tests.ps1 | 219 ++++++++++++++---- 2 files changed, 218 insertions(+), 45 deletions(-) diff --git a/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 b/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 index 11fb3fcb5..ccd36f74f 100644 --- a/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 +++ b/Modules/SharePointDsc/DSCResources/MSFT_SPSiteUrl/MSFT_SPSiteUrl.psm1 @@ -216,22 +216,58 @@ function Set-TargetResource if ($null -ne $params.Intranet) { - Set-SPSiteUrl -Identity $params.Url -Zone Intranet -Url $params.Intranet + $siteurl = Get-SPSiteURL -Identity $params.Intranet -ErrorAction SilentlyContinue + if ($null -eq $siteurl) + { + Set-SPSiteUrl -Identity $params.Url -Zone Intranet -Url $params.Intranet + } + else + { + throw ("Specified URL $($params.Intranet) (Zone: Intranet) is already assigned " + ` + "to a site collection: $($siteurl[0].Url)") + } } if ($null -ne $params.Internet) { - Set-SPSiteUrl -Identity $params.Url -Zone Internet -Url $params.Internet + $siteurl = Get-SPSiteURL -Identity $params.Internet -ErrorAction SilentlyContinue + if ($null -eq $siteurl) + { + Set-SPSiteUrl -Identity $params.Url -Zone Internet -Url $params.Internet + } + else + { + throw ("Specified URL $($params.Internet) (Zone: Internet) is already assigned " + ` + "to a site collection: $($siteurl[0].Url)") + } } if ($null -ne $params.Extranet) { - Set-SPSiteUrl -Identity $params.Url -Zone Extranet -Url $params.Extranet + $siteurl = Get-SPSiteURL -Identity $params.Extranet -ErrorAction SilentlyContinue + if ($null -eq $siteurl) + { + Set-SPSiteUrl -Identity $params.Url -Zone Extranet -Url $params.Extranet + } + else + { + throw ("Specified URL $($params.Extranet) (Zone: Extranet) is already assigned " + ` + "to a site collection: $($siteurl[0].Url)") + } } if ($null -ne $params.Custom) { - Set-SPSiteUrl -Identity $params.Url -Zone Custom -Url $params.Custom + $siteurl = Get-SPSiteURL -Identity $params.Custom -ErrorAction SilentlyContinue + if ($null -eq $siteurl) + { + Set-SPSiteUrl -Identity $params.Url -Zone Custom -Url $params.Custom + } + else + { + throw ("Specified URL $($params.Custom) (Zone: Custom) is already assigned " + ` + "to a site collection: $($siteurl[0].Url)") + } } } } diff --git a/Tests/Unit/SharePointDsc/SharePointDsc.SPSiteUrl.Tests.ps1 b/Tests/Unit/SharePointDsc/SharePointDsc.SPSiteUrl.Tests.ps1 index 0a1f46f78..5b07d5b1e 100644 --- a/Tests/Unit/SharePointDsc/SharePointDsc.SPSiteUrl.Tests.ps1 +++ b/Tests/Unit/SharePointDsc/SharePointDsc.SPSiteUrl.Tests.ps1 @@ -22,21 +22,30 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Mock -CommandName Remove-SPSiteUrl -MockWith { } Mock -CommandName Set-SPSiteUrl -MockWith { } Mock -CommandName Get-SPSiteUrl -MockWith { - return @( - @{ - Url = "http://sharepoint.contoso.intra" - Zone = "Default" - }, - @{ - Url = "http://sharepoint.contoso.com" - Zone = "Intranet" - }, - @{ - Url = "https://sharepoint.contoso.com" - Zone = "Internet" - } - ) + if ($global:SpDscSPSiteUrlRanOnce -eq $false) + { + $global:SpDscSPSiteUrlRanOnce = $true + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + }, + @{ + Url = "http://sharepoint.contoso.com" + Zone = "Intranet" + }, + @{ + Url = "https://sharepoint.contoso.com" + Zone = "Internet" + } + ) + } + else + { + return $null + } } + $global:SpDscSPSiteUrlRanOnce = $false # Test contexts Context -Name "No zones specified" -Fixture { @@ -103,6 +112,111 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } + Context -Name "The site exists, but the specified Intranet is already in use" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Intranet = "http://sharepoint.contoso.com" + Internet = "http://custom.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + } + } + + Mock -CommandName Get-SPSiteUrl -MockWith { + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + } + ) + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should Throw "Specified URL $($testParams.Intranet) (Zone: Intranet) is already assigned to a site collection" + } + } + + Context -Name "The site exists, but the specified Internet is already in use" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Internet = "http://custom.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + } + } + + Mock -CommandName Get-SPSiteUrl -MockWith { + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + } + ) + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should Throw "Specified URL $($testParams.Internet) (Zone: Internet) is already assigned to a site collection" + } + } + + Context -Name "The site exists, but the specified Extranet is already in use" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Extranet = "http://sharepoint.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + } + } + + Mock -CommandName Get-SPSiteUrl -MockWith { + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + } + ) + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should Throw "Specified URL $($testParams.Extranet) (Zone: Extranet) is already assigned to a site collection" + } + } + + Context -Name "The site exists, but the specified Custom is already in use" -Fixture { + $testParams = @{ + Url = "http://sharepoint.contoso.intra" + Custom = "http://sharepoint.contoso.com" + } + + Mock -CommandName Get-SPSite -MockWith { + return @{ + HostHeaderIsSiteName = $true + } + } + + Mock -CommandName Get-SPSiteUrl -MockWith { + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + } + ) + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should Throw "Specified URL $($testParams.Custom) (Zone: Custom) is already assigned to a site collection" + } + } + Context -Name "The site exists and the Internet zone should not be configured" -Fixture { $testParams = @{ Url = "http://sharepoint.contoso.intra" @@ -125,6 +239,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Test-TargetResource @testParams | Should Be $false } + $global:SpDscSPSiteUrlRanOnce = $false It "Should configure the specified values in the set method" { Set-TargetResource @testParams Assert-MockCalled Remove-SPSiteUrl @@ -145,22 +260,31 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPSiteUrl -MockWith { - return @( - @{ - Url = "http://sharepoint.contoso.intra" - Zone = "Default" - }, - @{ - Url = "http://sharepoint.contoso.com" - Zone = "Extranet" - }, - @{ - Url = "https://sharepoint.contoso.com" - Zone = "Custom" + if ($global:SpDscSPSiteUrlRanOnce -eq $false) + { + $global:SpDscSPSiteUrlRanOnce = $true + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + }, + @{ + Url = "http://sharepoint.contoso.com" + Zone = "Extranet" + }, + @{ + Url = "https://sharepoint.contoso.com" + Zone = "Custom" + } + ) + } + else + { + return $null } - ) } + $global:SpDscSPSiteUrlRanOnce = $false It "Should return values for the Intranet and Internet zones from the get method" { $result = Get-TargetResource @testParams $result.Extranet | Should Be "http://sharepoint.contoso.com" @@ -171,6 +295,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Test-TargetResource @testParams | Should Be $false } + $global:SpDscSPSiteUrlRanOnce = $false It "Should configure the specified values in the set method" { Set-TargetResource @testParams Assert-MockCalled Remove-SPSiteUrl @@ -192,22 +317,31 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-SPSiteUrl -MockWith { - return @( - @{ - Url = "http://sharepoint.contoso.intra" - Zone = "Default" - }, - @{ - Url = "http://sharepoint.contoso.com" - Zone = "Intranet" - }, - @{ - Url = "https://sharepoint.contoso.com" - Zone = "Internet" - } - ) + if ($global:SpDscSPSiteUrlRanOnce -eq $false) + { + $global:SpDscSPSiteUrlRanOnce = $true + return @( + @{ + Url = "http://sharepoint.contoso.intra" + Zone = "Default" + }, + @{ + Url = "http://sharepoint.contoso.com" + Zone = "Intranet" + }, + @{ + Url = "https://sharepoint.contoso.com" + Zone = "Internet" + } + ) + } + else + { + return $null + } } + $global:SpDscSPSiteUrlRanOnce = $false It "Should return values for the Intranet and Internet zones from the get method" { $result = Get-TargetResource @testParams $result.Intranet | Should Be "http://sharepoint.contoso.com" @@ -218,6 +352,7 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { Test-TargetResource @testParams | Should Be $false } + $global:SpDscSPSiteUrlRanOnce = $false It "Should configure the specified values in the set method" { Set-TargetResource @testParams Assert-MockCalled Remove-SPSiteUrl @@ -238,12 +373,14 @@ Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { } } + $global:SpDscSPSiteUrlRanOnce = $false It "Should return values for the Intranet and Internet zones from the get method" { $result = Get-TargetResource @testParams $result.Intranet | Should Be "http://sharepoint.contoso.com" $result.Internet | Should Be "https://sharepoint.contoso.com" } + $global:SpDscSPSiteUrlRanOnce = $false It "Should return true from the test method" { Test-TargetResource @testParams | Should Be $true } From f5e2c7346ddb9f70cdfdef2444a47c61f3bd5969 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Mon, 3 Sep 2018 11:07:15 +0200 Subject: [PATCH 22/23] Preparations for v2.5 release --- CHANGELOG.md | 2 +- Modules/SharePointDsc/SharePointDsc.psd1 | 61 +++++++++++------------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52a8ac354..03e3bbe0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change log for SharePointDsc -## Unreleased +## 2.5 * SPAppCatalog * Updated resource to retrieve the Farm account instead of requiring it diff --git a/Modules/SharePointDsc/SharePointDsc.psd1 b/Modules/SharePointDsc/SharePointDsc.psd1 index 92d24e2e0..c3eb9f8bb 100644 --- a/Modules/SharePointDsc/SharePointDsc.psd1 +++ b/Modules/SharePointDsc/SharePointDsc.psd1 @@ -12,7 +12,7 @@ # RootModule = '' # Version number of this module. -ModuleVersion = '2.4.0.0' +ModuleVersion = '2.5.0.0' # ID used to uniquely identify this module GUID = '6c1176a0-4fac-4134-8ca2-3fa8a21a7b90' @@ -128,43 +128,40 @@ PrivateData = @{ # ReleaseNotes of this module ReleaseNotes = " - * SPCacheAccounts - * Fixed issue where the Test method would fail if SetWebAppPolicy was set to - false. - * SPDistributedCacheService - * Updated resource to allow updating the cache size + * SPAppCatalog + * Updated resource to retrieve the Farm account instead of requiring it + to be specifically used + * SPDatabaseAAG + * Updated readme.md to specify that this resource also updates the database + connection string + * SPDiagnosticsProvider + * Fixed issue where enabling providers did not work * SPFarm - * Implemented ability to deploy Central Administration site to a server at a - later point in time - * SPInfoPathFormsServiceConfig - * Fixed issue with trying to set the MaxSizeOfUserFormState parameter - * SPProductUpdate - * Fixed an issue where the resource failed when the search was already paused - * SPProjectServerLicense - * Fixed issue with incorrect detection of the license - * SPSearchContentSource - * Fixed issue where the Get method returned a conversion error when the content - source contained just one address - * Fixed issue 840 where the parameter StartHour was never taken into account + * Added ability to check and update CentralAdministrationPort + * SPLogLevel + * Added High as TraceLevel, which was not included yet + * SPRemoteFarmTrust + * Updated readme.md file to add a link that was lost during earlier updates * SPSearchServiceApp - * Fixed issue where the service account was not set correctly when the service - application was first created - * Fixed issue where the Get method throws an error when the service app wasn't - created properly + * Updated Set method to check if service application pool exists. Resource + will throw an error if it does not exist * SPSearchTopology * Fixed issue where Get method threw an error when the specified service - application didn't exist yet. - * SPServiceAppSecurity - * Fixed issue where error was thrown when no permissions were set on the - service application + application didn't exist yet + * Fixed issue where the resource would fail is the FQDN was specified * SPShellAdmins - * Updated documentation to specify required permissions for successfully using - this resource - * SPTrustedIdentityTokenIssuerProviderRealms - * Fixed code styling issues + * Added ExcludeDatabases parameter for AllDatabases + * SPSite + * Added ability to check and update QuotaTemplate, OwnerAlias and SecondaryOwnerAlias + * SPSiteUrl + * New resource to manage site collection urls for host named site collections + * SPTrustedIdentityTokenIssuerProviderRealm + * Fixed issue where Get method threw an error when the realm didn't exist yet * SPUserProfileServiceApp - * Fixed code styling issues - " + * Fix for issue where an update conflict error was thrown when new service + application was created + * Added SiteNamingConflictResolution parameter to the resource + " } # End of PSData hashtable } # End of PrivateData hashtable From 8518f326729d3cabb78a68c328edd88908450c67 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 4 Sep 2018 13:10:13 +0200 Subject: [PATCH 23/23] Update documentation for 2.5 release --- .../en-US/about_SPAppCatalog.help.txt | 6 +- .../en-US/about_SPDatabaseAAG.help.txt | 6 ++ .../en-US/about_SPRemoteFarmTrust.help.txt | 3 +- .../en-US/about_SPServiceIdentity.help.txt | 2 +- .../en-US/about_SPShellAdmins.help.txt | 31 ++++++++ .../SharePointDsc/en-US/about_SPSite.help.txt | 28 ++++++++ .../en-US/about_SPSiteUrl.help.txt | 70 +++++++++++++++++++ .../about_SPUserProfileServiceApp.help.txt | 48 +++++++++++++ 8 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 Modules/SharePointDsc/en-US/about_SPSiteUrl.help.txt diff --git a/Modules/SharePointDsc/en-US/about_SPAppCatalog.help.txt b/Modules/SharePointDsc/en-US/about_SPAppCatalog.help.txt index c363e0214..1fd2673d8 100644 --- a/Modules/SharePointDsc/en-US/about_SPAppCatalog.help.txt +++ b/Modules/SharePointDsc/en-US/about_SPAppCatalog.help.txt @@ -9,9 +9,9 @@ catalog for the web application that the site is in. The catalog site needs to have been created using the correct template (APPCATALOG#0). - This resource should be run using the farm account, and not another specific - setup account. Running this with the setup account you have used in your - configuration may relate to access denied errors. + This resource should NOT be run using the farm account. The resource will + retrieve the farm credentials from SharePoint and use that to update the + AppCatalog. This does mean it requires CredSSP to be setup! .PARAMETER SiteUrl Key - string diff --git a/Modules/SharePointDsc/en-US/about_SPDatabaseAAG.help.txt b/Modules/SharePointDsc/en-US/about_SPDatabaseAAG.help.txt index dab04d597..5dff457fb 100644 --- a/Modules/SharePointDsc/en-US/about_SPDatabaseAAG.help.txt +++ b/Modules/SharePointDsc/en-US/about_SPDatabaseAAG.help.txt @@ -21,6 +21,12 @@ The default value for the Ensure parameter is Present. When not specifying this parameter, the content database is added to the AAG. + Note: + By design the Add-DatabaseToAvailabilityGroup cmdlet updates the database + connection string to the specified availability group. If this is NOT what + you want (for example: You are using SQL aliasses which point to the AG + listener), you should NOT use this resource. + .PARAMETER DatabaseName Key - string The name of the database to put in the AlwaysOn group diff --git a/Modules/SharePointDsc/en-US/about_SPRemoteFarmTrust.help.txt b/Modules/SharePointDsc/en-US/about_SPRemoteFarmTrust.help.txt index fe892a933..2d3079f83 100644 --- a/Modules/SharePointDsc/en-US/about_SPRemoteFarmTrust.help.txt +++ b/Modules/SharePointDsc/en-US/about_SPRemoteFarmTrust.help.txt @@ -7,7 +7,8 @@ This resource is used to trust a remote SharePoint farm. This is used when federating search results between two different SharePoint farms. The - technique is described at + technique is described at: + https://technet.microsoft.com/en-us/library/dn133749.aspx The default value for the Ensure parameter is Present. When not specifying this parameter, the remote farm trust is created. diff --git a/Modules/SharePointDsc/en-US/about_SPServiceIdentity.help.txt b/Modules/SharePointDsc/en-US/about_SPServiceIdentity.help.txt index 49c7fea1c..05a0d9e23 100644 --- a/Modules/SharePointDsc/en-US/about_SPServiceIdentity.help.txt +++ b/Modules/SharePointDsc/en-US/about_SPServiceIdentity.help.txt @@ -21,7 +21,7 @@ .PARAMETER InstallAccount Write - String - POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsAccount if using PowerShell 5 + POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsCredential if using PowerShell 5 .EXAMPLE diff --git a/Modules/SharePointDsc/en-US/about_SPShellAdmins.help.txt b/Modules/SharePointDsc/en-US/about_SPShellAdmins.help.txt index 3af584384..d35cb799c 100644 --- a/Modules/SharePointDsc/en-US/about_SPShellAdmins.help.txt +++ b/Modules/SharePointDsc/en-US/about_SPShellAdmins.help.txt @@ -66,6 +66,10 @@ Write - Boolean Specify if all databases must get the same config as the general config +.PARAMETER ExcludeDatabases + Write - String + Specify all databases that must be excluded from AllDatabases + .PARAMETER InstallAccount Write - String POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsCredential if using PowerShell 5 @@ -130,3 +134,30 @@ } +.EXAMPLE + This example gives admin access to the specified users for the local farm as + well as all content databases in the local farm, with the exception of database + WSS_Content_Portal. + + + Configuration Example + { + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + Import-DscResource -ModuleName SharePointDsc + + node localhost { + SPShellAdmins ShellAdmins + { + Name = "Shell Admins" + Members = "CONTOSO\user1", "CONTOSO\user2" + AllDatabases = $true + ExcludeDatabases = "WSS_Content_Portal" + } + } + } + + diff --git a/Modules/SharePointDsc/en-US/about_SPSite.help.txt b/Modules/SharePointDsc/en-US/about_SPSite.help.txt index 4e6a6487a..3af78c55b 100644 --- a/Modules/SharePointDsc/en-US/about_SPSite.help.txt +++ b/Modules/SharePointDsc/en-US/about_SPSite.help.txt @@ -105,3 +105,31 @@ } +.EXAMPLE + This example creates a site collection with the provided details + + + Configuration Example + { + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + Import-DscResource -ModuleName SharePointDsc + + node localhost { + SPSite TeamSite + { + Url = "http://sharepoint.contoso.com" + OwnerAlias = "CONTOSO\ExampleUser" + HostHeaderWebApplication = "http://spsites.contoso.com" + Name = "Team Sites" + Template = "STS#0" + QuotaTemplate = "Teamsite" + PsDscRunAsCredential = $SetupAccount + } + } + } + + diff --git a/Modules/SharePointDsc/en-US/about_SPSiteUrl.help.txt b/Modules/SharePointDsc/en-US/about_SPSiteUrl.help.txt new file mode 100644 index 000000000..6975b2f84 --- /dev/null +++ b/Modules/SharePointDsc/en-US/about_SPSiteUrl.help.txt @@ -0,0 +1,70 @@ +.NAME + SPSiteUrl + +# Description + + **Type:** Distributed + + This resource will configure the site url for a host named site collection. + There are four available zones to configure: Intranet, Internet, Extranet + and Custom. + + It is not possible to change the site url for the Default zone, since this + means changing the url that is used as identity. A site collection rename + is required for that: + $site = Get-SPSite "http://old.contoso.com" + $new = "http://new.contoso.com" + $site.Rename($new) + ((Get-SPSite $new).contentdatabase).RefreshSitesInConfigurationDatabase + +.PARAMETER Url + Key - string + The URL of the site collection + +.PARAMETER Intranet + Write - string + The URL of the Intranet zone + +.PARAMETER Internet + Write - string + The URL of the Internet zone + +.PARAMETER Extranet + Write - string + The URL of the Extranet zone + +.PARAMETER Custom + Write - string + The URL of the Custom zone + +.PARAMETER InstallAccount + Write - String + POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsCredential if using PowerShell 5 + + +.EXAMPLE + This example configures the site collection urls for the specified + Host Named Site Collection + + + Configuration Example + { + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + Import-DscResource -ModuleName SharePointDsc + + node localhost { + SPSiteUrl TeamSite + { + Url = "http://sharepoint.contoso.intra" + Intranet = "http://sharepoint.contoso.com" + Internet = "https://sharepoint.contoso.com" + PsDscRunAsCredential = $SetupAccount + } + } + } + + diff --git a/Modules/SharePointDsc/en-US/about_SPUserProfileServiceApp.help.txt b/Modules/SharePointDsc/en-US/about_SPUserProfileServiceApp.help.txt index 4751205ba..2ab8ccba5 100644 --- a/Modules/SharePointDsc/en-US/about_SPUserProfileServiceApp.help.txt +++ b/Modules/SharePointDsc/en-US/about_SPUserProfileServiceApp.help.txt @@ -21,6 +21,11 @@ The default value for the Ensure parameter is Present. When not specifying this parameter, the service application is provisioned. + The parameter SiteNamingConflictResolution accepts three values: Username_CollisionError, + Username_CollisionDomain and Domain_Username. More information on each of these + parameters can be found at: + https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.server.userprofiles.sitenameformat?view=sharepoint-server + NOTE: Due to the fact that SharePoint requires certain User Profile components to be provisioned as the Farm account, this resource and SPUserProfileSyncService @@ -81,6 +86,11 @@ Write - boolean Specifies if the service application should be configured to use AD Import +.PARAMETER SiteNamingConflictResolution + Write - string + Allowed values: Username_CollisionError, Username_CollisionDomain, Domain_Username + Specifies which SiteNamingConflictResolution should be used + .PARAMETER Ensure Write - string Allowed values: Present, Absent @@ -162,3 +172,41 @@ } +.EXAMPLE + This example adds a new user profile service application to the local farm + + + Configuration Example + { + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount, + + [Parameter(Mandatory = $true)] + [PSCredential] + $FarmAccount + ) + Import-DscResource -ModuleName SharePointDsc + + node localhost { + SPUserProfileServiceApp UserProfileServiceApp + { + Name = "User Profile Service Application" + ApplicationPool = "SharePoint Service Applications" + MySiteHostLocation = "http://my.sharepoint.contoso.local" + MySiteManagedPath = "personal" + ProfileDBName = "SP_UserProfiles" + ProfileDBServer = "SQL.contoso.local\SQLINSTANCE" + SocialDBName = "SP_Social" + SocialDBServer = "SQL.contoso.local\SQLINSTANCE" + SyncDBName = "SP_ProfileSync" + SyncDBServer = "SQL.contoso.local\SQLINSTANCE" + EnableNetBIOS = $false + SiteNamingConflictResolution = "Domain_Username" + PsDscRunAsCredential = $SetupAccount + } + } + } + +