My blog has moved!

You should be automatically redirected in 6 seconds. If not, visit
http://www.dullroar.com
and update your bookmarks.

Sunday, February 23, 2014

Moving off the Googleplex

I am slowly moving off Google properties. I no longer feel like giving my content to the All Seeing Eye. So I have migrated all these blog posts to my web site, dullroar.com, and all new content will be posted there. If you subscribe to this blog via a feed, update your subscription here.

Friday, January 10, 2014

Problems connecting to a Windows Remote Desktop Gateway using Windows 8

I am writing this in case anyone finds it while searching for the following symptoms. It is the two things I had to do to get a Windows remote desktop (RDP) connection to consistently work from a Windows 8 (8.1) client to a Windows 2012 server via a Microsoft Remote Desktop Gateway (RDG) connection.

Symptoms:

  1. You set up an RDP connection via a RDG. It works correctly the first time, but all subsequent attempts to login result in the remote desktop client prompting for your credentials but then returning to the RDP connection prompt again without connecting.

    And/or:
  2. You set up an RDP connection via RDG. It works correctly, but the connection drops and then automatically reconnects every 60 seconds or so.
If either of these are happening to you, read on.

Symptom 1 - First connection works, subsequent connections don't

The problem comes from how you answer the prompt the first time you successfully connect to the desktop. Depending on your RDG's policy, you may receive a "Logon Message" prompt similar to the following:


Be careful how you answer the two check boxes at the bottom. You must check the first one ("I understand and agree to the terms of this policy") to complete logging in. However, if you check the second one ("Do not ask again unless changes to policy occur") and your client machine is not under the same group policy as the server, i.e., you are connecting to your work's RDG via an RDP connection on your home machine, you will get symptom #1. So leave it unchecked, which means you will have to answer this prompt every time you login via the RDG, but so it goes.

If you have already checked the second check box and are getting symptom #1, the following may be helpful.

Since the following involves editing the registry, you take on all risk by doing this, and for this post I presume you know what you are doing. I am simply outlining what worked for me. Be careful and don't just blindly follow these instructions but use them as a starting point for your own problem determination and correction.
  1. I cleaned up all Remote Desktop entries in the registry dealing with the target RDP server (using its name to search on). These will appear under HKCU\Software\Microsoft\Terminal Server Client\Servers\<servername> (where <servername> is the problematic server). I simply deleted the key for the problem server (only).
  2. There were also entries under HKCU\Software\Microsoft\Terminal Server Gateway\<domain> (where <domain> is the internal A/D domain name of the server I was connecting to). Under that was a key called Messages. This had the message from the above logon prompt cached in it. I simply deleted the key for the specific domain (only).
  3. When I then tried to reconnect I was presented with the above logon message box again. Progress! On a hunch I then checked the first check box but left the second unchecked and from then on was able to reconnect successfully (albeit always having to answer the first check box in the logon message prompt).
This symptom only happened on my home box. On my work laptop it did not, even when the second check box was checked. My theory is that since the work laptop is under the same Active Directory group policy as the RDG server it all "just works," but since the home box is not and has no way of checking policy until it connects, it causes an issue.

Symptom 2 - Connection keeps disconnecting after approximately 60 seconds

This one seems to be a specific "Windows 8 thing" if you search for it on the 'net. This post has a lot of things to try in the long comment thread. However, the one that worked for me was changing the registry to disable UDP for RDP clients. Note that the original comment that proposes the registry change for this gets the value name wrong. This post has the correct name in a comment correcting that comment (got that? :). To be clear, the value name is fClientDisableUDP (not tofClientDisableUDP).

Since the following involves editing the registry, you take on all risk by doing this, and for this post I presume you know what you are doing. I am simply outlining what worked for me. Be careful and don't just blindly follow these instructions but use them as a starting point for your own problem determination and correction.
  1. Navigate to HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\Client.
  2. Create a DWORD named fClientDisableUDP and assign it a value of 1.
That should be all there is to it. After making the above change I had a multi-monitor RDP session via the RDG work uninterrupted for hours.

I hope this post helps someone else who is searching for answers to these issues. If it helps you, drop me a comment and let me know.

Friday, December 27, 2013

Release my chains

