Reassign the private key after deleting a certificate from the snap-in

In case we delete, by mistake, a certificate using the Certificate snap-in, we can still restore it. In order to do this, we need to import the certificate again and reassign the stored private key to it, without having to create a new request.

The following article was published for IIS, but it also applies to Lync/SfB Server and to Exchange Server:

How to assign a private key to a new certificate after you use the Certificates snap-in to delete the original certificate in Internet Information Services
https://support.microsoft.com/en-us/kb/889651

The first step is to import the certificate again to the Computer Personal Store:

privatekey01

After importing the certificate, if it doesn’t have the private key assigned, we cannot use the certificate in any Lync/SfB Server service.

Now we need to take note of the certificate Serial Number. We can get it either in the certificate Details tab:

privatekey02

Note: This is a lab CA and that is why the serial number is just 02, because normally you will have something like ‎04 3b df f8 25 84 cd. This serial number is given by the CA and it is the Serial Number that will be included in the CRL if the certificate is revoked.

Or use the Certutil store switch – https://technet.microsoft.com/en-gb/library/cc732443.aspx:

certutil -store my

privatekey03a

In a Command Prompt/PowerShell, we run the certutil with the repairstore switch:

certutil -repairstore my “Serial Number

 privatekey03

Alternatively, we can use the certificate index in the store. The index number is returned by the certutil -store my command:

privatekey03c

certutil -repairstore my 1

privatekey03b

If the private key is successfully assigned, we will see it in the Computer Personal Store after refreshing it:

privatekey04

Please note that sometimes the private key is lost and we will have to create a new request.

This method will also work if we change Certificate Common Name or add/remove FQDN to the SAN. In this case, we need to follow these steps:

  1. Request the changes in the Certificate Authority online website (note that if we re-key the certificate, we need to import the certificate as usual);
  2. Download the certificate;
  3. Import the certificate to the server;
  4. Take note of the certificate Serial Number;
  5. Run certutil -repairstore my “Serial number”

Merge certificate public and private key with OpenSSL

This post isn’t about Lync Server/Skype for Business Server, but we think it will be a good reference for people that work with Lync/Skype.

When we do an offline certificate request, we will get an .REQ file that looks like this:

—–BEGIN NEW CERTIFICATE REQUEST—–
###################################
—–END NEW CERTIFICATE REQUEST—–

Then we use public or private CA to complete the request, and in return we get a .CER/.CRT file:

—–BEGIN CERTIFICATE—–
###################################
—–END CERTIFICATE—–

The private key, however, is usually stored in the device that generates the request. We can have it in cleartext and it will look like this:

—–BEGIN PRIVATE KEY—–
###################################
—–END PRIVATE KEY—–

We had this customer who sent us the .CER and .KEY. Even though we sent the normal request file created by the Lync Deployment Wizard, still the customer decided to create a new certificate and send us the private key in cleartext.
It’s really important never to store or send the private key of a certificate in cleartext.
We could send a new request, but we really needed to deploy the Edge Server with federation enabled. After some research, we found an easy way to do it using OpenSSL:

OpenSSL.org
https://www.openssl.org/

In this case, we used the OpenSSL for Windows pre-compiled version:

OpenSSL.org – Binary Distributions
https://wiki.openssl.org/index.php/Binaries

Note: Download the 32- or 64-bit to match the Windows version.

Inside the compressed file, we have this:

opensslmerge03

Extract all files to a folder (in this case, we did it to C:OpenSSL) and copy the .CER and .KEY files to this same folder.
If we get a .P7B file with the certificate and the chain, we need to export the certificate first. In order to do this, simply open the file, right-click on the certificate and select All Tasks > Export:

opensslmerge07

When asked for Export File Format, we need to choose Base-64 encoded.509 (.CER):

opensslmerge08

Now in the Command Prompt, go to the folder, run the following command and insert a password (this will be used to import the certificate):

openssl pkcs12 -export -in lync_edge.cer -inkey lync_edge.key -out lync_edge_merged.pfx

opensslmerge04

Note: We can ignore the warning message, since we only need to merge the certificate.

