VMware

Custom Use of Snapshot files | Main | Notes on Running Internet Explorer through a ThinApp Virtual Bubble

January 27, 2009

Adding Non-Active Directory Validation Logic to a ThinApp Package

These are instructions on how to script in validation logic to your ThinApp package using VBS scripts - since virtually, whatever you can script, you can ThinApp.

Background Information

ThinApp allows administrators to assign Active Directory groups to a ThinApp package to provide some level of validation. This is great if the package is going to be deployed to the local or wide are network (LAN or WAN) and admins don't want their ThinApp packages to find their way onto any of their user's home computers.

What about adding other types of validation such as only allowing the application to run from a certain IP range or location on the network, a specific drive letter, a drive with a specific serial number, only once on a system at any given point in time, or even a system with a specific screen resolution? For this, ThinApp supports Visual Basic Scripting and with a VBS script, any type validation one can think of can potentially be used.

Requirements

The following items and knowledge are required for use of this procedure:

NOTES:

Make sure you read through this entire document!

Script Examples

Getting into Good Practice First

In this section I'm going to define some good practices to get into as this will help explain the example validation scripts later on.


Declaring Variables:

Declaring all of the variables within your script is always a good thing to do as it assigns a spot in memory and only releases it once the script shuts down or when you manually clear the variable somewhere in the script.

You may also notice that I specify a value for a variable called "strComputer". I do this here as I need the variable defined prior to setting global variables.

NOTE: The below text may be wrapped – the DIM line is all one line.

' DECLARE VARIABLES
Dim
WSHNetwork, WSHShell, objFSO, arraySearch, strSplit, objDrive, objWMIService, objProcess, colProcess, strComputer, strProcessKill, ExeName, ParentProcID, EPProcID, ParentProcIDTwo, EPProcIDTwo
strComputer = "."


Setting Global Use Variables:

Setting Global Use Variables is a good idea as you will likely utilize one of these calls at some point in your script.

' SET GLOBAL VARIABLES
Set WSHNetwork = CreateObject("WScript.Network")
Set WSHShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("Shell.Application")
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objRegistry = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")


Defining Global Script Environment Variables:

For script-wide variables which you will utilize time and again in your script, it is wise to set them once at the beginning of your script so that you may reuse them over and over without recalling the data to them (a longer process than just calling the value from memory).

