Tuesday, October 29, 2013

Turning a Wyse Xenith 2 into a Web Kiosk

Introduction


Designing a computer kiosk, where people can walk up and access a set of information online without being able to access all websites, is an application that seems tailor made for a thin client. Low power usage, remote management, no data stored locally - these are all things you want when you're deploying a computer in a public area. However, locking down the machine -- Xenith side and windows side -- can be tricky. Here's a quick guide to get you going





A Dedicated User


The first thing you need to do is setup a user account that will you can use for the kiosk. You'll need the machine on the domain, but presumably most users accessing an information kiosk are not going to have a logon to your domain.

So create a user, and give them logon access only to the Kiosk VM(s). You'll also want to make the password something totally unrelated to any other password you use on your systems. While I haven't found a way to extract the password for the Xen.ini auto logon, I'm sure it's possible; it pretty much has to be passed to it/stored in cleartext.





Locking down the Thin-Client - Xen.ini config


Note: These configurations are done on Firmware 2.0_104 - mileage may vary on different firmware

Beyond the usual lock-down you'd have on any thin client, there's a few special configurations for the Xen.ini file you'll want in a Kiosk environtment

USB Devices


You probably won't want users to be able to plug in USB devices to the Kiosk - all sorts of bad things could happen, and there's really no reason to have it in a kiosk. Physical security goes a long way here (have the thin client in a locked cabinet where users can't access it) but you can disable forwarding of USB Devices through Xen.ini as well. It'll look something like this; disabling sound is optional.

SessionConfig=ALL unmapprinters=yes unmapserials=yes disablesound=yes unmapusb=yes unmapclipboard=yes

 Auto Login


As I mentioned, users accessing a public information kiosk probably won't have credentials for your domain. This means you'll have to log them on automatically with the generic user. This will make the thin-client invisible to the user, and prevent domain users from logging in with their accounts. The configuration will look like this
Signon=Yes 
DefaultUser=kioskusr
Password=asupersecurepassword 
    DomainList="yourdomain"

 Disable Thin Client Lock


You won't want users to be able to lock the terminal - since your target audience won't have any idea what the password is. So you'll want to disable the key sequences that can lock the terminal.  

 Note: There seems to be a bit of a bug with the key sequences config. According to the documentation, all you should need is "KeySequence=No" in my testing that doesn't work you must user the following.

KeySequence=yes ctrl+alt+down=no ctrl+alt+left=no ctrl+alt+right=no win+L=no

Other Considerations

Those are all of the configurations I made special to Xen.ini for a kiosk. However, your default Xen.ini may be less locked down than mine, so here's some other configs that will probably be necessary.
  • Disable G key reset: "EnableGKey=no"
  • Lockdown Thin: "Privilege=None, LockDown=yes"
  • Disable that annoying system beep: "Device=audio mute=3"





XenDesktop Setup


Note: This setup is on XenDesktop 5.6 - setup may differ (and in fact does) on different versions.

I won't go through the process of setting up machines on XenDesktop. If you haven't created machine pools and delivery groups yet, you're reading the wrong guide. This is just a quick note to show how to assign a VM to specific thin-client. This works better than assign a VM to the kiosk user, because it prevents the kioskusr account from being used on other thin clients.

Full information can be found On Citrix's Support Site. From PowerShell on the DDC, run the following commands - replacing "domain\machine" with your kiosk machine name, and the IP with the address of your thin client.

Add-PSSnapin Citrix.Broker.Admin.*
Set-BrokerPrivateDesktop DOMAIN\MACHINE_A -AssignedIPAddress 10.11.132.7






Windows Customization/Lockdown

Locking down windows so that users cannot get out of the Kiosk mode is key. You don't want users to be able to access any files or other programs on the machine. Optionally you'll also want to restrict web browsing so that users cannot access things like facebook,news sites, or any inappropriate content. For this example I am using Google Chrome because it has a built-in kiosk mode and a bunch of add-ins that make it easier to restrict web browsing.

Some of these precautions are redundant, and you may be able to make a secure environment with just some of them. My goal was to create a system that was easy to manage while being escape-proof, so there's generally a reason for the redundancy.

Disabling CTRL+ALT+DELETE

The most difficult thing to disable on windows is the ctrl-alt-delte sequence; however it is necessary to disable this so that users cannot use it to escape the kiosk mode. The ctrl+alt+delete sequence is embedded deep in the windows operating system and, because it is a security concern and would break normal usage, cannot be disabled through conventional means. The only way to disable is to stop the interpreting of the ctrl,alt, and delete keystrokes (or at least ctrl, and alt). To do this, we must re-write the scan codes for those keys in the registry. I won't go into much detail here, because the article I'm linking does a pretty good job of explaining how to do this, and how it all works.

Don't reboot the machine after you apply this before reading the next section.

With that, enjoy this wonderful article

Removing the CTRL+ALT+DELETE for Logon

The most notable thing disabling ctrl+alt+delete does is break the logon process. If you can't press ctrl+alt+delete to logon, you're going to lock yourself out of the machine. Even XenDesktop utilizes this (it has to) so we need to turn it off.

So in keeping with the spirt of just linking to other sites, here's the Microsoft KB article on how to disable the "require ctrl+alt+delete for logon" feature.

Using AutoHotKey to reassign keys

The northcode article on remapping keys in the registry does a good job of disabling most of the problem keys that allow users to escape from a kiosk mode. It doesn't get all of them though. Notably F1, which usually brings up help menus, and right-clicking, which brings up all sorts of difficult-to-manage context menus. Now, we could add this through the scan code method above, but I find it more useful to use the program AutoHotKey (ahk) to do some remappings. This is because it is far easier to manage and more humanly readable, and because it is simple to remap things to something other than nothing.

Example
Sendmode Input
SetTitleMatchMode 2

F1:: Send {Browser_Home}
F9::.
RButton::.

The first two lines just configure some settings for the AHK program, you can read more about what they do specifically on the AHK website (Sendmode Input | SetTitleMatchMode). The next line re-binds the F1 key to the browser home button. This is useful because the home button will be hidden in Kiosk mode, and the normal home-button hotkey (alt+home) will be disabled.. The other two lines rebind F9 and the Right mouse button to do nothing. You can read a whole list of keys/rebindings here on the AHK website

I rebound all of the Fkeys and most shift+key shortcuts (user's can fill out forms on my kiosk, so disabling the shift key all together is not practical).

Using AutoHotKey as an Idle Timer

Generally when you have a kiosk, it is in a public area. So you'll probably want a nice welcome page to greet each new user. Since the users can hardly be expected to go back to the home page themselves when they are done, we need a way of detecting when a user has walked away from a kiosk, and sending the browser back to the home page. It turns out this is pretty simple to do with AutoHotKey.

Loop
{
WinActivate Chrome

if A_TimeIdle >= 90000
{
Send {Browser_Home}
}

Sleep 3000
}

This starts an infinite loop that checks how long a user has been idle every 3 seconds. The WinActivate Chrome line is another bit of security. Sometimes when the thin auto-logs-in, the taskbar is visible - that is chrome is not the active window; so someone resetting the thin client could theoretically escape the kiosk mode. This command forces chrome as the active window if it is not currently. Because it does this every three seconds, it also adds security because it means someone won't be able to do much if the user finds a way to alt-tab out of chrome.

A_TimeIdle is a system variable in AHK, it automatically keeps track of how long it has been since the last mouse/keyboard input. In my script, if there hasn't been any input in 90 seconds (90000 milliseconds), it resets to the home page. I choose A_TimeIdle here rather than A_TimeIdlePhysical (which detects only physical mouse/keyboard input, not input from programs/scripts) because otherwise after 90 seconds it would refresh the page every 3 seconds. Using A_TimeIdle, when the Send {Browser_Home} command is sent, it detects that as input, and resets the counter; it will wait another 90 seconds before refreshing again.

The last line is just a simple wait command that prevents the loop from running too quickly and hogging system resources.

Another way I found works, if you want to check for idle more often, but not have the page refresh constantly, is to run the check, but then set a delay after the first refresh. For example, This Script checks every 30 seconds, but then waits 2 minutes after it detects idle before it checks again.

Loop
{
WinActivate Chrome

if A_TimeIdle >= 30000
{
Send {Browser_Home}
 Sleep 120000
}

Sleep 3000
}


I'm realizing this post is probably already waaaay too long, so I'm going to arbitrarily cut it here. Stay tuned for next installment where I'll detail setting up chrome in kiosk mode, setting up startup/login scripts, and restricting user access to unauthorized websites.

Next part is up!

Tuesday, October 1, 2013

"Display" pane for SAP analysis for Microsoft Excel 1.4 Doesn't open.

I've been having ever so much fun getting pre-office 2013 add-ins to work in Excel 2013. For the most part adding them to the XLSTART folder in the office install directory (so they load automatically with excel) has fixed the problem. This only really works with XLA/XLAM type add-ins though. The last couple of days I've been working with one that launches via an exe and shows in excel as a .dll.

The add-in is "Analysis for Microsoft Excel" version 1.4, it's an add-in associated with SAP. The add-in is launched via an executable (BiSharedAddinLauncher.exe) and shows up in excel > file > optionas > add-ins> as a .dll (bishared07addinshim.dll).


The Short Version


The problem ended up being the start page (the new office 2013 thing that displays a bunch of templates and adds extra clicks before you can actually get work done). Disabling the start page (through group policy, you'll have to download/"install" the office 2013 ADMX files from microsoft) allowed the add-in to load properly.


The Long Version


So when we tried to launch the add-in on most computers (worked on some, which was weird) we would see the add-in load, and the appropriate tab on the ribbon would appear. Most functions would also work. However trying to open the "Display" pane didn't work. The icon would light-up like it was open, but the panel would never show up. 

This problem occurred on windows 7 x86 with office 2013 x86 and on a windows 2008R2 with office 2013 x86 running RDS. 

After much reinstalling (including the entire office suite) I finally found that launching the add-in once excel was already open (file > options > add-ins > com add-ins > go ) worked. This suggested that, for whatever reason, the add-in was not fully loaded when it was launched at the same time as excel. Obviously, adding the add-in in this manor each time you wanted to use it would be much less convenient that clicking the executable from the start menu. 

On a whim, a whim fueled mostly by my hate of the start page, I decided to disable the start page and low-and-behold the problem stopped. The add-in and all of its features work like they're supposed to. I can't imagine why the start page in excel would keep an add-in from loading properly. 

Oh, on a semi-related note, the "excel is not the current default program for all spreadsheet files" dialog also blocks add-ins from loading; blocks them entirely, they never load, you have to click  "don't show this again" and re-launch the add-in to get around it.

Monday, September 23, 2013

Powershell Rename-Computer and Add-Computer firewall -- non-domain joined machine

Had a challenge today where I needed to join a bunch of machines to our domain (a bunch of cloned VMs to be exact). I found I could do this through a pretty simple powershell script as follows.

$credlocal = get-credential
$creddomain = get-credential

$machinelist = import-csv c:\temp\machines.csv

foreach($line in $machinelist)
{
 
    add-computer -computername $line.IP -localcredential $credlocal -domain my.domain -domaincredential $creddomain -Newname $line.Hostname -restart

}
Where machines.csv is a CSV file with Hostname/IP pairs and a header row. It prompts for credentials twice, once for the local/built-in admin, then one with domain-join permission

However, when I actually tried to run this I got the following error.

add-computer : Cannot establish the WMI connection to the computer 'xxx.xxx.xxx.xxx' with the following error
message: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)). 
At C:\temp\renamecomputer.ps1:8 char:5
+     add-computer -newname $line.Hostname -computername $line.IP -localcredent ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (xxx.xxx.xxx.xxx:String) [Rename-Computer], InvalidOperationException
    + FullyQualifiedErrorId : RenameComputerException,Microsoft.PowerShell.Commands.RenameComputerCommand
This error was pretty simple, because these machines are not domain joined, the $c/$admin/etc shares are not enabled. You can enable the pretty simply see here:

http://everydaynerd.com/how-to/fix/windows-7-enable-admin-share

After that though, I was getting:

 add-computer : Cannot establish the WMI connection to the computer 'xxx.xxx.xxx.xxx' with the following error
message: The RPC server is unavailable. (Exception from HRESULT: 0x800706BA).
At C:\temp\renamecomputer.ps1:8 char:5
+     add-computer -newname $line.Hostname -computername $line.IP -localcredent ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (xxx.xxx.xxx.xxx:String) [Rename-Computer], InvalidOperationException
    + FullyQualifiedErrorId : RenameComputerException,Microsoft.PowerShell.Commands.RenameComputerCommand
This error turned out to be less straight-forward to fix. The short version is, you have to allow RPC calls through the firewall (something AD does automatically, either by design or by settings that have been in our domain long before I started working here) which isn't really easy because of Asynchronous callback. Basically, all incoming RPC calls go to port 135, no problem, you can open that. But so that calls don't tie up that port, all the first request returns is a new port for all future calls to come in on - this is more problematic because this appears to be ANY non-standard port; you can't very well open the firewall to all ports about 5000. Also, all of the remote-management rules that are in advfirewall (disabled) don't see to have any effect on this problem. Luckily after some digging, I found you can use program-based firewall rules to get things going.

This is article is for windows 8.1 embeded, so step #2 doesn't work on win 7, but everything else seems to run. Also, step #1 is the same reg key created from the last link.

http://msdn.microsoft.com/en-us/library/jj980508(v=winembedded.81).aspx

I re-ran the command after each step, mine started working after step 5, so I think that's the key rule, but the others don't seem to hurt. Of course, this is something that has to be in the master image, so now I have reclone about 50 VMs but hey, testing things like this before the cloning is overrated.




Wednesday, September 18, 2013

ICA Connection request denied because AutoLogon was not possible and EnforceAutoLogon is active

This is what I spent my morning doing.

So in the ongoing quest to get a XenDesktop 7 environment going. I was having a problem where, when logging in as a non-admin user, the desktop would appear for a split-second -- you could just make out the windows login screen -- before kicking the user back to the XenDesktop login (Wyse Xenith 2 login, in this case).

The only Error in the event log, the one that makes this posts title, was as follows

  • Error | ICA Service | EventID: 34 | ICA Connection Request denied because AutoLogon was not possible and EnforceAutoLogon is active.
Googleing this error code returned nothing, 0 results. Googleing the symptoms returns some things, but nothing that solved my problem.

In my case it was simple and stupid. I had put these new machines in an old OU in AD. This OU had, unbeknownst to me, a GPO which denied local login to non-admins (OU was for remote-desktop machines in the past). Removing the GPO fixed everything, go figure. 

If this isn't the case in your situation, the error so far as I can tell, is caused when the pass-through authentication fails. This can be caused by any number of things (like bad GPOs), and there's a lot of good support forum posts about the non-stupid causes of this problem, so I won't go into much detail here. But here's some things I researched that might get you pointed in the right direction.

XenDesktop Passthrough Authentication failure:

Exact symptoms I described, but with a different cause:

Tuesday, September 17, 2013

Windows RDS (Terminal Server) - Stuck Applying group policy

Had a lovely time yesterday when the terminal server (2008 R2 running RDS) that our users use to access programs/files from off site decided to tank. Luckily we have a backup server... except that one was tanking as well.

The short version is that, at some point over the weekend, the server began taking inordinate amounts of time applying group policy settings, making user log on take upwards of 5 minutes and killing server performance. Some of the error available in event viewer included

  • warning|grouppolicy|eventid:1090|"Windows failed to record Resultant Set of Policy (RSoP) information, which describes the scope of Group Policy objects applied to the computer or user. This could be caused by Windows Management Instrumentation (WMI) service being disabled, stopped, or other WMI errors. Group Policy settings successfully applied to the computer or user; however, management tools may not report accurately."
  • warning|winlogon|eventid:6005|"The winlogon notification subscriber <GPClient> is taking long time to handle the notification event (CreateSession)."
  • warning|winlogon|eventid:6006|"The winlogon notification subscriber <GPClient> took xxx second(s) to handle the notification event (Logon)."
On the user side you would see "Applying user Policy..." for 5+ minutes while trying to login. When I tried to reboot one of the servers it took (quite literally) several hours to get past the "Applying computer settings" screen. On reboot, in task manager you'd see an svchost process using 2+GB of ram and 100% cpu (limited to one core, so it was ~13% in my case). Killing this process would cause all sorts of interesting errors to occur - best I can tell this was the GPclient service. 

After a few hours of trying different things - notably de-joining  from the domain, which didn't work and took forever - I finally figured out it had something to do with the WMI repository. From command line I tried:
winmgmt /verifyrepository
winmgmt /salvagerepository
Neither of these ever returned anything (let them both run, separately, for 30 minutes).  While either was running there would be a winmgmt.exe process in task manager using 100%/13% CPU and progressively more RAM. So, since neither of those worked I tried:
winmgmt /resetrepository
Boom! Everything was back to normal. It was almost disconcerting how quickly everything started working again. Rebooted the server and it shutdown and restarted in its normal couple of minutes. I have yet to discover exactly what caused the wmi repository to corrupt but at least for the time being users are able to get to their stuff.
 

Wyse Xenith 2 - Unable to set up connection (err=-5914)

This error, which I mentioned in the post just minutes ago, turned out to be a pretty simple fix. As I also mentioned in the last post, I'm building up a XenDesktop 7 environment to replace our current XenDesktop 5.6 Environment, and I'm trying to document all of the things that I figure out somewhere where other people might benefit from them.

Anyway, like I said, this fix was pretty simple. The error I was getting (This is in the Event Log of the Wyse Xenith 2 client) was :


  • xx:xx:xx Error ERR_TCP_CONNECT_ERROR
  • xx:xx:xx SSL: Unable to setup connection (err=-5914)
The error displayed user side was simply "Citrix Sign on Failed"

Turns out this is because of a change to the way XenDesktop handles connections, you have to specifically point the Xenith units to the "legacy" URL.

Previously my Xen.ini file looked like this, and this worked fine in XenDesktop 5.6:
pnliteserver=MYDDC.domain  
However, in XenDesktop 7 it needs to be this:
pnliteserver=http://MYDDC.domain/Citrix/Store/PNAgent/config.xml
This URL is defined in the Citrix StoreFront under StoreFront > Stores > Configure Legacy Support. There's a checkbox (enable legacy support) there as well that you'll want to make sure is checked.

After I made that change to the Xen.ini file I was able to connect to the Desktop.

XenDesktop 7 - No Desktops Available

Working on building a XenDesktop 7 deployment to replace our current XenDesktop 5.6 instance. The Controller, XMLBroker,WebStore, and pretty much every component is installed on the same (albeit beefy) server - This deployment isn't big enough to warrant separate servers for everything, just a bunch of Wyse Xenith2 thin clients.

Anyway, I got to configuring the storefront which thankfully seems a lot more straight forward than the web interface in 5.6, except one problem - whenever I log in no I get a message saying "no applications or desktops are currently available to you". I can see in Studio that there should be desktops available, but I don't get them as an option anywhere I log in. 

A few hours of googling around and going through event viewer leads me to the conclusion that there's a problem with the XML Broker Service. I have the following errors in Event Viewer:

  • Warning:Citrix Broker Service: EventID:2010: General "The Citrix Broker Service encountered a problem while an XML service attempted to listen for http(s) requests. The Windows HTTP configuration might be incomplete or incorrect. ": Details Access is Denied System.Net.HttpListenerException
  • Error:Citrix Store Service:EventID:4003: "All the Citrix XML Services configured for the farm Controller failed to respond to this XML Service transaction"
  • Error:Citrix Store Service:EventID:0 : "An error occurred while attempting to connect to the server <this.stupid.server> on port <xxxx>. Verify that the Citrix XML Service is running and is using the correct port. If the XML Service is configured to share ports with Microsoft Internet Information Services (IIS), verify that IIS is running. This message was reported from the XML Service at address . The specified Citrix XML Service could not be contacted and has been temporarily removed from the list of active services."
The long and short of these is : "The XML service didn't start correctly and so the Store Front is failing to connect to it so storefront can't determine what desktops are available". The Details of the first error are useful, because - my knowledge of port binding is limited, but generally sufficient - it suggested that whatever port the XML service is trying to bind to is already in use.

This information leads me to this post on the Citrix forums: 


Which suggests changing the http port for the Broker Service. This is done via the command:

This is in the citrix install directory, typically c:\program files\citrix
..\citrix\broker\service\brokerservice.exe -wiport xxxx
I did this, but unfortunately the errors continued. Then I ran the following command and it showed a number of other ports that the XML service is using:

..\service\brokerservice.exe /show
SDK Port: 80
VDA Port: 80
WI Port: 8888
WI SSL Port: 443
Changing all of these ports got the broker service up and running.

The Broker Service automatically restarts itself when you run these commands
 ..\brokerservice.exe -wisslport xxxa
..\brokerservice.exe -sdkport xxxb
..\brokerservice.exe -vdaport xxxc 
At first I changed all four of these, and that caused the desktops to start showing up (After I changed the port of the Delivery controller in StoreFront (StoreFront>Stores>Manage Delivery Controllers).

Unfortunately it also caused all the desktops to unregister from the controller and Studio to break. This is because the vdaport appears to control what port the desktops need to register with and the sdkport controls port the Studio needs to connect on (as well as probably any other management software). Changing those two things back to port 80 things started working more the way I'd expected.

I have yet to actually get a thin to connect -- getting "SSL: unable to setup connection, (err=-5914)" but more on that once I figure it out.