Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPSearchServiceApp: Added logic and parameter to provision default search topology #1401

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- SPSearchServiceApp
- Added optional ProvisionDefaultTopology (boolean) parameter to control should
the SPSearchServiceApp provision search topology as well. See more info how
this works from the resource readme.md

### Fixed
- SPWebApplication
- Fixed an issue where the Set method tried to use the Parameter SecureSocketsLayer with Set-SPWebApplication on SharePoint Server older than Subscription Edition.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ function Get-TargetResource

[Parameter()]
[System.UInt16]
$RecrawlErrorInterval
$RecrawlErrorInterval,

[Parameter()]
[System.Boolean]
$ProvisionDefaultTopology
)

Write-Verbose -Message "Getting Search service application '$Name'"
Expand Down Expand Up @@ -351,7 +355,11 @@ function Set-TargetResource

[Parameter()]
[System.UInt16]
$RecrawlErrorInterval
$RecrawlErrorInterval,

[Parameter()]
[System.Boolean]
$ProvisionDefaultTopology
)

Write-Verbose -Message "Setting Search service application '$Name'"
Expand Down Expand Up @@ -469,8 +477,156 @@ function Set-TargetResource
Set-SPEnterpriseSearchServiceApplication @setParams
}

Write-Verbose -Message ("NOTE: Don't forget to configure a Search topology " + `
"using the SPSearchTopology resource!")
# Provision default topology if ProvisionDefaultTopology = $true
if ($params.ContainsKey("ProvisionDefaultTopology") -eq $true)
{
if ($params.ProvisionDefaultTopology -eq $true)
{
$isCustomOrSingleProvisioning = $false

$possibleSearchServers = Get-SPServer | Where-Object { $_.Role -in ("Search", "ApplicationWithSearch", "Custom", "SingleServerFarm", "SingleServer") }

if ($possibleSearchServers.Count -eq 0)
{
$message = ("You have specified DefaultSearchTopology=`$true, but we are " + `
"unable to provision search topology as no servers having " + `
"one of the supported roles found. Make sure you have at least " + `
"one server configured using one of the supported roles which are: " + `
"Search, ApplicationWithSearch, Custom, SingleServer or SingleServerFarm")

Add-SPDscEvent -Message $message `
-EntryType 'Error' `
-EventID 100 `
-Source $eventSource
throw $message
}
else
{
$searchServers = $possibleSearchServers | Where-Object { $_.Role -in ("Search", "ApplicationWithSearch") }

if ($searchServers.Count -eq 0)
{
Write-Verbose -Message "Provisioning default search topology"

$searchServers = $possibleSearchServers | Where-Object { $_.Role -eq "Custom" }

if ($searchServers.Count -eq 0)
{
$searchServers = $possibleSearchServers | Where-Object { $_.Role -in ("SingleServerFarm", "SingleServer") }

if ($searchServers.Count -gt 0)
{
$isCustomOrSingleProvisioning = $true
}
}
else
{
$isCustomOrSingleProvisioning = $true
}
}

# if custom, application, singleserver or singleserverfarm then we provision only to 1 server
if ($isCustomOrSingleProvisioning)
{
$searchServers = $searchServers[0]
}

# Ensure the search service instance is running on all servers
foreach ($searchServer in $searchServers)
{
$serverName = $searchServer.Address

Write-Verbose -Message "SEARCH SERVER: $($searchServers)"

$searchService = Get-SPEnterpriseSearchServiceInstance -Identity $serverName `
-ErrorAction SilentlyContinue

if ($null -eq $searchService)
{
$domain = (Get-CimInstance -ClassName Win32_ComputerSystem).Domain
$searchServer = "$serverName.$domain"
$searchService = Get-SPEnterpriseSearchServiceInstance -Identity $serverName -ErrorAction SilentlyContinue
}

if (($searchService.Status -eq "Offline") -or ($searchService.Status -eq "Disabled"))
{
Write-Verbose -Message "Start Search Service Instance"
Start-SPEnterpriseSearchServiceInstance -Identity $serverName
}

# Wait for Search Service Instance to come online
$loopCount = 0
$online = Get-SPEnterpriseSearchServiceInstance -Identity $serverName -ErrorAction SilentlyContinue
while ($online.Status -ne "Online" -and $loopCount -lt 15)
{
$online = Get-SPEnterpriseSearchServiceInstance -Identity $serverName -ErrorAction SilentlyContinue
Write-Verbose -Message ("$([DateTime]::Now.ToShortTimeString()) - Waiting for " + `
"search service instance to start on $searchServer " + `
"(waited $loopCount of 15 minutes)")
$loopCount++
Start-Sleep -Seconds 60
}
}

# Get current topology and prepare a new one
$currentTopology = $app.ActiveTopology
$newTopology = New-SPEnterpriseSearchTopology -SearchApplication $app `
-Clone `
-SearchTopology $currentTopology

#$domain = "." + (Get-CimInstance -ClassName Win32_ComputerSystem).Domain

foreach ($searchServer in $searchServers)
{
$serverName = $searchServer.Address

$serviceInstance = Get-SPEnterpriseSearchServiceInstance -Identity $serverName

$NewComponentParams = @{
SearchTopology = $newTopology
SearchServiceInstance = $serviceInstance
}

Write-Verbose -Message "Adding $serverName to run an AdminComponent"
$null = New-SPEnterpriseSearchAdminComponent @NewComponentParams

Write-Verbose -Message "Adding $serverName to run a CrawlComponent"
$null = New-SPEnterpriseSearchCrawlComponent @NewComponentParams

Write-Verbose -Message "Adding $serverName to run a ContentProcessingComponent"
$null = New-SPEnterpriseSearchContentProcessingComponent @NewComponentParams

Write-Verbose -Message "Adding $serverName to run an AnalyticsProcessingComponent"
$null = New-SPEnterpriseSearchAnalyticsProcessingComponent @NewComponentParams

Write-Verbose -Message "Adding $serverName to run a QueryComponent"
$null = New-SPEnterpriseSearchQueryProcessingComponent @NewComponentParams

$NewComponentParams += @{
IndexPartition = 0
}

Write-Verbose -Message "Adding $serverName to run an IndexComponent"
$null = New-SPEnterpriseSearchIndexComponent @NewComponentParams
}

# Apply the new topology to the farm
Write-Verbose -Message "Applying new Search topology"
Set-SPEnterpriseSearchTopology -Identity $newTopology


# Stop search service instance on all the other servers not part of search topology
(Get-SPServer) | Where-Object { $_ -notin $searchServers -and $_.Role -ne "Invalid" } | ForEach-Object {
Get-SPEnterpriseSearchServiceInstance -Identity $_.Address | Stop-SPEnterpriseSearchServiceInstance
}
}
}
}
else
{
Write-Verbose -Message ("NOTE: Don't forget to configure a Search topology " + `
"using the SPSearchTopology resource!")
}
}
}
}
Expand Down Expand Up @@ -841,7 +997,11 @@ function Test-TargetResource

