Recently I was giving a presentation with some AppSense pre-sales guys regarding desktop challenges and AppSense DesktopNow. Probably the most rewarding part about using AppSense software is overcoming the challenges that you see in particular enterprises by leveraging it. What makes the DesktopNow suite so good at this, and this was something I mentioned in my presentation, is the native integration with VBScript and PowerShell that allows you to extend the possibilities of what you can do with it. So when I came across another interesting problem this week, I thought I would do a quick blog post on it to show how you can use DesktopNow to overcome these challenges.
The issue I was confronted with in this case was a client with a single-image desktop who wanted to deploy three distinct departmental desktops from the same image. All of the applications would be installed into the base image or packaged through App-V, and then made available to the user based around their Active Directory security group membership. For instance, call centre users would receive a locked-down desktop with access provided to their required applications and nothing else, but the same desktop image would also provide back-office users with a completely different set of applications and a much more relaxed set of restrictions. Obviously this was a job for Environment Manager and Application Manager combined - Environment Manager to provide access to the required applications and lock down parts of the user interface through Group Policy, and Application Manager to secure the other applications should the users be able to break through the sandbox.
The particular challenge, though, centred around the fact that access to the specific desktops was provided by AD security group. Personally, I'd have preferred this to be done by OU membership, as a user can only be a member of one OU at a time, and therefore couldn't inadvertently be in two of the OUs and have two sets of desktop settings pushed down to them. However, because the AD OU structure was undergoing a refresh, this wasn't what the client wanted to do. Also, there is the consideration that an OU lookup requires communication with a domain controller - whereas AD security group membership can be done "offline" using the local security token, a feature which is essential to AppSense EM working quickly.
A User Group Condition showing the "LSA Supported" suffix, indicating that offline checking is available |
Conversely, the User OU Condition has no offline checking |
So we were left with the situation that we wanted to make sure a user, at logon time, was not a member of more than one of the "desktop groups" set up in AD. If they were a member of multiple groups, two sets of policy and configuration settings would be effectively merged into each other, resulting in at best, a messy-looking desktop, and at worst, allowing users access to applications and files that they shouldn't be allowed to.
What we decided to do was implement a check at logon for the group memberships, and if a user was a member of more than one of the groups, to pop up a message advising them to contact technical support, and then log the user out.
Checking for multiple group memberships
This sounds like it should be easy enough using the User Group Condition, yes? Fortunately it is...you just need to do a bit of nesting to ensure that the user matches several Conditions rather than just one.
First of all it would make sense to check if the user is a member of the target group, so that you won't be doing any unnecessary Condition checking
Then, if the check passes for Application_Group_1, we need to nest some more Conditions inside this one, but this time checking if the user isn't a member of the other groups
Just so you're clear on what I'm getting at, these Conditions should be nested like this so that all of them need to be satisfied
Once we've established that the user is a member of the first group and not a member of the second and third ones, we then need to set some sort of flag to mark the user as such. I'm going to use a Registry value for this - whatever flag you choose is up to you. Nest the Action for the flag under the last Condition so that it is only set when all of the nested Conditions match
Now for the fiddly bit - recreating the above for the other two groups. A bit of cut and paste might help you out, along with a bit of quick editing :-) The finished section should look like this
The only thing you will have to remember to add is a Logoff Action to remove the Registry flag (if it's a Registry flag you're using). You don't have to worry about this for Session Disconnects because a user won't update their security groups if they disconnect and reconnect their session, it is only at logon that the security groups could change, so if the flag is there, it only needs to be removed at logoff.
Popping up a warning message
I'd love it if Environment Manager had some sort of Message Box functionality - but at the moment it doesn't (feature request!). So we're going to use a scripted Action. Now, normally I prefer to use PowerShell over VBScript wherever possible, but after a bit of digging, it seemed that the msgbox function in VB was vastly more straightforward than anything available in PS. However, as I am determined to better myself, PowerShell-wise, I doggedly stuck with it and eventually came up with something that worked.
At logon, we will use a Registry Condition to check if the flag exists
and if it doesn't, which would indicate that a user is a member of more than one of the groups (or none of the groups - which would again be a cause for concern and remediation), then we need to call a Custom Action to pop up a message logging them out.
The PowerShell I found that worked for me was this
$a=new-object -comobject wscript.shell
$b=$a.popup(“Your user account appears to be a member of multiple desktop groups. This will result in the provision of incorrect settings and unreliable application availability. Please contact Technical Support on x0000 to rectify this problem and quote the error 'MULTIPLE DESKTOP GROUPS'. This session will now be logged out.”,0,”Duplicate AD group memberships detected!”,0)
This isn't the native way to do it, though. Thanks to Michael B Smith (@essentialexch) for the education below
[Reflection.Assembly]::LoadWithPartialName( 'Microsoft.VisualBasic' ) | Out-Null
function InputBox( [string]$prompt, [string]$title, [string]$default )
{
( [string] ( [Microsoft.VisualBasic.Interaction]::InputBox( $prompt, $title, $default ) ) ).Trim()
}
function MsgBox( [string]$prompt, [string]$title, [int]$buttons )
{
[int]([Microsoft.VisualBasic.Interaction]::MsgBox( $prompt, $buttons, $title ) )
}
$vbOK = 1
$vbCancel = 2
$vbAbort = 3
$vbRetry = 4
$vbIgnore = 5
$vbYes = 6
$vbNo = 7
$vbOKOnly = 0
$vbOKCancel = 1
$vbAbortRetryIgnore = 2
$vbYesNoCancel = 3
$vbYesNo = 4
$vbRetryCancel = 5
$vbCritical = 16
$vbQuestion = 32
$vbExclamation = 48
$vbInformation = 64
$vbError = ( $vbOKOnly + $vbCritical ) ## this is mine and mine alone (not a standard value)
$vbDefaultButton1 = 0
$vbDefaultButton2 = 256
$vbDefaultButton3 = 512
$vbApplicationModal = 0
$vbSystemModal = 4096
$vbMsgBoxSetForeground = 65536
$vbMsgBoxRight = 524288
$vbMsgBoxRtlReading = 1048576
So, with that learning curve out of the way, we should now have a Custom Action that presents the user with a message to respond 'OK' to.
Logging the user out
I was going to call this from PowerShell too, but then realized I was falling into one of the traps I spend a lot of time railing against - overcomplication! Why call a logoff routine from PowerShell when I can do it natively from Environment Manager?
Indeed, the simplest thing to do is simply use the logoff.exe command, handily able to be called directly from Environment Manager
So now the set of Actions that check the user's group memberships and respond (if necessary) should look like this (notice I've used a Reusable Node, but unless you need to call this in multiple locations a standard node should do)
Testing!
All that's left to do now is check that this behaves as expected. First I log a user in that is a member of one desktop group, and everything works normally. Next I add the user to a secondary desktop group, and this time when I log in I see this
As soon as I click 'OK', a logoff initiates. I'm a bit narked that the desktop (extremely briefly) shows before the logoff kicks in, but this is something I can live with - there is no way the user can interrupt the logoff process, so that's a result all round.
Summary
The point of this post is not to provide a solution to a common problem. It's to demonstrate that AppSense DesktopNow can easily come up with a solution to whatever problems you may encounter in your particular environment.
Especially, the key part here is the integration between native and custom (scripted) EM Actions. Before EM supported PowerShell, I frequently found myself calling out to external files that then had to be maintained and updated, giving myself a solution that didn't feel self-contained. Now that the console supports PS directly, you can easily customize solutions to specific problems that the native Actions can't fully achieve themselves.
Anyway, I hope this little walkthrough is useful to some of you out there!