Using a Reverse Proxy to Automatically Force External Lync Meeting Guests to Use Silverlight Client

Microsoft, in their infinite wisdom, designed Lync in such a way that if members of two organizations deploy Lync and try to schedule meetings with each other, Lync will use federation in order negotiate authentication between the two domains.  This is great if you have a federated relationship with all your partners that you want to hold meetings with.  But what if you want to do ad hoc meetings with unauthenticated guests?  Microsoft gives you two choices.  One is to allow automatic discovery of federated partners, where the Lync servers will negotiate with each other based on published DNS and other settings, and the other is to log into the meeting using the Silverlight client.

There’s just one problem.

If you have the Lync desktop client on your PC and you try to visit an external meeting link, such as https://lync.contoso.com/meet/username/EJHFSN and you are not a part of the Contoso organization and you do not have federation set up or do not allow automatic discovery of federated partners, it will fail with a useless numeric error code that means absolutely nothing.  Since the desktop client does not allow you log on anonymously, it will never fallback to guest logon, even if the meeting organizer has it enabled for the meeting.

TechNet to the rescue!  All you have to do is append “sl=1” to the end of the query string of the URL, so that you visit https://lync.contoso.com/meet/username/EJHFSN?sl=1 and then it will force the Silverlight client, which will allow you to log on anonymously.  In this scenario, Lync meetings then behave basically like WebEx or GotoMeeting, where external participants need a browser plugin to connect to the meeting.  Perfect.  That’s exactly what I want.

Again, one problem.  Imagine trying to get your entire staff to always remember to append that to the meeting link when they set up external meetings.  Despite best efforts, it’s just not going to happen.  Your CFO has better things to do and she will forget, because that is human nature.  And, really, this is Microsoft’s shortsightedness here.  You can read my comment at the TechNet article linked above.

Thanks for the "?sl=1" trick. That did the trick for me. But explaining this to my users is going to be a pain. Imagine me in the CFO's office after months of extolling the virtues of Lync and how we even got rid of our WebEx subscription because, heck, Lync does meetings too! But suddenly, a meeting participant is also using Lync at his company but we have no federated relationship with each other, so when we click on each other's meeting links it just fails with a terrible numerical error. "I thought this thing could replace WebEx," the CFO bellows, scowling at me in disdain. "Oh, it can," I reply, "just make sure you modify every meeting invitation so that the URL has ?sl=1 at the end of it!" Yea, that will go over well.

Thankfully, there is a workaround.  And due to the way Lync is designed, it’s really not difficult to set up.

When you set up your Lync websites, it creates an internal and external site.  The external site by default uses the non-standard ports 8080 and 4443.  The Lync best practice is to use a Reverse Proxy or firewall port forwarding rules to send traffic destined for the normal web ports to the Lync alternate ports.  Your internal users, on the other hand, use ports 80 and 443 as normal, directly communicating with the Lync server.

Reverse proxies can also be set up to modify URLs before the connection is sent to the backend.  This is known as URL Rewriting.  In this case, you want a URL rewrite rule that will modify connections to /meet/ such that ?sl=1 is always added to the end.  I found from trial and error that you get the best results by only modifying the /meet/ part of the above URL (assuming you are using Simple URLs like that).  So I set up my topology so that 8080 and 4443 were exposed directly to the outside so I have an option to bypass the reverse proxy once the connection is established.  This is all completely secure and transparent to the end user.  We’re not bypassing the firewall, just the reverse proxy’s URL rewriting when it is not needed.

So the final topology looks like this.  (The Lync Front End is either your Edge server or your single server depending on the size of your deployment.)

Lync Diagram

From outside my firewall, ports 80, 443, 8080, and 4443 are all open.  If you connect to 80 or 443, you are sent to the reverse proxy.  If you go to 8080 or 4443, you are sent directly to Lync.

To prepare Lync for this configuration, I first edited the topology so that the published ports are assigned the same as the internal (8080 and 4443) as this will allow us to bypass the reverse proxy when it is not needed.


