Installation

Important

SharePoint (especially 2019) has unaddressed reliability issues when deploying farm solutions on farms with multiple servers.
The more servers the farm has, the bigger the risk that deployment fails. To mitigate this, cmdlet Install-SPSolution can be run with -Local on each server, but it requires more operations.
This page will guide you through the steps to install AzureCP in a safe and reliable way.

Deploy the solution

Important

Always start a new PowerShell process to ensure using up to date persisted objects and avoid nasty errors.

Execute the following steps:

  • Download the latest version of AzureCP.wsp.

  • Install and deploy the solution, using either the simple or the safe method:

    • Simple method: Recommended for single-server farms only:
    # Run this script on the server running central administration, in a new PowerShell process
    Add-SPSolution -LiteralPath "C:\Data\AzureCP.wsp"
    # Wait for some time (until solution is actually added)
    # Then run Install-SPSolution (without -Local) to deploy solution globally (on all servers that run service "Microsoft SharePoint Foundation Web Application"):
    Install-SPSolution -Identity "AzureCP.wsp" -GACDeployment
    • Safe method: Recommended for production environments with multiple servers:

    Important

    Run this script on ALL SharePoint servers running the service "Microsoft SharePoint Foundation Web Application" and/or the central administration, sequentially (not in parallel), starting with the server running the central administration.

    <#
    .SYNOPSIS
        Deploy "AzureCP.wsp" in a reliable way, to address reliability issues that may occur when deploying solutions in SharePoint (especially 2019) (and especially if there are many servers):
    .DESCRIPTION
        Run this script on ALL SharePoint servers running the service "Microsoft SharePoint Foundation Web Application" and/or the central administration, sequentially (not in parallel), starting with the server running the central administration.
        The script does not require any modification, you only need to set the variable $packagefullpath with the path to the solution file (used only on the 1st server)
    .LINK
        https://entracp.yvand.net/docs-azurecp/usage/install/
    #>
    
    # To use this script, you only need to edit the variable $packagefullpath below
    $claimsprovider = "AzureCP"
    $packagefullpath = "C:\Data\$claimsprovider.wsp"
    $packageName = "$claimsprovider.wsp"
    
    # Perform checks on the local server to detect and prevent potential problems
    # Check 1: Install-SPSolution will fail if claims provider is already installed on the current server
    if ($null -ne (Get-SPClaimProvider -Identity $claimsprovider -ErrorAction SilentlyContinue)) {
        Write-Error "Cannot continue because current server already has claims provider $claimsprovider, which will cause an error when running Install-SPSolution."
        throw ("Cannot continue because current server already has claims provider $claimsprovider, which will cause an error when running Install-SPSolution.")
        Get-SPClaimProvider| ?{$_.DisplayName -like $claimsprovider}| Remove-SPClaimProvider
    }
    
    # Check 2: Install-SPSolution will fail if any feature in the WSP solution is already installed on the current server
    if ($null -ne (Get-SPFeature| ?{$_.DisplayName -like "$claimsprovider*"})) {
        Write-Error "Cannot continue because current server already has features of $claimsprovider, Visit https://entracp.yvand.net/docs/help/fix-setup-issues/ to fix this."
        throw ("Cannot continue because current server already has features of $claimsprovider, Visit https://entracp.yvand.net/docs/help/fix-setup-issues/ to fix this.")
    }
    
    Write-Host "All checks passed on this server, continuing..."
    # Add the solution if it's not already present in the farm (only the 1st server will actually do this)
    if ($null -eq (Get-SPSolution -Identity $packageName -ErrorAction SilentlyContinue)) {
        Write-Host "Adding solution $packageName to the farm..."
        Add-SPSolution -LiteralPath $packagefullpath
    }
    
    $count = 0
    while (($count -lt 20) -and ($null -eq $solution))
    {
        Write-Host "Waiting for the solution $packageName to be available..."
        Start-Sleep -Seconds 5
        $solution = Get-SPSolution -Identity $packageName
        $count++
    }
    
    if ($null -eq $solution) {
        Write-Error "Solution $packageName could not be found in the farm."
        throw ("Solution $packageName could not be found in the farm.")
    }
    
    # Always wait at least 5 seconds to avoid that Install-SPSolution does not actually trigger deployment
    Start-Sleep -Seconds 5
    Write-Host "Deploying solution $packageName on the local server..."
    # Set -local in Install-SPSolution to deploy the bits on this server only and prevent reliability issues in SharePoint
    Install-SPSolution -Identity $packageName -GACDeployment -Local
  • Visit central administration > System Settings > Manage farm solutions: Confirm the solution is “Globally deployed”.