Take notice that the new merged certificate was created in the folder:

opensslmerge05

We can import the certificate and finally have a certificate ready to be used by Lync Server/Skype for Business Server:

opensslmerge06

Request/Renewing Skype for Business Server 2015 Certificates

Here are the steps to request or renew certificates in Skype for Business Server 2015.

Most of the steps are similar to Lync Server 2010/2013, so to start let’s go to the well-known Deployment Wizard Step 3 and click Run or Run Again (depending on if you are requesting for the first time or renewing the certificates).

Skype4B-ReqCert01

Now, in Certificate Wizard, we select the proper certificate and then click Request:

Skype4B-ReqCert02

The Certificate Request wizard will open and we can notice that this user interface changed from Lync Server 2010/2013. Now we have all the basic information to request a certificate consolidated in a single window:

Skype4B-ReqCert03

Note: In the Edge Server, the certificate request is the same as in Lync Server 2010/2013, therefore we don’t have the new consolidated view.

We can use the Advanced mode (also known as old Lync Server 2013 mode), in case we need to specify one of the following settings:

  • Create an Offline Request

Skype4B-ReqCert04

  • Specify another CA

Skype4B-ReqCert05

  • Specify different CA credentials

Skype4B-ReqCert06

  • Use a different Certificate Template

Skype4B-ReqCert07

  • Change key bit length and/or Mark the certificate private key as exportable

Skype4B-ReqCert08

  • Add additional SAN names

Skype4B-ReqCert09

After that, we will return to the initial Certificate Request screen. Don’t forget to select the SIP Domains served by this server:

Skype4B-ReqCert10

In the next screen, check if all the details are correct:

Skype4B-ReqCert11

If the certificate request is successful, we get Task status: Completed:

Skype4B-ReqCert12

Continuing with our request, select the Assign this certificate to Skype for Business Server certificate usages option:

Skype4B-ReqCert13

Note: Before requesting a new certificate, we need to make sure that the Root CA certificate is installed in the Trusted Root Certification Authorities under the Local Computer Certificate Store:

Skype4B-ReqCert14

The Certificate Assignment wizard will be launched, and we can view the details or continue:

Skype4B-ReqCert15

Before assigning the certificate, we need to verify the details:

Skype4B-ReqCert16

Task status: Completed confirms that the certificate was correctly assigned:

Skype4B-ReqCert17

We have just assigned the new certificate, so all we need now is to restart the services on the Front End. In case we have a Front End Enterprise Pool, keep in mind that we need to check if there are enough Front End servers running before restarting the services. In order to do this, simply use the Get-CsUpdatePoolReadiness.

Finally, if there are enough Front End servers to keep the pool running, we can proceed and restart the services:

Stop-CsWindowsService
Start-CsWindowsService

Lync Server 2013: Event 14497,14517 LS Protocol Stack

This issue dates a while back, but after Lync Server 2013 Cumulative Update 3 (5.0.8308.556 and above) the Edge Server Access Service won’t start with the Event 14497 LS Protocol Stack:

Event14517-14497-02

One or more configuration errors were detected at startup that cannot be mitigated.

Cause: There are serious problems with the server configuration that prevented it from starting up.
Resolution:
Review the previous event log entries to identify failures. Alter the server configuration as required. If problems persist, contact Product Support Services.

Log Name:      Lync Server
Source:        LS Protocol Stack
Date:          07/05/2015 17:41:09
Event ID:      14497
Task Category: (1001)
Level:         Error
Keywords:      Classic
User:          N/A

Computer:      edge01.gears.lab

In a previous error, we found the following in Event Viewer:

Event14517-14497-01

Event 14517, LS Protocol Stack

The server configuration validation mechanism detected some serious problems.

1 errors and 0 warnings were detected.

ERRORS:
The server at FQDN [sipfed.online.lync.com] is configured as both type ‘allowed partner server’ and type ‘IM service provider’.

WARNINGS:
No warnings

Cause: The configuration is invalid and the server might not behave as expected.
Resolution:
Review and correct the errors listed above, then restart the service. You may also wish to review any warnings present.