Whenever you publish your topology, remember to rerun the Lync setup wizard.

The reverse proxy can be easily created using IIS.  In fact, you can set it up on your Lync edge server if you want.  It depends on your workload.  For the purposes of this post, we’ll assume you are setting it up on the same server.   Note: Lync will stop any non-Lync website in IIS whenever you publish your topology and rerun setup, so be prepared for this!

In order to configure the reverse proxy, you need to install the Application Request Routing and URL Rewrite extensions for IIS.  These both should already be installed if you are using your Lync server.

Enable the Application Request Routing.  This is done at the server level.  Click on your IIS server in the IIS manager, double click Application Request Routing Cache, then click on Server Proxy Settings.  Check Enable proxy and keep everything else at defaults.


Create a new website.  Give it a folder path that is not shared with any other site (i.e., don’t reuse C:\Inetpub\wwwroot).  The bindings should be whatever the external IP address is mapped to through your firewall.  Bind HTTP and HTTPS on the default ports.  Make sure you use a different internal IP address than your Lync internal website so there isn’t a collision.  You don’t want internal users going through the reverse proxy.

Go into the site’s URL Rewrite section and create a dummy rule.  We are going to overwrite this later, so it doesn’t matter what it is.  We just want to create a web.config that we can edit by hand.

Edit the web.config “rules” section for the reverse proxy site.  Now here is where the fun begins.  We are going to modify any request that goes to /meet/ so that it has sl=1 at the end.  I created a rule for both HTTP and HTTPS since I am using default Lync ports (non-standard web ports).  There is also a condition that if the query string already contains sl=, it will not modify it.  Underneath the /meet/ rewrites are the default rules that just pass the request through unmodified to the correct ports.  Obviously, URLs, RegEx, ports, and so on, will all need to be modified to match your environment.

<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="^meet/(.*)" />
<add input="{QUERY_STRING}" pattern="(.*)sl=(.*)" negate="true" />
<add input="{CACHE_URL}" pattern="^(https)://" />
<action type="Rewrite" url="{C:1}://lync.contoso.com:4443/{R:0}?sl=1&{QUERY_STRING}" appendQueryString="false" logRewrittenUrl="true" />
<rule name="ReverseProxyInboundRule2" stopProcessing="true">
<match url="^meet/(.*)" />
<add input="{QUERY_STRING}" pattern="(.*)sl=(.*)" negate="true" />
<add input="{CACHE_URL}" pattern="^(http)://" />
<action type="Rewrite" url="{C:1}://lync.contoso.com:8080/{R:0}?sl=1&{QUERY_STRING}" appendQueryString="false" logRewrittenUrl="true" />
<rule name="ReverseProxyInboundRule3" stopProcessing="true">
<match url="(.*)" />
<add input="{CACHE_URL}" pattern="^(https)://" />
<action type="Rewrite" url="{C:1}://lync.contoso.com:4443/{R:1}" appendQueryString="true" logRewrittenUrl="true" />
<rule name="ReverseProxyInboundRule4" stopProcessing="true">
<match url="(.*)" />
<add input="{CACHE_URL}" pattern="^(http)://" />
<action type="Rewrite" url="{C:1}://lync.contoso.com:8080/{R:1}" appendQueryString="true" logRewrittenUrl="true" />

If you attempt to connect to a meeting externally now, this is what happens.

  1. Browser initiates connection to https://lync.contoso.com/meet/username/EJHFSN.
  2. Reverse Proxy receives the request, adds sl=1 to the query string, and passes the request to the external Lync website at https://lync.contoso.com:4443/meet/username/EJHFSN?sl=1.
  3. Lync server replies and tells the browser to load the Silverlight Lync client which then attempts to connect directly to the lync web services (bypassing the Reverse Proxy) at https://pool1.lync.contoso.com:4443/Reach/Client/WebPages/ReachClient.aspx.
  4. The external user can join as an anonymous guest, or log on using the domain credentials of the organizer’s meeting, if they have that.  The desktop Lync client will never launch!

