2

We had an issue with the Secure Store Service on SharePoint 2016 when we tried to create a new instance in partition mode for a multi-tenancy farm.

The main issue, it was impossible to generate a master key from powershell by using Update-SPSecureStoreMasterKey command - no error, and some times

Didn't perform that operation...

or via the central administration

"Failed to generate/refresh key due to error: bla bla blaaa.

For your information, the account used to perform those operations is Farm Admin and follow Microsoft guidelines in terms of permissions, then the farm topology contains 2 WFE, 2 Apps & 2 SQL Servers.

After a lot of investigation, for an unknown reason, the method

"ChangeKey" in the "Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplicationProxy" doesn't work as expected.

So, to fix that first part you have to execute

"ChangeMasterSecretKey" from the instance of "Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplication".

Well, you think it's fine you can can see from the central admin that the key is defined, nooooope a new error will occur when you tries to add a target application:

Unable to get the master key.

It's a joke, absolutely not... Fine, if you try now to "refresh the master key" by the central admin with the same passphrase, yataaa, the secure store works as expected.

By now, how to replicate those actiona to automate that for the next deployment ? Have a look on the class definition "Microsoft.Office.SharePoint.ClientExtensions.SecureStoreAdministration.ChangeDBKey" at the method "**OkButton_Click**", you'll see activities performed to generate or refresh a master key are not the same performed by PowerShell commands (**Update-SPSecureStoreMasterKey**/Update-**SPSecureStoreApplicationServerKey**).

Finally, the powershell code bellow could save your day. Enjoy.

$sa = Get-SPServiceApplication <Your_SercureStoreApplication_Identity>;
$proxy = Get-SPServiceApplicationProxy <Your_SercureStoreApplicationProxy_Identity>;
$sp_secure_store_passpharse_new = "<Your_PassPhrase>";
try{
    ##BUG with Update-SPSecureStoreMasterKey => Didn't work properly

    #HotFix: Reverse engineering on classes:
    #-> Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplication
    #-> Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplicationProxy
    #-> Microsoft.Office.SecureStoreService.Server.KeyManagement.KeyManager
    #-> Microsoft.Office.SecureStoreService.Server.CryptoHelper

    $ass = $sa.GetType().Assembly
    $CryptoHelperType = $ass.GetType("Microsoft.Office.SecureStoreService.Server.CryptoHelper")
    $GetPassPhraseHashMethod=$CryptoHelperType.GetMethod("GetPassPhraseHash");

    $proxyType = $proxy.GetType();
    $IsMasterSecretKeyPopulated = $proxyType.GetMethod("IsMasterSecretKeyPopulated",[Reflection.BindingFlags]"NonPublic,Instance")
    $SetChangeKeyPassphrase = $proxyType.GetMethod("SetChangeKeyPassphrase",[Reflection.BindingFlags]"NonPublic,Instance")
    $SetKey = $proxyType.GetMethod("SetKey",[Reflection.BindingFlags]"NonPublic,Instance", $null, [type[]]@([string]), $null)

    if(-not $IsMasterSecretKeyPopulated.invoke($proxy,$null)){

        #ChangeKey with the proxy is buggy
        #$proxy.ChangeKey( $proxy.GetChangeKeyToken(), $sp_secure_store_passpharse_new );
        #Fallback by using the service application directly
        $token = $sa.GetChangeMasterSecretKeyToken();
        $sa.ChangeMasterSecretKey($token, $GetPassPhraseHashMethod.Invoke($null, $sp_secure_store_passpharse_new) );

        $c=0;

        while(-not $IsMasterSecretKeyPopulated.invoke($proxy,$null)){
            $c++;
            if($c -ge 20){
                Write-Error $("The master key cannot be populated!");
            }
            sleep 1;
        }
    }

    $SetChangeKeyPassphrase.invoke($proxy, @($sp_secure_store_passpharse_new));
    $SetKey.invoke($proxy,$sp_secure_store_passpharse_new);


}catch{
    Write-Error $("Cannot update the secure store master key.`n{0}" -f $_.Exception.Message);
}
  • we don't receive enough of these knowledgebase type questions. Thank you! Can you put the solution in the form of an answer below, then mark it as the solution? Thank you @Vladimir – Mike Oct 26 '17 at 17:11
1

Anwser:

$sa = Get-SPServiceApplication <Your_SercureStoreApplication_Identity>;
$proxy = Get-SPServiceApplicationProxy <Your_SercureStoreApplicationProxy_Identity>;
$sp_secure_store_passpharse_new = "<Your_PassPhrase>";
try{
    ##BUG with Update-SPSecureStoreMasterKey => Didn't work properly

    #HotFix: Reverse engineering on classes:
    #-> Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplication
    #-> Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplicationProxy
    #-> Microsoft.Office.SecureStoreService.Server.KeyManagement.KeyManager
    #-> Microsoft.Office.SecureStoreService.Server.CryptoHelper

    $ass = $sa.GetType().Assembly
    $CryptoHelperType = $ass.GetType("Microsoft.Office.SecureStoreService.Server.CryptoHelper")
    $GetPassPhraseHashMethod=$CryptoHelperType.GetMethod("GetPassPhraseHash");

    $proxyType = $proxy.GetType();
    $IsMasterSecretKeyPopulated = $proxyType.GetMethod("IsMasterSecretKeyPopulated",[Reflection.BindingFlags]"NonPublic,Instance")
    $SetChangeKeyPassphrase = $proxyType.GetMethod("SetChangeKeyPassphrase",[Reflection.BindingFlags]"NonPublic,Instance")
    $SetKey = $proxyType.GetMethod("SetKey",[Reflection.BindingFlags]"NonPublic,Instance", $null, [type[]]@([string]), $null)

    if(-not $IsMasterSecretKeyPopulated.invoke($proxy,$null)){

        #ChangeKey with the proxy is buggy
        #$proxy.ChangeKey( $proxy.GetChangeKeyToken(), $sp_secure_store_passpharse_new );
        #Fallback by using the service application directly
        $token = $sa.GetChangeMasterSecretKeyToken();
        $sa.ChangeMasterSecretKey($token, $GetPassPhraseHashMethod.Invoke($null, $sp_secure_store_passpharse_new) );

        $c=0;

        while(-not $IsMasterSecretKeyPopulated.invoke($proxy,$null)){
            $c++;
            if($c -ge 20){
                Write-Error $("The master key cannot be populated!");
            }
            sleep 1;
        }
    }

    $SetChangeKeyPassphrase.invoke($proxy, @($sp_secure_store_passpharse_new));
    $SetKey.invoke($proxy,$sp_secure_store_passpharse_new);


}catch{
    Write-Error $("Cannot update the secure store master key.`n{0}" -f $_.Exception.Message);
}
  • Thanks a lot. The problem seems to apply to the preview version of SP 2019 as well. The solution / workaround works however either. – pholpar May 23 at 13:47
  • Thanks for your feedback. I’m not alone in that situation :) – Vladimir Herrlein May 24 at 15:58
1

In SharePoint 2016 I had to run Get-SPServiceApplication and Get-SPServiceApplicationProxy to get the GUID for the service in order to run this.

It might be obvious to some, but I didn't understand that at first.

Therefore the commands look like this:

$sa = Get-SPServiceApplication 'd64a59ab-5f04-40ac-9058-462770ba0000';

where the GUID matches your service guid

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.