Tuesday, April 14, 2015

Thursday, April 09, 2015

Lync 2013 Archiving to Exchange 2013


For compliance reasons, I've always recommended that customers configure Lync archiving.  Unlike email, IM messaging is usually not a very large data set, and while the Lync client does have the option to save the conversation history in Outlook and Exchange, those folders are visible to end users and they can also empty and clean those folders out to cover tracks.

Ever since Exchange 2013 launched, I have been aware of the Lync archiving integration to it, but frankly have not had many customers that both had Lync 2013 and Exchange 2013 deployed until fairly recently. 

While reading about these integrations, I learned that the Exchange based archiving is NOT equal to the SQL based archiving.  You must place the users into an in place or litigation hold within Exchange in order for the data to be discoverable in Exchange's eDiscovery portal.

Let me say that a different way.  Unless you place a user on hold in Exchange, no Lync archives will be written to the user's mailbox.

I had spent a lot of time reading before this became clear to me, so hopefully this saves someone else some time.

Reading material:
  • Doug's blog - Archiving Options in Lync Server 2013
  • Exchange 2013 - Archive Lync conversations and meeting content to Exchange states "This requires placing the user on In-Place Hold"
  • Lync 2013 - Configuring Microsoft  Lync Server 2013 to use Microsoft Exchange Server 2013 archiving, in Step 3 states that the Set-CSUser object has four settings for the ExchangeArchivingPolicy attribute:
    • Uninitialized. Indicates that archiving will be based on the In-Place Hold settings configured for the user's Exchange mailbox; if In-Place Hold has not been enabled on the user's mailbox then the user will have his or her messaging and Web conferencing transcripts archived in Lync Server.
    • UseLyncArchivingPolicy. Indicates that the user's instant messaging and Web conferencing transcripts should be archived in Lync Server rather than in Exchange.
    • NoArchiving. Indicates that the user's instant messaging and Web conferencing transcripts should not be archived at all. Note that this setting overrides any Lync Server archiving policies assigned to the user.
    • ArchivingToExchange. Indicates that the user's instant messaging and Web conferencing transcripts should be archived to Exchange regardless of the In-Place Hold settings that have (or have not) been assigned to the user's mailbox.

By default, all users will be Uninitialized.  The UseLyncArchivingPolicy means the user will only use SQL based archiving.  The NoArchiving is pretty self-explanatory.  The last option, ArchivingToExchange sounds like what I had thought Exchange archiving was originally, but the article also states this is an optional step only if your Exchange and Lync servers are in different forests:

"If Lync Server 2013 and Exchange 2013 are located in different forests then it is not enough to simply enable Exchange archiving in the archiving configuration settings; that will not result in instant messaging and Web conferencing transcripts being archived in Exchange. Instead, you must also configure the ExchangeArchivingPolicy property on each of the relevant Lync Server user accounts."

So, if you use Exchange 2013 archiving for Lync, and you have not been setting users to be in an in place hold, you do not have discoverable Lync data and need to add them to a hold, or rely on your SQL based logging instead!

Friday, March 27, 2015

Exchange 2013 and RMS on Windows 2012 R2 getting UnsupportedCryptographicSetException error