Hopefully in the future Microsoft will fix the desktop client to allow it to log on anonymously to external meetings and also give us a checkbox in the Lync Server Control Panel that allows us to force all external connections to the Silverlight client (for legacy organizations that might connect to ours).


Elfen Lied: One Messed Up (But Awesome) Anime

I just finished watching the Elfen Lied anime, which is based on a fairly long running manga.  The anime was only 13 episodes long, with one 30 minute OVA being produced afterwards.  This anime has been out for a while, so I’m a bit late to the party in commenting on it, but it was such a shocking series, I felt it deserved its own post.

The anime opens with Lucy, a young girl with horns, pink hair, and strange powers, fully nude walking through a building that looks like a cross between a bomb shelter and insane asylum.  As she walks down the hallways, she is ripping guards and scientists to shreds using powers that are explained later in the series.  Blood, bones, guts, and organs splatter everywhere.  This scene sets the tone for the rest of the anime.  I’ve read critics of the series decry this portrayal as over-the-top and gratuitous or simply sex and violence fan service. 

If that’s all you watch and then turn it off, I would agree.  But as you continue to watch the first episode, the mystery of what Lucy is, what that facility she was in is, and how that all relates to the college aged teens she meets who take her in to help her, is absolutely engrossing.  That scene is not the end of the extreme violence and nudity.

As the first few episodes progress, you begin to see the reason behind the over-the-top approach to this anime.  Nearly all of the characters are absolutely tortured.  Without giving away too much of the plot, you have one character who witnessed his sister and father brutally murdered before his eyes at a young age, another who was sexually molested by her step father with her mother accusing her of lying and eventually abandoning her, one whose limbs are mutilated and is left for dead, and several who are tortured repeatedly in gruesome and inhumane ways by authority figures.  The nudity and blood is simply a way to reinforce and help push the sort of emotional twistedness of the extreme horrors the characters have been through.

Nudity in most movies or series is usually a precursor to a love scene.  In this anime it’s more closely tied to something bad, usually quite violent, happening to a character.  It’s actually quite a brilliant mind screw and a good way to get you to empathize with the torture the character is experiencing.

So, yea, not for kids, this one.

My only complaint is that while the first four episodes and last four episodes were strong, the middle was very slow.  This is a weird thing since anime is based on a rather long running manga.  You would think they had plenty of material to work with, but it’s almost like the producers and writers just lost their way in the middle.  The same fights and arguments were fought and argued again and again.  Nothing new really happened.  And the conversations just sounded very forced.  I’m not sure why this happened.  Maybe it was a brief reprieve before the torture started again?  lol.  Also, without giving away the ending, I will just say that it had a satisfying conclusion, but ended with the typical amount of loose ends that most anime series end up having. 

The OVA was apparently never released in the USA, but it’s easy to find on the internet with subtitles.  It takes place in the middle of the series and is rather light hearted compared to the series and answers a few questions that were not otherwise resolved.  Honestly, they should have cut the middle four episodes down to two and added the plot of the OVA into the middle and the pacing would have been a lot better.

So, if you can tolerate watching something that will mess with your emotions and shock you with gruesome violence and gratuitous nudity, this is an anime I have to highly recommend.  The series is on NetFlix.

On a 1-10 scale, I give this anime an 8.  Now I need to go find something to watch on NetFlix that is more uplifting and less disturbing!


Finding Stale Recovery Points in DPM 2010 Using PowerShell

I recently had a disk failure that I was using for my Microsoft Data Protection Manager 2010 (DPM) protection groups.  Unfortunately, it wasn't a recoverable error so I had to remove the disk from the pool and reallocate the affected data sources.  DPM is supposed to error out the data sources when it can't perform the backup, but I've found this is not always the case.  Only about 25% of the data sources that were on that disk ever errored out.  The rest had the happy green "OK."  Looking through the protection groups, I noticed that any data source that was no longer protected would still show the correct last recovery point from when it last succeeded (which was days ago).  When I tried to run a manual express full backup at that point, I would get an error that stated that the disk was missing and it could not perform the backup.  However, it still showed the green "OK" symbol next to the data source.