Important

If you did not run Install-SPSolution -Local on every SharePoint server running the service "Microsoft SharePoint Foundation Web Application" and/or the central administration, the solution will NOT be "Globally deployed" and SharePoint will NOT activate AzureCP features.

Finalize the installation

This step is very important and applies to all SharePoint servers which do NOT run the service “Microsoft SharePoint Foundation Web Application” and/or the central administration.

Important

This step must be executed during both install (Install-SPSolution) and update (Update-SPSolution) scenarios.

For each of those servers, complete the steps below to manually add/update AzureCP bits (azurecp.dll and its dependent assemblies) in the GAC:

  • Download the package ‘AzureCP-XXXX-dependencies.zip’ corresponding to the version you downloaded (expand the “Assets” to find it).

  • Use 7-zip to extract the DLLs in a local folder.

  • Run the script below to add the assemblies in the GAC:

    <#
    .SYNOPSIS
        Check if assemblies in the directory specified are present in the GAC, and add them if not.
    .DESCRIPTION
        This script needs to be executed each time you install/update AzureCP, on all SharePoint servers that do not run SharePoint service “Microsoft SharePoint Foundation Web Application”.
        Set $assemblies to the path where 'AzureCP-XXXX-dependencies.zip' was unzipped
    .LINK
        https://azurecp.yvand.net/docs/usage/install/
    #>
    
    $assemblies = Get-ChildItem -Path "C:\AzureCP-XXXX-dependencies-unzipped\*.dll"
    
    [System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    $publish = New-Object System.EnterpriseServices.Internal.Publish
    foreach ($assembly in $assemblies)
    {
        $filePath = $assembly.FullName
        $assemblyFullName = [System.Reflection.AssemblyName]::GetAssemblyName($filePath).FullName
    
        try
        {
            $assemblyInGAC = [System.Reflection.Assembly]::Load($assemblyFullName)
            Write-Host "Assembly $assemblyFullName is already present in the GAC"
    
            if ($assemblyInGAC.FullName -match "AzureCP, Version=1.0.0.0, Culture=neutral, PublicKeyToken=65dc6b5903b51636")
            {
                # AzureCP must always be overwritten because each version has the same full name
                $publish.GacRemove($assemblyInGAC)
                $publish.GacInstall($filePath)
                Write-Host "Assembly $assemblyFullName sucessfully re-added to the GAC" -ForegroundColor Green
            }
        }
        catch [System.IO.FileNotFoundException] 
        {
            # Assembly.Load throws a FileNotFoundException if assembly is not found in the GAC: https://docs.microsoft.com/en-us/dotnet/api/system.io.filenotfoundexception?view=netframework-4.8
            Write-Host "Adding assembly $assemblyFullName to the GAC"
            $publish.GacInstall($filePath)
            Write-Host "Assembly $assemblyFullName sucessfully added to the GAC" -ForegroundColor Green
        }
    }
  • Restart the IIS service and the SharePoint timer service (SPTimerV4):
    Restart-Service W3SVC; Restart-Service SPTimerV4

Enable the claims provider

To be enabled, AzureCP must be associated with the SPTrustedLoginProvider which stores the configuration of the trust with the trusted STS:

$trust = Get-SPTrustedIdentityTokenIssuer "SPTRUST NAME"
$trust.ClaimProviderName = "AzureCP"
$trust.Update()

You can now configure AzureCP.