Well, I never really considered myself an RMS guy, but I guess this month has changed things some.  After my last article, I was running through a test plan, when I came to find that the Test-IRMConfiguration was failing on one server (the entire time of this project, I had only really focused on the Exchange servers in the same datacenter.  The exact failure seen below is identical to the error you would expect to see on an older OS, or an unpatched Exchange 2010 server.  It also was documented here.  We did use Cryptographic Mode 2, but since we are on Windows 2012 R2 and Exchange 2013, the error was not expected here.  Also, the permissions that the error tells you to set are already in place.  Keep in mind that I already had two Exchange 2013 servers working correctly, just this other one didn't.


Acquiring Rights Account Certificate (RAC) and Client Licensor Certificate (CLC) ...
    - FAIL: Failed to acquire a Rights Account Certificate (RAC) and/or a Client Licensor Certificate (CLC).
This failure may cause features such as Transport Decryption, Transport Protection Rules, Journal Report Decryption, IRM in Outlook Web App, IRM in Exchange ActiveSync, and IRM Search to not work. Make sure that the Exchange Servers Group is granted "Read" and "Read & Execute" rights on the ServerCertification.asmx and Publish.asmx pipelines on your AD RMS server. For details, see "Set Permissions on the AD RMS Certification Pipeline" at  http://go.microsoft.com/fwlink/?LinkId=186951.

----------------------------------------
Microsoft.Exchange.Security.RightsManagement.RightsManagementException: Failed to acquire server box RAC from

---> System.Web.Services.
Protocols.SoapException: System.Web.Services.Protocols.SoapException: Exception of type 'System.Web.Services.
Protocols.SoapException' was thrown. ---> Microsoft.DigitalRightsManagement.Cryptography.UnsupportedCryptographicSetException: Exception of type 'Microsoft.DigitalRightsManagement.Cryptography.UnsupportedCryptographicSetException' was thrown.
   --- End of inner exception stack trace ---
   at Microsoft.DigitalRightsManagement.Certification.BaseCertificationWebService.Certify(CAType caType, CertifyParams requestParameters)
   at Microsoft.DigitalRightsManagement.Certification.ServerCertificationWebService.Certify(CertifyParams requestParams)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.EndInvoke(IAsyncResult asyncResult)
   at Microsoft.Exchange.Net.WsAsyncProxyWrapper.EndInvoke(IAsyncResult result)
   at Microsoft.Exchange.Security.RightsManagement.SOAP.ServerCertification.ServerCertificationWS.EndCertify(IAsyncResult asyncResult)
   at Microsoft.Exchange.Security.RightsManagement.ServerCertificationWSManager.EndAcquireRac(IAsyncResult asyncResult)

Exchange server was 2013 and patched on a Windows 2012 R2 server



Resolution:
This issue was because the environment had an RMS server in the past that had been decommissioned.  The Exchange server that was failing to use RMS was doing so because it already had machine certificates.  The fix was to backup these cache files, and reboot the Exchange server, then the command passed and it rebuilt the cached files using the new RMS instance.  Of course, the old instance was Type 1 Cryptographic mode, hence the mismatch error.




  1. On the impacted Exchange server, go to c:\ProgramData\Microsoft\DRM\Server (Server is a hidden folder, so you need to specify it)
  2. You will see SID's like below in there.  I just moved both into a new subfolder for now.  You can see an example of the content of these folders below as well.
  3. Reboot the Exchange server
  4. Re-test the Test-IRMConfiguration


Tuesday, March 24, 2015

ADRMS, SQL mirroring, and named instances

First and foremost, I need to thank my PSS colleagues for their assistance on this case. It was open for quite some time, but Samesh Panicker and Kaustubh Dwivedi were critical to my success in this configuration. Here's the scenario:
  • Two ADRMS servers running on Windows 2012 R2
  • Two SQL servers, SQL 2012 on Windows 2012 R2 with a SQL express witness
    • Since we colocated with another SQL instance, I had to use named instances (more on this soon)
  • An F5 Hardware load balancer (HLB) publishing an internal and external VIP using split brain DNS to resolve rms.domain.com to the correct VIP


The article that I followed was from the Technet Wiki here:
http://social.technet.microsoft.com/wiki/contents/articles/14977.test-lab-guide-configuring-ad-rms-with-sql-mirroring-in-windows-server-2012.aspx

This is required reading for the rest of the post, as I am only going to highlight key differences from that guide.


Step 3d 
There are a few things on using setspn. First, most people are not familiar with it. Even those who are, use it infrequently. I am OK running setspn.exe, but you need to know how to check and then delete any mistakes. I tend to use ADSIedit here. You are adding Service Principal Names (SPNs) to the SQL service account. So in ADSIiedt, you drill down to that account (not the SQL server computer objects) to set, edit, or delete SPNs.

Keep in mind, his example shows:
Setspn –A MSSQLsvc/[sql1 fqdn] [domain]\SQLSVC
Setspn –A MSSQLsvc/[sql2 fqdn] [domain]\SQLSVC
Setspn –A MSSQLsvc/[sql1] [domain]\SQLSVC
Setspn –A MSSQLsvc/[sql2] [domain]\SQLSVC

A few changes and clarifications here.
  • MSSQLSvc is a static field, that isn't your account name (his example using SQLSVC makes this confusing IMO)
  • If you are using a named instance for SQL, you need to specify it.
This is done as shown below.



So to correct the above paste from the wiki (needed only if specifying an instance name)


Setspn –A MSSQLsvc/[sql1 fqdn:INSTANCE] [domain]\ADRMSSQLSVC
Setspn –A MSSQLsvc/[sql2 fqdn:INSTANCE] [domain]\ADRMSSQLSVC
Setspn –A MSSQLsvc/[sql1:INSTANCE] [domain]\ADRMSSQLSVC
Setspn –A MSSQLsvc/[sql2:INSTANCE] [domain]\ADRMSSQLSVC

If you are running more than a single instance of SQL on a server or servers in my case, you cannot use the same mirroring port if another instance is using it. TCP/5022 is the default port - if another SQL instance is already using mirroring on that port, you will need to pick a new port. Be sure to do a netstat -ano and ensure its not in use first, then follow this guide to change your mirror port: http://www.macaalay.com/2012/10/10/altering-mirroring-endpoints-ports-on-sql-server/  

Step 10
First off, PSS recommends you not really edit SQL using transact. It's totally acceptable if you are strong in SQL, but they really prefer you use RMSConfigEditor.exe from the RMS toolkit . And yes that is from 2006 and doesn't say anything about 2012 or 2012 R2, but it still works.

Second, and I see Kaustubh has already updated the wiki, but the Logging Database SHOULD NOT have the "data source=" like the CertificationUserKeyStorageConnectionString and the DirectoryServicesCacheDatabase . When we specified it with that connection string, logging/reporting functions did not work in the RMS Admin console, and RMS was broken if the database was hosted on the SQL02 server.

Another thing to note, as it’s a simple mistake to make, but your Database= string, the [cluster] will always be host_domain_com, and NOT host.domain.com. If you are working on issues with RMS late at night, or after many hours at it, this can be pretty painful to mistake, so do check it!

Monday, March 09, 2015

Quickly implementing Cisco CDA registry permissions required

Recently was working with a colleague on our Cisco team to implement Cisco's Context Directory Agent (CDA) product in order to provide user to IP address mapping so that Cisco Cloud Web Security could correctly identify users based on their IP.

The tasks to configure this on the Microsoft side are fairly straightforward, but there are registry setting permissions that cannot be implemented via GPO because GPO's are run by SYSTEM, which doesn't have access to these particular keys.

So first off, the Cisco article on implementation:
http://www.cisco.com/c/en/us/td/docs/security/ibf/cda_10/Install_Config_guide/cda10/cda_install.html

Here's the registry specific settings, which need to be performed on ANY DOMAIN CONTROLLER in a site where users will be using CDA!

From that article:
For Windows 2008 R2,Windows 2012, and Windows 2012 R2, the Domain Admin group does not have full control on certain registry keys in the Windows operating system by default. In order to get the CDA to work, Active Directory admin must give the Active Directory user Full Control permissions on the following registry keys:
  • HKEY_CLASSES_ROOT\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}
  • HKLM\Software\Classes\Wow6432Node\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}