I have several hundred protected data sources and I couldn't go through them one by one, so I whipped up a PowerShell script to show me stale DPM data.  Basically, it enumerates all the data sources and compares the latest recovery point date with 24 hours ago.  If it's older than that, it outputs the protected resource so I can removed it and add it back to the protection group with a fresh volume.

The biggest gotcha I ran into is that a lot of properties returned by Get-DataSource are asynchronous, which is annoying when you are scripting.  Luckily, a TechNet blogger had a solution to that problem.  His script contains an error (a missing parenthesis), though.  I notified him so hopefully it will get fixed.  I have confirmed my script below works.

This script is not just useful for finding stale data due to a failed disk.  It could also be adapted to notify you when failed backups is close to surpassing your defined Recovery Point Objective (RPO).  DPM's internal notification system is very noisy since it's not uncommon for a backup to fail, then recover on its own very quickly.  If you manage a large DPM deployment, you are probably used to hundreds to thousands of emails awaiting you after the weekend.   I'm not using it that way yet, but I think I just might.

The output of my script looks like this:

$ds[133] System State and BMR : server1.avianwaves.com : Computer\System Protection

The $ds variable is the array that stores all the data sources used in the script.  The 133 is the index, so you can quickly query more information about the data source if you need to.  Just type "$ds[133]" at the PowerShell prompt to do so.  Immediately after the variable name is the Protection Group.  Following that is the server holding the protected resource.  Then the last part is the protected resource itself.

I hope this helps somebody out there!

# Refresh the datasource metadata. Code taken from: http://blogs.technet.com/b/dpm/archive/2010/09/11/why-good-scripts-may-start-to-fail-on-you-for-instance-with-timestamps-like-01-01-0001-00-00-00.aspx
Disconnect-DPMserver #clear object caches
$ds = @(Get-ProtectionGroup (&hostname) | foreach {Get-Datasource $_})
$ds = $ds | ?{$_} #remove blanks
for ($i=0; $i -lt $ds.count;$i++) { [void](Register-ObjectEvent $ds[$i] -EventName DataSourceChangedEvent -SourceIdentifier "TEV$i" -Action { $global:RXcount++}) }
# touch properties to trigger events and wait for arrival
$ds | select latestrecoverypoint  > $null #do not use [void] coz does not trigger
$begin = get-date
$m = Measure-Command { while (((Get-Date).subtract($begin).seconds -lt 30) -and ($RXcount -lt $ds.count)) {sleep -Milliseconds 100} }
if ($RXcount –lt $ds.count) { write-host “WARNING: Less events arrived [$RXcount] than expected [$($ds.count)]” }
Unregister-Event *

# Look for stale data
$staleDate = (get-date).AddDays(-1) # 24 hours old is our limit
$count = 0
foreach ($dsi in $ds)
  if ($dsi.LatestRecoveryPoint -lt $staleDate)
    write-host "`$ds[$count] $($dsi.ProtectionGroup.FriendlyName) : $($dsi.ProductionServerName) : $($dsi.LogicalPath)"
  $count ++


Microsoft Data Protection Manager: Start a Consistency Check on all Inconsistent Replicas with PowerShell

I'm a big fan of MS DPM and have been using it for years.  The one place where it really suffers, though, is the management console.  Even in DPM 2010, there are very few things you can do in a batch sequence, which is a common need for DPM administrators.

From time to time, your server may get a large amount of inconsistent replicas.  This is usually due to something outside of DPM's control.  For example, one DPM server I manage is a VM.  If the host server suspends the VM, then resumes and the target server it was backing up before suspend is suddenly offline (such as during a reboot cycle from updates), you can get inconsistent replicas.  There are numerous other scenarios, but you get the drift.  When this happens, the management console forces you to right click on every single alert individually and select "Run a synchronization job with consistent check."  (You can also just wait for the next automatic consistency check interval, but that's not always ideal.)