Back in the dark days before the ubiquity of USB1 there was a standard for connecting devices called SCSI. As time went on it ended up having multiple interfaces such as "Fast SCSI" and "Ultra SCSI" and so on. Which meant that along with having to understand the horrors that were device numbers and cable terminators your average techie ended up with a box of different SCSI cables, all of them outrageously expensive. This was made worse by the fact that over time you ended up with various "this-interface-to-that-interface" adapters and gender-benders, because those were cheaper than buying a new cable. It wasn't uncommon to have to take a cable out of your tangled box and then find an adapter (or two!) to fit either the particular interface on your SCSI card or the device. To put it in technical terms, it was a massive pain in the ass.

I gladly dumped all my SCSI devices and cables and whatnot some years back. But recently I've noticed a similar and disturbing trend. Behold:
These are all adapters for changing various video cables into other types. Just in this picture alone I have VGA-to-DVI, HDMI-to-DVI, and DisplayPort-to-HDMI. I don't own any Apple equipment, or I am sure I would have Thunderbolt-to-whatever as well. And like SCSI, I find most video cables to be ridiculously priced ("It's just a $50 cable"). I presume HDMI will be the winner, at least outside of Appleland. But it will take a while, and I still have a lot of VGA/DVI monitors floating around the house that will have to die or go the way of the landfill before we get to that place.

