Last Update: Sep 04, 2024 | Published: Dec 12, 2013
If you have multiple SharePoint 2013 farms, you should be considering publishing some of your SharePoint service applications from one farm and then subscribe to them from another farm. In this article I’m going to show you how to share service applications across SharePoint 2013 farms – and I’ll show you how to do it with PowerShell so that you can take care of multiple service applications in just a few lines of code!
Sharing your service applications is an ideal use in the case of a development or test farm, in which you’d like your user profile service application to be consistent between the two farms or the terms stored in the managed metadata service application to be shared by all of the farms.
This first part of doing this is exchanging the certificates between the two farms and creating all of the trusts. If you need more information on that, I just happen to have an article describing the steps required to create your SharePoint 2013 farm trusts.
I’m going to refer to the production farm as being the farm that is running the service applications, and the test farm as being the farm that will subscribe to those services running in production.
Since our farms now trust each other and the production farm has been configured to accept user sessions (the tokens) from the test farm, we are all clear to publish the services.
Note: There are limitations on the amount of latency that some service applications can tolerate. If your farms aren’t located in the same datacenter, you’ll want to check TechNet to ensure that the service applications that you’re wanting to share can handle your topology. If everything is in the same datacenter, you don’t usually need to worry about that.
Now, let’s publish all of our service applications.
To begin, create two remote sessions, $prodServer and $testServer, which will be used from your workstation to quickly go between the farms.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”> $AdminMe = Get-Credential DOMAINUSERNAME
$ProdHost = “PRODServer”
$TestHost = “TESTServer”
$ProdHost, $TestHost | Foreach-Object {New-Variable –Name $_ -Value (New-PSSession $_ -Authentication CredSSP –Credential $AdminMe) }
Invoke-Command –Session $PRODServer, $TESTServer –Scriptblock {
Add-PSSnapin Microsoft.SharePoint.PowerShell
}
You’ll now have a variable that is named the host of the production server and the test server. For example, if your prod server is named “ProdSP1,” then your variable is $ProdSP1 and it is an active remote connection to the server.
From here on, I’ll reference the remote sessions as $ProdSession and $TestSession, but your variables will be the hostnames of those servers.
Run this command from your workstation to the following:
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”> Invoke-Command -Session $prodSession {
$Publish = “search service application”,
“user profile service application”,
“managed metadata service”,
“secure store service application”,
“Business Data Connectivity Service”,
“Machine Translation Service”
$ServicesToPublish = Get-SPServiceApplication | Where-Object {
$Publish -contains $_.Typename
}
$ServicesToPublish | Publish-SPServiceApplication
}
This creates a list of all service applications that can be published. There are other service applications, but those in this list are the only service application in SharePoint 2013 that can be published.
The great thing about running that scriptblock against your prod server is that it first gets a list of all service application types that can be published, and then it gets the list of all service applications that you have created. If any of the service applications you’re running are of a type that can be published, it will publish them!
Naturally, you’ll have to assign permissions to those published service applications before they can be subscribed to. This is made much simpler with PowerShell, though it might look complicated. I use a lot of commands here, but taken a little at a time they aren’t so bad.
First, get the farm ID from the test farm. You’ll need it in the production farm to identify claims providers. We’ll use a remote session, but we’ll return a value back to a variable on the local workstation.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”> $TestSPFarm = Invoke-Command -Session $TestSession {
Get-SPFarm | Select ID
}
Now we’ll pass that $TestSPFarm variable (holding the test farm ID) into a set of commands to run on the production farm. Don’t be scared! If you read it carefully, you’ll see what we’re doing makes sense.
Here’s what that looks like.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”> Invoke-Command -Session $prodSession -ArgumentList $TESTSPFarm -Scriptblock {
$TESTSPFarm = $args[0]
$Security = Get-SPTopologyServiceApplication | Get-SPServiceApplicationSecurity
$ClaimProvider = (Get-SPClaimProvider System).ClaimProvider
$principal=New-SPClaimsPrincipal -ClaimType “http://schemas.microsoft.com/sharepoint/2009/08/claims/farmid” -ClaimProvider $ClaimProvider -ClaimValue $TESTSPFarm.Id.Guid
Grant-SPObjectSecurity -Identity $security -Principal $principal -Rights “Full Control”
Get-SPTopologyServiceApplication | Set-SPServiceApplicationSecurity -ObjectSecurity $security
}
Now that we’ve added the permissions for the test farm into the prod security system, we can provide some permissions to the specific service applications that have been published. If you run this scriptblock from your workstation you will set the permissions on each of the published service applications on the production farm. The only service application that we won’t assign permissions is the user profile service application, because instead of granting rights to the test farm ID, we’ll be setting permissions for the user that runs the application pool for the web applications in test.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”> Invoke-Command -Session $ProdSession -ScriptBlock {
$NotUPS = $ServicesToPublish | Where-Object {$_.TypeName -ne “User Profile Service Application”}
$NotUPS | Foreach-Object {
$ThisServiceApp = $_
$ServiceAppSecurity = $_ | Get-SPServiceApplicationSecurity
$NamedRights = $ServiceAppSecurity.NamedAccessRights | Where-Object {$_.name -like “*full*”}
 
Grant-SPObjectSecurity -Identity $ServiceAppSecurity -Principal $Principal –Rights $($NamedRights.Name)
Set-SPServiceApplicationSecurity $ThisServiceApp -ObjectSecurity $ServiceAppSecurity
}
}
Now we can set the permissions for the user profile service application. However, before we can do that we’ll get the name of the web application pool from the test server.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”> $TestAppID = Invoke-Command -Session $testSession -ScriptBlock {
Get-SPServiceApplicationPool -Identity “YourTestWebApplicationUrl”
}
Invoke-Command -Session $ProdSession -ArgumentList $TestAppID -ScriptBlock {
$TestAppID = $Args[0]
$UPS = $ServicesToPublish | Where-Object {$_.typename -eq “User Profile Service Application”}
$UPS | Foreach-Object {
$ThisServiceApp = $_
$ServiceAppSecurity = $_ | Get-SPServiceApplicationSecurity
$NamedRights = $ServiceAppSecurity.NamedAccessRights | Where-Object {$_.name -like “*full*”}
$Principal = New-SPClaimsPrincipal -Identity $($TestAppID.ProcessAccountName) -IdentityType WindowsSamAccountName
Grant-SPObjectSecurity -Identity $ServiceAppSecurity -Principal $Principal -Rights $($NamedRights.Name)
Set-SPServiceApplicationSecurity $ThisServiceApp -ObjectSecurity $ServiceAppSecurity
}
}
Finally, we get to subscribe to the service applications. Since the service applications are actually running in the production farm, we won’t be creating new service applications in the test farm. Instead, we’ll be creating new service application proxies in the test farm that point to the service applications in the production farm.
To do this, we’ll need some information from the production farm. We’ll use remote sessions to bring the data locally then push it into the test farms remote session.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”> $PublishedServices = Invoke-Command -Session $ProdSession -ScriptBlock {
$ServicesToPublish
}
$Connection = Invoke-Command -Session $ProdSession {
(Get-SPTopologyServiceApplication).ServiceInstances
}
Invoke-Command -Session $TestSession -ArgumentList $Connection {
$Connection = $args[0]
}
We’ve now passed the $Connection variable into the test farm. This connection tells the test farm where to make the service connections for the service applications. We’ll pass in the list of services to connect to along with this final scriptblock, which will create the service application proxies for each of the published service applications.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”>
Invoke-Command -Session $sa30 -ArgumentList $PublishedServices {
$PublishedServices = $args
$PublishedServices | ForEach-Object {
$name = $_.name
$uri = $_.uri.AbsoluteURI
Switch($_.typename) {
“search service application” {
New-SPEnterpriseSearchServiceApplicationProxy -Name “$Name Proxy” -Uri $Uri
}
“user profile service application” {
New-SPProfileServiceApplicationProxy -Name “$Name Proxy” -Uri $Uri
}
“managed metadata service” {
New-SPMetadataServiceApplicationProxy -Name “$Name Proxy” -Uri $Uri
}
“secure store service application” {
New-SPSecureStoreServiceApplicationProxy -Name “$Name Proxy” -Uri $Uri
}
“Business Data Connectivity Service” {
New-SPBusinessDataCatalogServiceApplicationProxy -Name “$Name Proxy” -Uri $Uri
}
“Machine Translation Service” {
New-SPTranslationServiceApplicationProxy -Name “$Name Proxy” -Uri $Uri
}
}
}
}
And now, just like magic, we’ll find that our service applications have been added to our test farm. All you’ll have to do now is add your service applications into the default proxy group (or any additional proxy groups that you’re using) and you’ll see your service applications from farm, even when you’re in test.