Luckily, PowerShell provides a better way to kick off a manual consistency check.  Behold!  Here is my DPM PowerShell script that kicks off a consistency check on every inconsistent replica.  This is tested with DPM 2010, but should also work with DPM 2007.

$pg = Get-ProtectionGroup
foreach ($pgi in $pg) { $ds = get-datasource $pgi; foreach ($dsi in $ds) { if ($dsi.State -eq 'Invalid') { Start-DatasourceConsistencyCheck $dsi | out-null; $dsi.ProductionServerName + " :: " + $dsi.DisplayPath } } }



Who Will Vote Against the Interests of the Downtrodden Wealthy?

House Democrats are forcing the Republicans to admit with their vote that they just want tax breaks for the rich.  The Democrats are trying a (sneaky or awesome, depending on your political preference) procedural move to force the hand of Republicans.  Speaker-in-waiting John Boehner is turning a brighter shade of orange.   Are Democrats finally learning how to play politics the same way as Republicans?  I hope so.  I'm basically an o-bot, it seems, by Liberal Intertubez Blog Commenting Standards, but I am oh-so-very-glad to see some hardball being played after several days of the media reporting that Obama apologized for not being more accommodating to the guys who got our country into the mess it's in.

So will the Republicans vote against tax cuts because the uber wealthy aren't getting their (unfair) share?  A lot of them will, is my prediction, but we'll see.  Either way, the media headlines will emphasize the delicate fee fees of the Republicans being hurt, and not the fact that (some?) Republicans vote against tax breaks for the middle class.  Just you wait and see.  Extra credit for lazy reporting for anybody in the media refers to this bill as a "tax hike" (on the wealthy) by Democrats.

Either way, I'm just happy to see the House Dems go out in a blaze of glory.  It is hte awesome!


My New Pet Peeve

My new pet peeve is when technology pundits that use the phrase (or a variation thereof), "designing for 1985" when talking about traditional mouse/keyboard input modalities.  This is usually said as a derogatory comment to Microsoft, but also includes other companies that have not yet jumped headfirst into the latest fad of iPad computing (if you can call running applets on a multimedia presentation device "computing.")

I think touch screens a la cell phones and slate devices have their place and can be awesome, but just, for a minute, try imagining typing a long document on an iPad compared to basically any traditional computer setup.  The very thought of it is tiring to me.  I need a nap.  My point is that mouse+kb has been successful for so long because when you know how to type (probably not many tech magazine writers know how without staring at the keyboard and pecking with their index fingers, unfortunately), the keyboard is incredibly fast for input.  And for situations that you can't use the keyboard, the mouse is still faster than touch screens.  With a mouse you can quickly jump from one part of the screen to the other and precisely zero in with just the smallest flick of your wrist.  Touch screens require your arm and hand actually extend to each of the affected areas on the screen.  When you have two or three monitors, having to touch for all direct-contact input with controls on the screen would actually be quite slow, even if it is satisfying in a "I feel like I'm on Star Trek" kind of way.

All that said, kb+mouse+touch is the ultimate win.  You get the best of all possible worlds.

Which brings me back to the original article that sparked this rant.  I completely disagree with the unimaginative Lenovo Technology Director.  Windows 7 on a slate device sounds incredibly awesome.  I would take that in a heartbeat over iOS, Android, or the other proprietary OSes.  Apparently somebody hasn't gotten the memo about all the touch work that went into Windows 7.  It does everything your precious, precious iPad does, plus it can actually run real productivity software.


America Spoke: No Socialists Win in Election

Now that the 2010 election is over, I think it's safe to say that Americans have clearly spoken: nobody on the Socialist Party ticket won.  Clearly this means America is a center-right country.  At the same time, Obama should have used the bully pulpit more, because progressive voters are fragile creatures who would rather let their opponents win and go scorched earth than support a moderate on their own ticket.

Yea, also, to, this is all stupid and wrong.  I can say this because I have as much knowledge and credentials as most of the lip-flapping sputter coming out of the beltway media.  I posted the following comment on Balloon Juice (one of the only sane political blogs on the intertubes), but had to share it here to.