[Parameter()]
[System.UInt16]
$RecrawlErrorInterval
$RecrawlErrorInterval,

[Parameter()]
[System.Boolean]
$ProvisionDefaultTopology
)

Write-Verbose -Message "Testing Search service application '$Name'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ class MSFT_SPSearchServiceApp : OMI_BaseResource
[Write, Description("Specifies what items get deleted: 0 - All unvisited items, 1 - (Default) All unvisited items that have the same host as the start address, 2 - None of the unvisited items. You can specify the following three values:")] uint16 DeleteUnvisitedMethod;
[Write, Description("Specifies the number of consecutive crawls in which errors were encountered while fetching changes from the SharePoint content database")] uint16 RecrawlErrorCount;
[Write, Description("Specifies the number of hours since the first error were encountered while fetching changes from the SharePoint content database")] uint16 RecrawlErrorInterval;
[Write, Description("Should default search topology be provisioned")] boolean ProvisionDefaultTopology;
};
15 changes: 13 additions & 2 deletions SharePointDsc/DSCResources/MSFT_SPSearchServiceApp/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,19 @@ For more information about the Deletion Policy settings, check the following
article:
https://docs.microsoft.com/en-us/previous-versions/office/sharepoint-server-2010/hh127009(v=office.14)?redirectedfrom=MSDN

**NOTE:** Don't forget to configure a Search topology using the SPSearchTopology
resource!
**NOTE:** Use 'ProvisionDefaultTopology = $true' parameter to provision default search topology. When this parameter is defined
and value is TRUE then topology is created as below:

1. First we check are there any servers having Search or ApplicationWithSearch role. If there are then all search components are
provisioned to all these servers

2. If no Search or ApplicationWithSearch role servers exist then we check are there servers having Custom role. If yes then all
search server components are provisioned to one (1) server having Custom role

3. If no servers exist having roles defined in 1 and 2 then we check is this SingleServer or SingleServerFarm deployment and if yes
the all search server components are provisioned to that single server

If you do not want to provision default topology then you need to define search topology using the SPSearchTopology resource!

**NOTE2:** The resource is also able to add the Farm account as db_owner to all
Search databases, to prevent the issue described here:
Expand Down