Personally, though, I am hoping that something like WiDi takes off (and wireless USB while I'm wishing). Just as wireless routers have gotten rid of the need for network cables for most homes (not ours, but most), and wireless keyboards and mice have cleared my desktops at work and home, it would be nice to get rid of the remaining rat's nest of cables I have for connecting two devices together. Of course then we'll all get cancer from the increased RF signals bouncing around our homes.

1 And before USB became a power supply standard as much as an interface one.

Thursday, December 19, 2013

Stacked bar charts in ASP.NET with no code-behind

[This is posted as an intellectual exercise someone else may find interesting or useful.]

I am currently working on a project at work that involves among other things gathering metrics for our various scanners across all of our locations. We have a heterogeneous scanner environment (which raises its own issues) with 16 models of scanners from Canon, Fujitsu, Lexmark and Xerox spread across 24 different sites. Some sites only have one scanner, others have two or three. I wanted to show total scanner volume by site, broken down by scanner model at each site. This is a perfect application for a stacked bar chart.

I have been using the ASP.NET charting control for other charts in this project, and purely by chance (not design) I had done everything I needed with each chart in pure markup and SQL with no code-behind for the Web page until I needed this stacked bar chart. Then I had a hard time finding any information on the Internet about how to accomplish a stacked bar chart in pure markup (because I wanted to see if I could).

The issue is that for a stacked bar chart to work, there need to be multiple series (in my case, scanner models), and each series has to have the same number of data points, i.e., in my case each series has to have 24 locations. This is because the stacked bar chart is "dumb" and simply stacks the first column in each series on the first bar, the second column in each series on the second bar, and so on. But the locations each only have one to three scanners, so at most each location only has approximately 20% of the scanner models available. Needless to say, a query something like:


SELECT Branch, ScannerModel, COUNT(*) AS Scans FROM ScanMetrics
GROUP BY Branch, ScannerModel
ORDER BY Branch, ScannerModel

...is going to produce output like this:


This is not what we need, since the output is "ragged" (each location has a different number of scanner models).

I thought about it some more and finally figured out what I needed was to have my data in a pivot table. Using the output from that, I could then do the stacked bar chart in pure ASP.NET markup. Here is a view I created to give me the pivot output I needed:


CREATE VIEW BranchScannerScansPivot
AS
WITH Branches
AS
(
        SELECT DISTINCT
                Branch
        FROM ScanMetrics
),
Scanners
AS
(
        SELECT DISTINCT
                Branch,
                ScannerModel
        FROM ScanMetrics
),
BranchScannerCombos
AS
(
        SELECT DISTINCT
                B.Branch,
                S.ScannerModel
        FROM Branches B
        CROSS JOIN Scanners S
),
BranchScannerCounts
AS
(
        SELECT
                BSC.Branch,
                BSC.ScannerModel,
                COUNT(SM.ScannerModel) AS Scans
        FROM ScanMetrics SM
        RIGHT OUTER JOIN BranchScannerCombos BSC ON
                SM.Branch = BSC.Branch
                AND SM.ScannerModel = BSC.ScannerModel
        GROUP BY
                BSC.Branch,
                BSC.ScannerModel
)
SELECT
        *
FROM BranchScannerCounts BSC
PIVOT(SUM(Scans) FOR ScannerModel IN
(
        [CANON2200],
        [CANON3080],
        [CANON3100],
        [CANON3300],
        [CANON3320],
        [CANON3570],
        [CANON4035],
        [CANON4080],
        [CANON5035],
        [CANON5051],
        [CANON6010],
        [CANON6050],
        [FUJITSU6010],
        [LEXMARK658],
        [LEXMARK796],
        [XEROX5745]
)) AS Scans

Selecting from this view produces a 24-row result set with exactly the output I need:


It is a "rectangular" grid of values for each combination of location and scanner model.

With that data in hand, then producing the stacked bar chart in pure markup is simply an exercise in copying and pasting 16 series (one for each scanner model). Here is the entire ASPX file (some wrapping may occur):



<%@ Page Title="Metrics" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Metrics.aspx.cs" Inherits="ScanMetrics" %>

<%@ Register Assembly="System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI.DataVisualization.Charting" TagPrefix="asp" %>

<asp:Content runat="server" ID="FeaturedContent" ContentPlaceHolderID="FeaturedContent">
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1><%: Title %>.</h1>
                <h2>Scan statistics.</h2>
            </hgroup>
        </div>
    </section>
</asp:Content>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <asp:Chart ID="Chart1" runat="server" DataSourceID="SqlDataSource1" Height="800" Width="800">
        <Titles>
            <asp:Title Text="Scans by Branch and Scanner Model"></asp:Title>
        </Titles>
        <ChartAreas>
            <asp:ChartArea Name="Branch">
                <Area3DStyle Enable3D="true" />
                <AxisX Interval="1">
                    <MajorGrid Enabled="false" />
                </AxisX>
            </asp:ChartArea>
        </ChartAreas>
        <Series>
            <asp:Series Name="CANON2200" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON2200">
            </asp:Series>
            <asp:Series Name="CANON3080" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON3080">
            </asp:Series>
            <asp:Series Name="CANON3100" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON3100">
            </asp:Series>
            <asp:Series Name="CANON3300" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON3300">
            </asp:Series>
            <asp:Series Name="CANON3320" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON3320">
            </asp:Series>
            <asp:Series Name="CANON3570" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON3570">
            </asp:Series>
            <asp:Series Name="CANON4035" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON4035">
            </asp:Series>
            <asp:Series Name="CANON4080" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON4080">
            </asp:Series>
            <asp:Series Name="CANON5035" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON5035">
            </asp:Series>
            <asp:Series Name="CANON5051" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON5051">
            </asp:Series>
            <asp:Series Name="CANON6010" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON6010">
            </asp:Series>
            <asp:Series Name="CANON6050" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="CANON6050">
            </asp:Series>
            <asp:Series Name="FUJITSU6010" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="FUJITSU6010">
            </asp:Series>
            <asp:Series Name="LEXMARK658" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="LEXMARK658">
            </asp:Series>
            <asp:Series Name="LEXMARK796" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="LEXMARK796">
            </asp:Series>
            <asp:Series Name="XEROX5745" ChartType="StackedBar" ChartArea="Branch" XValueMember="Branch" YValueMembers="XEROX5745">
            </asp:Series>
        </Series>
        <Legends>
            <asp:Legend Enabled="true" Alignment="Center"></asp:Legend>
        </Legends>
    </asp:Chart>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString1 %>" ProviderName="<%$ ConnectionStrings:ConnectionString1.ProviderName %>"
        SelectCommand="SELECT Branch, CANON2200, CANON3080, CANON3100, CANON3300, CANON3320, CANON3570, CANON4035, CANON4080, CANON5035, CANON5051, CANON6010, CANON6050, FUJITSU6010, LEXMARK658, LEXMARK796, XEROX5745 FROM BranchScannerScansPivot ORDER BY 1 DESC"></asp:SqlDataSource>
</asp:Content>


And here is the output:


Mission accomplished.

Now, I am not saying I think this should be a standard approach. For one, I find it "fragile" as a solution since it requires both the SQL pivot and the chart series markup to know in advance the number and names of the scanner models. Thus, adding a new model would require code changes to both the view and the Web page.

However, I did want to publish this because I have found when working with the Microsoft chart control that often there are fairly straightforward markup-only approaches, but most samples on the Web tend to be a mishmash of markup and code with no good discussion about why a given property is set in markup and another is set in the code-behind. Also, depending on your environment, it may be easier to make changes to markup in production than to compiled code. It can certainly be easier to "tweak" markup.

And finally, I just thought it was an intellectual challenge, and hope you found it interesting as well.