Log Name:      Lync Server
Source:        LS Protocol Stack
Date:          07/05/2015 10:32:35
Event ID:      14517
Task Category: (1001)
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      edge01.gears.lab

Both the errors helped us to find the issue easily. In this case, we had configured a Lync Online tenant as Allowed Domain in SIP Federated Domains before updating to Lync Server 2013 CU3:

Lync Server Control Panel

Event14517-14497-03

Event14517-14497-04

Lync Server PowerShell

Lync Server 2013: Get-CsAllowedDomain
https://technet.microsoft.com/en-us/library/gg398164(v=ocs.15).aspx

Event14517-14497-03ps

Lync Server 2013: Get-CsHostingProvider
https://technet.microsoft.com/en-us/library/gg413078(v=ocs.15).aspx

Event14517-14497-04ps

To solve this we simply need to remove the Access Edge service (FQDN), which in this case is sipfed.online.lync.com from the Allowed Domain:

Lync Server Control Panel

Event14517-14497-05

Lync Server PowerShell

Lync Server 2013: Set-CsAllowedDomain
https://technet.microsoft.com/en-us/library/gg398931(v=ocs.15).aspx

Event14517-14497-05ps

Before continue, we need to check if the replication was successful:

Lync Server 2013: Get-CsManagementStoreReplicationStatus
https://technet.microsoft.com/en-us/library/gg399052(v=ocs.15).aspx

Event14517-14497-06a

Now we can go to Edge Server and use Start-CsWindowsService to start all Lync Server related services. After that, we can check with Get-CsWindowsService that all services are up and running:

Event14517-14497-06

Notice that after Lync Server 2013 Cumulative Update 3 we cannot add a new Allowed Domain with the same Access Edge service (FQDN) as a Hosting Provider:

Event14517-14497-07

When using Allowed Domains without specifying the Access Edge service (FQDN), make sure that Lync Server will rely on the DNS SRV Record for that specific SIP domain.

The Nslookup.exe Command Line Tool

https://technet.microsoft.com/en-us/library/ee624049(v=ws.10).aspx

nslookup -type=srv _sipfederationtls._tcp.<SIP Domain>
Event14517-14497-08

Deploying SQL Server AlwaysOn Availability Group for Skype for Business Server 2015

In Lync Server 2013, there were requests regarding an alternative to SQL Mirroring for SQL Server High Availability. This was related to the fact that SQL Mirroring was marked as a feature to be removed in future SQL Server versions:

This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature. Use AlwaysOn Availability Groups instead.
in SQL Server 2014 – Database Mirroring (SQL Server) – https://msdn.microsoft.com/en-us/library/ms189852.aspx

In Lync Server 2013, it was common to have SQL Server High Availability using SQL Mirroring. The reason for this was that Topology Builder did all the hard work for us. Another supported scenario was to use SQL failover clustering, but in this case we need to manually deploy it:

Database software support in Lync Server 2013
https://technet.microsoft.com/en-us/library/gg398990.aspx

The good news is Skype for Business Server 2015 comes with AlwaysOn Availability Groups:

Note: AlwaysOn Availability Groups requires SQL Server 2012/2014 Enterprise Edition.

For other supported scenarios, check the following:

Back End Server high availability in Skype for Business Server
https://technet.microsoft.com/en-us/library/jj205248.aspx

To deploy AlwaysOn Availability Groups for Skype for Business Server 2015, we need to follow specific steps. In this tutorial, we consider a lab environment with one Front End server and two SQL Server 2014 Enterprise Edition servers, which is a new environment without any previous Lync Server/OCS deployments.

Let’s start by installing and configuring the clustering service on both SQL Servers (SQL01 and SQL02). We can add new features by using the following PowerShell cmdlet:

Add-WindowsFeature Net-Framework-Core, Failover-Clustering, RSAT-Clustering-Mgmt,RSAT-Clustering-PowerShell -Source d:\sources\sxs
Note: The reason to use the source switch is that Windows Server 2012 R2 doesn’t install the source files. So, if your server doesn’t have internet access, you need to specify the path. In this case, the DVD is D:

Now that we have both servers with the necessary Windows Features, we can create the cluster. Before creating the cluster, we should test the configuration:

Test-Cluster -Node sql01,sql02
https://technet.microsoft.com/en-us/library/hh847274.aspx

In a lab environment, these warnings can be ignored, but in a production environment we need to check them before continue.
The Test-Cluster cmdlet will generate a Failover Cluster Validation Report:

After the test, we can create the cluster. For that, we can also use a PowerShell cmdlet. Since we don’t have DHCP in our lab subnet, we need a valid IP Address in the SQL Servers subnet:

New-Cluster -Name sqlcluster -Node sql01,sql02 -NoStorage -StaticAddress 172.20.15.8
https://technet.microsoft.com/en-us/library/hh847246.aspx

The New-Cluster will generate a Create Cluster report:

Before installing SQL Server we also need to configure the Cluster Quorum, we can use a File Share Witness:

Set-ClusterQuorum -Cluster sqlcluster -NodeAndFileShareMajority “\\dc01.gears.lab\SQLClusterWitness”
https://technet.microsoft.com/en-us/library/ee461013.aspx

Note: For additional information please go to Configure and Manage the Quorum in a Windows Server 2012 Failover Cluster

Now that we have the cluster with basic configuration, we can proceed and install SQL Server 2014 on both servers:

In Instance Features select at least Database Engine Services:

We can use Default instance for both servers:

Or change it to a different name. If you change it to a Named Instance, make sure both servers use the same instance name:

In Service Accounts, change the Account Name to a custom service account and use it on both SQL Servers:

After completing the installation, we need to enable AlwaysOn Availability Groups. On each server, we need to open SQL Server Configuration Manager, then right click on SQL Server Service and open Properties:

Select the AlwaysOn High Availability tab and tick Enable AlwaysOn Availability Groups:

For the changes to be applied, we need to restart SQL Server Service:

Skype4B-AOAG14

Select SQL Server Service, then click on the Restart service icon:

An additional step is to create a DNS A record for sqlpool.halo.lab. This is our Availability Group Listener FQDN:

In the Skype for Business Server 2015 Topology Builder, we add a new SQL Server Store with the following configuration:

Notice that we use the SQL01 server FQDN. This is normal and we will change it later on.

Now we publish the topology:

In SQL Server Management Studio, we can check that the Skype for Business Server 2015 related databases were successfully created in SQL01:

To create a new Availability Group, right click AlwaysOn High Availability and open New Availability Group Wizard…:

Fill the Availability Group name:

The wizard will check for prerequisites and will let us know that, before we proceed, the database recovery needs to be changed to full and also perform a full backup:

To make things easier, we can use the following PowerShell SQL cmdlets:

Back End databases:

Invoke-Sqlcmd -Query “ALTER DATABASE [cpsdyn] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”
Invoke-Sqlcmd -Query “ALTER DATABASE [rgsconfig] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”
Invoke-Sqlcmd -Query “ALTER DATABASE [rgsdyn] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”
Invoke-Sqlcmd -Query “ALTER DATABASE [rtcab] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”
Invoke-Sqlcmd -Query “ALTER DATABASE [rtcshared] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”
Invoke-Sqlcmd -Query “ALTER DATABASE [rtcxds] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”

Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database cpsdyn
Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database rgsconfig
Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database rgsdyn
Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database rtcab
Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database rtcshared
Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database rtcxds

CMS Databases:

Invoke-Sqlcmd -Query “ALTER DATABASE [xds] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”
Invoke-Sqlcmd -Query “ALTER DATABASE [lis] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”

Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database xds
Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database lis

Monitoring Databases:

Invoke-Sqlcmd -Query “ALTER DATABASE [LcsCDR] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”
Invoke-Sqlcmd -Query “ALTER DATABASE [QoEMetrics] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”

Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database LcsCDR
Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database QoEMetrics

Archiving Database:

Invoke-Sqlcmd -Query “ALTER DATABASE [LcsLog] SET RECOVERY FULL WITH NO_WAIT;” -ServerInstance “SQL01\S4B_BackEnd”

Backup-SqlDatabase -ServerInstance SQL01\S4B_BackEnd -Database LcsLog

Another requirement is that we copy the directory structure to the second SQL server:

robocopy C:\CsData \\SQL02\C$\CsData /e /xf *
https://technet.microsoft.com/en-GB/library/cc733145.aspx

Go back to the wizard, click Refresh and select the databases:

On the next step, click Add Replica…:

Change the server name and connect to the second SQL Server:

Select both SQL Instances in the Replicas tab:

We also need to create a listener, thus select the Listener tab and then select Create an availability group listener:

Note: As mentioned before, we don’t have DHCP on this Lab subnet, so we use a static address (different from the cluster).

Click Next and specify a temporary file share:

The wizard will run additional availability group validation checks:

And if everything goes okay, we get the following messages:

In AlwaysOn High Availability, we can check if the selected databases were included in the group:

Almost done. If we compare Security Logins for both servers, we can notice that some logins are missing from SQL02:

To add all the necessary permissions, we need to change the Primary Replica to the second SQL Server, right click on Availability Group and select Failover:

In the wizard, click Next:

We need to connect to the server:

If Failover is successful, we get this:

We can see that the Primary Replica is now the second SQL Server:

Time to go back to Topology Builder, select SQL Server Store and Edit Properties… :

Change the SQL Server FQDN to the second SQL Server:

Publish the topology.

In the Skype for Business Server 2015 server, open the PowerShell and run:

Install-CsDatabase -Update -ConfiguredDatabases -SqlServerFqdn sqlpool.halo.lab -Verbose

After completion, the necessary logins are also added to the second SQL server:

Finally, let’s change SQL Server Store in Topology Builder to the final value:

After publishing the topology, we now have Skype for Business Server 2015 with an AlwaysOn Availability Group configured.

Additional resource:

Chris Lehr experienced a few errors during the deployment and published the notes on his blog:

Chris and Robin’s Technology blog – SQL 2014 AlwaysOn Deployment for Skype for Business Server 2015 http://blog.chrislehr.com/2015/06/sql-2014-alwayson-deployment-for-skype.html

Skype for Business Server 2015 Component Version using PowerShell

There are two methods to get the Skype for Business Server component version: using Windows Registry or the WMI Classes. Both methods were previously published for Lync Server 2010 and Lync Server 2013:

Lync Server Component Version using PowerShell (Windows Registry)
https://uclobby.wordpress.com/2014/12/15/lync-server-component-version-using-powershell-windows-registry/

Lync Server Component Version using PowerShell (WMI Classes)
https://uclobby.wordpress.com/2013/08/14/lync-server-component-version/

The preferred method is using the Windows Registry method, since it is faster than the WMI method.

Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | ?{$_.DisplayName -like “*Skype for Business*”} | Sort-Object DisplayName | Select DisplayName, DisplayVersion, InstallDate | Format-Table -AutoSize

Using search filter *Skype for Business* will also get the Skype for Business Online PowerShell Module version, which is installed by default when you install Skype for Business Server 2015 components.

If for some reason you need to use the WMI method, run this:

Get-WmiObject -query ‘select name, version from win32_product’ | where {$_.name -like “*Skype for Business*”} | Sort-Object Name | Select Name, Version | ft -AutoSize

If you experience any issue with the PowerShell window length, run the following in PowerShell:

$pshost = get-host
$pswindow = $pshost.ui.rawui
$newsize = $pswindow.buffersize
$newsize.height = 3000
$newsize.width = 100
$pswindow.buffersize = $newsize
$newsize = $pswindow.windowsize
$newsize.height = 50
$newsize.width = 100
$pswindow.windowsize = $newsize

Please check on PowerShell window/buffer resizing in the following article:

How Can I Expand the Width of the Windows PowerShell Console?
http://blogs.technet.com/b/heyscriptingguy/archive/2006/12/04/how-can-i-expand-the-width-of-the-windows-powershell-console.aspx