Regarding this article.

My comment…

So much analysis. So much wrong!

Everybody keeps pointing to their favorite ponies and stating, “if only Obama would have petted this pony more often and with a more vigorous stroking technique, Democrats would have done better.”


Despite what the Firebaggers say, Obama, Pelosi, and Reid passed a lot of pretty great stuff. Pretty great stuff can also be scary because it’s new and different. Could the pretty great stuff have been even awesomer? As always, yes, IF Republicans weren’t such total douchebags.

I will take pretty great stuff (that had a possibility of passing and did) over super awesome great stuff that could never pass. I will also definitely take the pretty great stuff over whatever the beltline Pony of the Day is.

I see a lot of pointing to the economy. That’s historically correct and correct today too. But I’m glad Obama didn’t spend the last two years primping a new stimulus pony. It could even have had sparkles, braided hair, and an “I love you” tattoo on its leg, but it never would have passed!

I think this shows really good leadership and a true commitment to this country for Obama, Pelosi, and Reid. They walked in knowing how much they were truly fucking themselves in the next election or two, but did the stuff they did anyway, because it was the right thing to do.

Like it or not, that’s how American politics works. Good stuff happens. When it does, there’s a backlash from entrenched interests and fear. Shit, there was a major backlash against social security (there still is today)! But it’s in no danger of going away because even conservative Americans rely on it. The same will be true for much of what was passed in the last two years.

Relish in the liberalism of the last two years. It will be back. Fear can’t last forever.

Also, too, THIS.


WTF Has Obama Done So Far?!

The winningest site for those of us on the left that understand that governing this country is more than just a bully pulpit and getting angry: http://whatthefuckhasobamadonesofar.com/




A while back I created the SCHANNEL.ADM administrative template to allow SCHANNEL ciphers and protocols to be configured in a GPO and pushed out to all servers in a domain.  Basically, in any Windows Server version before 2008, the SSL 2.0 protocol was enabled, and so were a bunch of weak ciphers, like 40-bit RC2 or 56-bit DES.

Well, recently one of the sites I manage began failing a HackerSafe test for ciphers and it seems I missed a few ciphers in my template.  Why HackerSafe only discovered this now instead of years ago is anybody's guess.  It is run by McAfee now, so I wouldn't bet the farm on their audits…  But I digress.

I updated the template on my website for download.  In addition to having  a few more ciphers, I also put in the description "(Recommend Disabled)" next to all the weak ciphers.

Remember that these values are not fully managed policy entries and if you delete your GPO, the affected server will not automatically revert to default values – you will be left to clean up the registry.

More information on enabling/disabling protocols and cipher in Windows can be found here: http://support.microsoft.com/kb/245030

Download SCHANNEL.ADM here.

Recent Comments
  1. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Derek: Edward, great find. +1 on the fix... Thanks!!
  2. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    milo: Thanx MIKE - this helped me: DPM 2016 setup will fail if you have SQL Server Management Studio (SSMS...
  3. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Terry: Edward, you are the Man!!!! Looked for a solution for hours, then found your post and BAM!!! it worked...
  4. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Mr. JoeM: Edward! Thank you, saved me hours of work.
  5. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Brian: Thank you so much Edward! :-)
  6. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Tom: Thank you Edward! After beating my head against a wall for days, tried your suggestion out and lo and...
  7. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Mike: DPM 2016 setup will fail if you have SQL Server Management Studio (SSMS) V17.x installed. Re-Install...
  8. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Rob: Edward, thanks man! you were a lifesaver. My scenario was Win Server 2016 from scratch, SQL 2016 (N...
  9. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Edward: It also crashes with the 4387 error if you have the SQL Management Studio 17 tools installed. Installing...
  10. Re: DPM 2016 + SQL 2016 and "An unexpected error occurred during the installation" ID: 4387
    Ram: Hi - I followed richsmif instruction and was able to successfully install DPM 2016 on SQL 2016. Completed...