Now, when they say "the Active Directory User" they mean the service account that CDA is using.  So you need to add a reg permission to two keys on every DC.

Now, this customer had less than 10 domain controllers, so I did this in a more manual way, but hopefully someone else can find this and have the problem of 200+ domain controllers and script this properly by focusing on the Domain Controllers OU and implementing (or better yet, finding a way to address via GPO somehow)

I chose to use SetACL.exe, which is NOT a Microsoft tool, but is a quite effective and great tool.  Using this, and either using the \\computername method, or running locally on each DC, you can implement these changes using the below command.  Note - you need to take ownership with your account in order to set permissions.  I highlighted the sections that you will need to configure specific to your environment in bold.

SetACL.exe -on "hklm\Software\Classes\Wow6432Node\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}" -ot reg -actn setowner -ownr "n:AdminAccount"
SetACL.exe -on "hklm\Software\Classes\Wow6432Node\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}" -ot reg -actn ace -ace "n:domain.com\CDAServiceAccount;p:full"
SetACL.exe -on "HKEY_CLASSES_ROOT\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}" -ot reg -actn setowner -ownr "n:
AdminAccount"
SetACL.exe -on "HKEY_CLASSES_ROOT\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}" -ot reg -actn ace -ace "n:domain.com\
CDAServiceAccount;p:full"

If anyone runs into this situation and ultimately ends up automating the solution feel free to post in the comment section below for others.  Should be easy enough to get domain controllers into an array to for-each through.

Thursday, March 05, 2015

Lync - External meeting participants not able to use web join

I had this issue recently where a customer reported that external parties couldn't join a meeting. I asked him to send me a meeting, I clicked the URL, and I got right in. After a few emails back and forth, realized that the issue occurred if the external party didn't have Lync installed. So I forced web join using ?sl=1 and sure enough, I got a DNS error that the internal web services URL could not resolve.

Thankfully, this is a very simple fix, their external web services URL was reverse publishing from 443->443 when it should have been 443->4443.  I changed their TMG publishing rule and everything worked OK after that.