' DEFINE SCRIPT ENVIRONMENT VARIABLES
Origin = GetEnvironmentVariable("TS_ORIGIN")
LastSlash = InStrRev(Origin, "\")
SourcePath = Left(Origin, LastSlash)
ExeName = Mid(Origin, LastSlash + 1, Len(Origin))
SandboxParent = GetBuildOption("SandboxPath")
SandboxName = GetBuildOption("SandboxName")
If SandboxParent = "." Then
    SandboxPath = SourcePath & SandboxName
Else
    SandboxPath = SandboxParent & Chr(92) & SandboxName
End If


Scripted Validation Examples

In this section I've coded some examples of different types of script validations that can be done. This is, by no means, all that you can do within a script!


Determine if Running from a UNC Path:

This code is useful in case you wish to ensure the application is only run from a drive letter and not a UNC path.

Origin = GetEnvironmentVariable("TS_ORIGIN")

Function OnFirstSandboxOwner
    
' -----------------------------------------
    
' Determine if running from a UNC path
    
' -----------------------------------------
    IsUNC =
InStr(Origin, "\\")
    
If IsUNC = 0 Then
        
' Find the drive letter which the ThinApp is running from
        arraySearch =
Split(Origin, "\", -1, 1)
        strSplit = (arraySearch(0))
        
Set objDrive = objFSO.GetDrive(strSplit)
    
Else
        
MsgBox "Application must be run from a valid drive"
        ExitProcess 0
    
End If
End Function

Note the use of the "Origin" ThinApp API call in the above code. This defines the path of where the ThinApp executable is actually running from.

The above code can also be expanded to determine the drive letter or path the ThinApp package is running from.


Determine Free Drive Space:

It may be that your application (packaged or otherwise) requires a certain amount of free disc space available to properly run. This code will check the free drive space by utilizing the File System Scripting Object.

Function OnFirstSandboxOwner
    
' -----------------------------------------
    
'Check Drive Free Space
    
' -----------------------------------------
    
Set objDrive = objFSO.GetDrive(strSplit)
    
If objDrive.FreeSpace > "1012903936" Then
        
MsgBox "FreeSpace " & objDrive.FreeSpace
    
Else
        
MsgBox "There is not enough free space, please contact Administrator"
        ExitProcess 0
    
End If
End Function

It should be noted that the "Set objDrive = objFSO.GetDrive(strSplit)" line could actually exist in the Global Variable section of the script. Additionally, it is likely only needed once per script – so if the "UNC Path" code previously discussed is also in the script, then the "Set objDrive = objFSO.GetDrive(strSplit)" line is only needed once in the script.


Determine Drive (or Volume) Name:

The following code will check for the "<Valid Company C Drive>" name (or whatever you specify as a valid name) and run the ThinApp if it is correct.

Function OnFirstSandboxOwner
    
' -----------------------------------------
    
'Check Drive Name
    
' -----------------------------------------
    
If objDrive.VolumeName = "<Valid Company C Drive>" Then
        
MsgBox "Volume Name is Correct" & objDrive.VolumeName
    
Else    
        
MsgBox "This system drive name is incorrect, please contact Administrator"
        ExitProcess 0
    
End If
End Function

Obviously you'll want to ensure that each system which your ThinApp package runs on has the same volume name. This is probably a little more impractical as someone could easily circumvent this by setting their home computer to the same volume name – but this is just to provide some examples.


Ask for a Validation Code:

This code will check ask the user for a validation code and check it against the "valid code". This is another script that, in its current form, would be somewhat restrictive; but it is a good starting point and example of what validation options can be arranged within a script.

Function OnFirstSandboxOwner
    
' -----------------------------------------
    
'Ask the user for a Validation Code
    
' -----------------------------------------
    ValidationCode =
InputBox("Enter your code: ")
    
'Verify the Validation Code.
    
If Not ValidationCode = "1111" Then 'If correct, notify and run the ThinApp.
        
MsgBox "Invalid Validation Code: " & ValidationCode
        ExitProcess 0
    
End If
End Function


Only Allow One Instance of a ThinApp Application to Run at a Time ONLY DURING VALIDATION:

WARNING! - This code is a bit more involved and requires additional modifications to the ThinApp package as well.

NOTE: This code utilizes the "Determine if Running from a UNC Path" code.

This piece of scripting will only allow one instance of a ThinApp packaged application to be executed at time during the validation phase. Once validation is successful, any number of instances of the ThinApp application can be launched. You may have just realized that using this code in conjunction with other validation logic is a must as this will prevent the circumvention of the OnFirstSandboxOwner validation logic code.

Explanation: When you utilize a single bit of validation code in the OnFirstSandboxOwner function of a ThinApp script, at the point of a prompt, the ThinApp executable can be launched a second time and will immediately bypass the validation stored in OnFirstSandboxOwner. This, actually, is by design because of the fact the four callback functions are timing points within ThinApp and not specifically for use with security functions and validation logic. Simply put, launching the entry point (any entry point into the same package) a second time while the first entry point is running will no longer execute the OnFirstSandboxOwner. Any validation logic in the OnFirstSandboxOwner callback function will not be executed for the second application (even if it's the same entry point).

To properly accommodate for this, we use the below script code and package modifications to prevent the launching of a second entry point (or relaunching of the same entry point) during the validation phase of the VB script. You'll also notice that similar code exists in both the OnFirstSandboxOwner and in the OnFirstParentStart ThinApp callback functions. This is because we're ensuring that similar processes occur for both the first launch of the application and subsequent and simultaneous launches of the application.


NOTE: The below script code assumes you have properly set and declared script variables prior to execution of this code. You may also wish to replace the "
& SandboxName &" code with something such as a company name.

Function OnFirstSandboxOwner
    
' -------------------------------------------------------------------
    
' Search for HKCU registry keys to record process information and create it if not found in VOS
    
' ------------------------------------------------------------------------------------
    objRegistry.GetStringValue &H80000001,
"SOFTWARE\" & SandboxName,"ParentProcID",dwValue
    
If IsNull(dwValue) Then
        objRegistry.CreateKey &H80000001,
"SOFTWARE\" & SandboxName
        WSHShell.RegWrite
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\EPProcID", EPProcID, "REG_SZ"
        WSHShell.RegWrite
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\ParentProcID", ParentProcID, "REG_SZ"
    
End If
    
    
' -------------------------------------------------------------------
    
' Search for process already running in background. If not found, write process id and parent process id to virtual registry
    
' -------------------------------------------------------------------
    ParentProcID = WSHShell.RegRead(
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\ParentProcID")
    EPProcID = WSHShell.RegRead(
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\EPProcID")
    
    
' Fix up Numeric Values
    
If IsNumeric(ParentProcID) Then
        ParentProcID =
Abs(Fix(ParentProcID))
    
End If
    
If IsNumeric(ParentProcID) Then
        EPProcID =
Abs(Fix(EPProcID))
    
End If
    
    
Set colProcess = objWMIService.ExecQuery ("Select * from Win32_Process Where Name = " & "'" & ExeName & "'")
    
If ParentProcID = "" And EPProcID = "" Then
        
For Each objProcess In colProcess
            ParentProcID =
Abs(Fix(objProcess.ParentProcessId))
            EPProcID =
Abs(Fix(objProcess.ProcessId))
            WSHShell.RegWrite
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\EPProcID", EPProcID, "REG_SZ"
            WSHShell.RegWrite
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\ParentProcID", ParentProcID, "REG_SZ"
        
Next
    
Else
        
For Each objProcess In colProcess
            
If ParentProcID <> Abs(Fix(objProcess.ParentProcessId)) Or EPProcID <> Abs(Fix(objProcess.ProcessId)) Then
                
MsgBox "This application '" & ExeName & "' is already running and cannot be ran more than once at a time during validation.",, ExeName & " is already running!"
                ExitProcess 0
            
End If
        
Next
    
End If
    
' -------------------------------------------------------------------
    
    
' -----------------------------------------
    
' Determine if running from a UNC path
    
' -----------------------------------------
    IsUNC =
InStr(Origin, "\\")
    
If IsUNC = 0 Then
        
' Find the drive letter which the ThinApp is running from
        arraySearch =
Split(Origin, "\", -1, 1)
        strSplit = (arraySearch(0))
        
Set objDrive = objFSO.GetDrive(strSplit)
    
Else
        
MsgBox "Application must be run from a valid drive"
        ExitProcess 0
    
End If
End Function

Function OnFirstParentStart
    
' -------------------------------------------------------------------
    
' Search for process already running in background. If not found, write process id and parent process id to virtual registry
    
' -------------------------------------------------------------------
    ParentProcID = WSHShell.RegRead(
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\ParentProcID")
    EPProcID = WSHShell.RegRead(
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\EPProcID")
    
    
' Fix up Numeric Values
    
If IsNumeric(ParentProcID) Then
        ParentProcID =
Abs(Fix(ParentProcID))
    
End If
    
If IsNumeric(ParentProcID) Then
        EPProcID =
Abs(Fix(EPProcID))
    
End If
    
    
Set colProcess = objWMIService.ExecQuery ("Select * from Win32_Process Where Name = " & "'" & ExeName & "'")
    
If ParentProcID = "" And EPProcID = "" Then
        
For Each objProcess In colProcess
            ParentProcID =
Abs(Fix(objProcess.ParentProcessId))
            EPProcID =
Abs(Fix(objProcess.ProcessId))
            WSHShell.RegWrite
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\EPProcID", EPProcID, "REG_SZ"
            WSHShell.RegWrite
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\ParentProcID", ParentProcID, "REG_SZ"
        
Next
    
Else
        
For Each objProcess In colProcess
            
If ParentProcID <> Abs(Fix(objProcess.ParentProcessId)) Or EPProcID <> Abs(Fix(objProcess.ProcessId)) Then
                
MsgBox "This application '" & ExeName & "' is already running and cannot be ran more than once at a time during validation.",, ExeName & " is already running!"
                ExitProcess 0
            
End If
        
Next
    
End If
    
' -------------------------------------------------------------------
    
    
' -----------------------------------------
    
' Determine if running from a UNC path
    
' -----------------------------------------
    IsUNC =
InStr(Origin, "\\")
    
If IsUNC = 0 Then
        
' Find the drive letter which the ThinApp is running from
        arraySearch =
Split(Origin, "\", -1, 1)
        strSplit = (arraySearch(0))
        
Set objDrive = objFSO.GetDrive(strSplit)
    
Else
        MsgBox "Application must be run from a valid drive"
        ExitProcess 0
    
End If
End Function

Function OnLastProcessExit
    
' -------------------------------------------------------------------
    
' Clean up after duplicate process searching if RemoveSandboxOnExit=1 not set in PACKAGE.INI
    
' -------------------------------------------------------------------
    ParentProcID =
""
    EPProcID =
""
    WSHShell.RegWrite
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\EPProcID", EPProcID, "REG_SZ"
    WSHShell.RegWrite
"HKEY_CURRENT_USER\SOFTWARE\" & SandboxName & "\ParentProcID", ParentProcID, "REG_SZ"
    
' -------------------------------------------------------------------
End Function


ATTENTION! – The above script code also requires modification of the package's HKEY_CURRENT_USER.TXT file and creation of the below lines. Also, replace "<SandboxName>" with a valid Sandbox Name.

isolation_full HKEY_CURRENT_USER\SOFTWARE\<SandboxName>
Value=EPProcID
REG_SZ=#00
Value=ParentProcID
REG_SZ=#00


WARNING! – Ensure when modifying any ThinApp package registry TXT file that you only leave one blank line between entries.

Example:


Example VBS Script with above examples and suggestions:

Download ThinApp Validation Script Examples

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d8341c328153ef010536f3f4a0970b

Listed below are links to weblogs that reference Adding Non-Active Directory Validation Logic to a ThinApp Package:

Comments

Post a comment

If you have a TypeKey or TypePad account, please Sign In.

About this Blog

VMware ThinApp lets you deliver and deploy applications more efficiently, more securely, and more cost-effectively with agentless application virtualization.

Subscribe via RSS  

Or submit your email for updates:

End-User Computing Blog


Read additional blog posts for VMware ThinApp on the VMware End-User Computing Blog.

Visit Now

Search ThinApp Blog

Community


Discussions and resources for VMware ThinApp

Visit now

Twitter


Facebook

YouTube


    VMware Blogs