Sunday, April 14, 2024

Get a List of User Logons

A frequent request of Citrix administrators is the activity in the environment. In this post, we will show you how to create a report of user logons within the past x days. 
The script will accept a parameter specifying the number of days (i.e. List user logons for the past X days). In addition, you will also to modify the variables holding the name or IP address of the SQL Server hosting the monitoring database, as well as the database name (and you need permissions to read the database, of course).

param ([string]$daysCovered)

$SQLServer = "SQL Server"  
$SQLDBName = "CitrixMonitorDB" 

There are also some optional variables to change, such as the location to save the report, the file name, and the title of the report.

$reportLocation = ".\" 
$reportFileName = "UserLogons"
$title = "User Logon Report"


We begin by defaulting to a span of a week if the number of days was not specified. Then we calculate the beginning and ending dates and create a date filter for our SQL query.

if ($daysCovered -eq '') {
# default to a week - back 6 days
$daysCovered = 6
}

# set the starting and ending dates
$eDate = [datetime]::now 
$sDate = $eDate.AddDays(-$daysCovered)

# create the date filter
$filter = "and monitordata.session.StartDate > convert(datetime,'"+(get-date ($sDate).ToUniversalTime() -Format "MM/dd/yyyy HH:mm:ss")+"') "


We create a SQL query to retrieve desktop sessions.

$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True; MultipleActiveResultSets = True"
[System.Collections.ArrayList]$sessions = @()
[System.Collections.ArrayList]$appsessions = @()
[System.Collections.ArrayList]$sessions = sqlquery -q `
"select
monitordata.session.SessionKey
,monitordata.connection.establishmentDate
,monitordata.session.StartDate
,logonduration
,enddate
,connectionstate
,username
,fullname
,monitordata.machine.HostedMachineName
,monitordata.desktopgroup.Name as appDeskName
,IsRemotePC
,DesktopKind
,SessionSupport
,SessionType
,DeliveryType
,ClientName
,ClientAddress
,ClientVersion
,ConnectedViaHostName
,ConnectedViaIPAddress
,LaunchedViaHostName
,LaunchedViaIPAddress
,IsReconnect
,Protocol
,LogOnStartDate
,LogOnEndDate
,BrokeringDuration
,BrokeringDate
,DisconnectCode
,DisconnectDate
,VMStartStartDate
,VMStartEndDate
,ClientSessionValidateDate
,ServerSessionValidateDate
,EstablishmentDate
,HdxStartDate
,HdxEndDate
,AuthenticationDuration
,GpoStartDate
,GpoEndDate
,LogOnScriptsStartDate
,LogOnScriptsEndDate
,ProfileLoadStartDate
,ProfileLoadEndDate
,InteractiveStartDate
,InteractiveEndDate
,Datediff(minute,logonenddate,DisconnectDate) as 'SessionLength'
from monitordata.session
join monitordata.[user] on monitordata.session.UserId = monitordata.[user].Id
join monitordata.Machine on monitordata.session.MachineId = monitordata.machine.Id
join monitordata.DesktopGroup on monitordata.machine.DesktopGroupId = monitordata.desktopgroup.Id
join monitordata.connection on monitordata.session.SessionKey = monitordata.connection.SessionKey
where UserName <> '' and SessionType = '0'
$filter
order by logonenddate,SessionKey" | ?{$_ -notlike "*[0-9]*"}

We then create a query to retrieve XenApp sessions.

[System.Collections.ArrayList]$appsessions = sqlquery -q `
"select monitordata.session.SessionKey
,monitordata.connection.establishmentDate
,monitordata.session.StartDate
,LogOnDuration
,monitordata.session.EndDate
,ConnectionState
,UserName
,FullName
,monitordata.application.Name as appDeskName
,PublishedName
,monitordata.machine.HostedMachineName
,IsRemotePC
,DesktopKind
,SessionSupport
,DeliveryType
,ClientName
,ClientAddress
,ClientVersion
,ConnectedViaHostName
,ConnectedViaIPAddress
,LaunchedViaHostName
,LaunchedViaIPAddress
,IsReconnect
,Protocol
,LogOnStartDate
,LogOnEndDate
,BrokeringDuration
,BrokeringDate
,DisconnectCode
,DisconnectDate
,VMStartStartDate
,VMStartEndDate
,ClientSessionValidateDate
,ServerSessionValidateDate
,EstablishmentDate
,HdxStartDate
,AuthenticationDuration
,GpoStartDate
,GpoEndDate
,LogOnScriptsStartDate
,LogOnScriptsEndDate
,ProfileLoadStartDate
,ProfileLoadEndDate
,InteractiveStartDate
,InteractiveEndDate
,Datediff(minute,logonenddate,DisconnectDate) as 'SessionLength'
from monitordata.Session
join monitordata.[user] on monitordata.session.UserId = monitordata.[user].Id
join monitordata.Machine on monitordata.session.MachineId = monitordata.machine.Id
join monitordata.DesktopGroup on monitordata.machine.DesktopGroupId = monitordata.desktopgroup.Id
join monitordata.connection on monitordata.session.SessionKey = monitordata.connection.SessionKey
join monitordata.applicationinstance on monitordata.ApplicationInstance.SessionKey = monitordata.session.SessionKey
join monitordata.application on monitordata.application.id = monitordata.ApplicationInstance.ApplicationId
where UserName <> '' and sessiontype = '1' 
$filter
order by logonenddate,SessionKey" | ?{$_ -notlike "*[0-9]*"}

We create an array to contain both XD and XA sessions, filtering by our date criteria above, and sorting by the user's name

$allsessions = $sessions | 
Select-Object @{n='startdate';e={'{0:MM/dd/yy hh:mm tt}' -f $_.startdate.toLocalTime()}},
username, fullname,
@{n='enddate';e={'{0:MM/dd/yy hh:mm tt}' -f $_.enddate.toLocalTime()}}, 
sessionLength, appDeskName

$allsessions += $appsessions | 
Select-Object @{n='startdate';e={'{0:MM/dd/yy hh:mm tt}' -f $_.startdate.toLocalTime()}},
username, fullname,
@{n='enddate';e={'{0:MM/dd/yy hh:mm tt}' -f $_.enddate.toLocalTime()}}, 
sessionLength, appDeskName  

$sortedSessions = $allsessions | sort fullname


We calculate the session duration (in minutes).

$sortedSessions | %{
if ($_.enddate -eq $Null) {
$_.sessionlength = [math]::Round(((Get-Date) - (get-date $_.startDate)).totalminutes,0)
} else {
$_.sessionlength = [math]::Round(((Get-Date $_.enddate) - (Get-Date $_.startDate)).totalminutes,0)
}
}


Finally, we create an HTML report of the sessions, as well as a .CSV file that you can slice and dice to your specifications.

$Header = @" 
<style>
body, TH, TD { font-family: Segoe UI, tahoma, Arial, sans-serif ; font-size:14px; }
h2 { font-family: tahoma; font-size:20px; }

TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;width: 95%} 
TH {border-width: 1px;padding: 3px;border-style: solid;border-color: black;color:white; background-color: #6495ED;} 
TD {border-width: 1px;padding: 3px;border-style: solid;border-color: black;} 
.odd { color:black; background-color:#ffffff; } 
.even { color:black; background-color:#dddddd; } 
</style>
"@
$e = '{0:MM/dd/yy hh:mm tt}' -f $eDate
$s = '{0:MM/dd/yy hh:mm tt}' -f $sDate
$message = $null
$formattedsessions = $sortedSessions | 
Select-Object -unique @{n='Start Date/Time';e={'{0:MM/dd/yy hh:mm tt}' -f $_.startdate}},
@{n='User Name';e={$_.userName}}, @{n='Full Name';e={$_.fullName}}, 
@{n='End Date/Time';e={'{0:MM/dd/yy hh:mm tt}' -f $_.enddate}}, 
@{n='Duration';e={duration($_.sessionLength)}},
@{n='Application/Desktop Group';e={$_.appDeskName}}

if ($formattedsessions.Count -gt 0) {
$sessionsHTML = $formattedsessions | ConvertTo-Html -head $header -Title $title -PreContent "<h2>$($title): &nbsp; $s - $e</h2> $($formattedSessions.Count.ToString('N0')) Sessions" | Set-AlternatingRows -CSSEvenClass even -CSSOddClass odd

if ($sessionsHTML -ne $null) {
$timeStamp = (Get-Date -Format u).Replace(":",".").Replace("Z","").Replace(" ","_")
$filePathName = "$($reportLocation)$($reportFileName)_$($timeStamp).html"
$sessionsHTML | Out-File $filePathName

$filePathName = "$($reportLocation)$($reportFileName)_$($timeStamp).csv"
$formattedsessions | ConvertTo-Csv  -NoTypeInformation | Out-File $filePathName

}

We also make use of 4 functions:
Set-AlternatingRows - to color code the HTML report, making it easier to read
Convert-UTCtoLocal  - to convert start/end times (stored in UTC) to local time
duration - if the session duration is longer than a day, will display > x days instead of hours
sqlquery - the function that executes the SQL query and returns the results

Function Set-AlternatingRows {
[CmdletBinding()]
Param(
[Parameter(Mandatory,ValueFromPipeline)]
[string]$Line,
   
[Parameter(Mandatory)]
[string]$CSSEvenClass,
   
[Parameter(Mandatory)]
[string]$CSSOddClass
)
Begin {
$ClassName = $CSSEvenClass
}
Process {
If ($Line.Contains("<tr><td>"))
{ $Line = $Line.Replace("<tr>","<tr class=""$ClassName"">")
If ($ClassName -eq $CSSEvenClass)
{ $ClassName = $CSSOddClass
}
Else
{ $ClassName = $CSSEvenClass
}
}
Return $Line
}
}

function sqlquery ($q) {
$SqlQuery = $q
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
return $DataSet.tables[0]
}

function Convert-UTCtoLocal
{
  param(
[parameter(Mandatory=$true)]
[String] $UTCTime
  )
$strCurrentTimeZone = (Get-WmiObject win32_timezone).StandardName
$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)
$LocalTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)
}

Function duration {
[CmdletBinding()]
Param(
[Parameter(Mandatory)]
[int]$mins
)
[string] $strDuration = ""

if ($mins -gt 2880) {
$strDuration = "> $([math]::Floor($mins/1400)) days"
} elseif ($mins -gt 1440) {
$strDuration = "> 1 day"
} else {
$hh = ([math]::Floor($mins/60)).ToString("00")
$mm = ($mins % 60).ToString("00")
$strDuration = "$($hh):$($mm)"
}

return $strDuration
}

You can download the complete script here:  Get-UserLogons.ps1. Save the file on any machine with access to the monitoring database. Open a PowerShell command prompt or the PowerShell ISE, and execute:

<path to script>\Get-UserLogons.ps1  nn

where nn is the number of days to report on. If you omit nn, the script defaults to 7 days.

Happy scripting!

Sam Jacobs is the Director of Technology at Newtek Technology Solutions (formerly IPM, the longest standing Citrix Platinum Partner on the East Coast). With more than 40 years of IT consulting, Sam is a Citrix NetScaler, StoreFront, and Web Interface customization and integration expert. He holds Microsoft Azure Developer and Citrix CCP-N certifications, and was a frequent contributor to the CUGC CTP blog. He has presented advanced breakout sessions at Citrix Synergy for 6 years on ADC (NetScaler) and StoreFront customizations and integration. He is one of the top Citrix Support Forum contributors, and has earned industry praise for the tools he has developed to make NetScaler, StoreFront, and Web Interface easier to manage for administrators and more intuitive for end users. Sam became a Citrix Technology Professional (CTP) in 2015, and can be reached at sjacobsCTP@gmail.com.

Sunday, March 17, 2024

PowerShell Script to Get Citrix VM details

Quite a number of clients are running a virtual Citrix environment, so here is a script to get a list of basic details on each VM such as name, state, IP address, VM host, and memory. You will need to modify the value of the $VIserver variable.

# load the PowerCLI cmdlets
Import-Module VMware.PowerCLI

# name or IP of the vCenter server
$VIserver   = 'vcenter.domain.com'

# where to store the output
$outputFile = 'c:\temp\VMlist.csv'

# retrieve the vCenter creds
$creds      = Get-Credential

# connect to vCenter
Connect-VIServer $VIserver -Credential $creds

# retrieve and format the information from vCenter
Get-VM | Sort-Object PowerState, Name |

   Select-Object -Property `

   @{n='IP Address'; e={$_.guest.IPAddress[0]}},

   @{n='VM Host'; e={$_.VMHost}},

   @{n='Memory'; e={"$([math]::Round($_.MemoryGB))GB"}},

   @{n='State'; e={$_.PowerState.toString().Substring(7)}} | 

   Export-Csv -Path $outputFile -NoTypeInformation

# disconnect from vCenter - no need to confirm
Disconnect-VIServer -Confirm:$false


Sam Jacobs is the Director of Technology at Newtek Technology Solutions (formerly IPM, the longest standing Citrix Platinum Partner on the East Coast). With more than 40 years of IT consulting, Sam is a Citrix NetScaler, StoreFront, and Web Interface customization and integration expert. He holds Microsoft Azure Developer and Citrix CCP-N certifications, and was a frequent contributor to the CUGC CTP blog. He has presented advanced breakout sessions at Citrix Synergy for 6 years on ADC (NetScaler) and StoreFront customizations and integration. He is one of the top Citrix Support Forum contributors, and has earned industry praise for the tools he has developed to make NetScaler, StoreFront, and Web Interface easier to manage for administrators and more intuitive for end users. Sam became a Citrix Technology Professional (CTP) in 2015, and can be reached at sjacobsCTP@gmail.com.

Sunday, February 18, 2024

Get A List of Unused Citrix Applications

Citrix Director gives administrators the capability to create their own custom reports. However, that feature is only available with a Platinum license. But don't lose hope - you can easily create your own custom reports by querying the Citrix Monitoring database. 
Some of our clients have in excess of 100 published applications. It's no wonder, then, that they may wish to remove unused applications. So, let's use a PowerShell script to create a report of unused applications.
The script will accept a parameter specifying the number of days (i.e. List applications that haven't been used in X days). We will also need the name or IP address of the SQL Server hosting the monitoring database, as well as the database name.

    param ([int] $daysCovered = 30) $SQLServer = "<SQL Server with Citrix Monitor DB>"       $SQLDBName = "CitrixMonitoring"

We then create a SQL query to retrieve the name and last used date of all applications in the monitoring database. If an application has never been used (its LastUsed date is null), we set the date to 1/1/1900).

    # retrieve the data     $SqlConnection = New-Object System.Data.SqlClient.SqlConnection     $SqlConnection.ConnectionString = `
        "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True; `
        MultipleActiveResultSets = True"     [System.Collections.ArrayList]$sessions = @()     $strQuery = `     "SELECT Name AS AppName, LastUsed =        ISNULL((select Max(StartDate)        FROM monitordata.applicationinstance inst        JOIN monitordata.application app on app.id = inst.ApplicationId        where Name = application.Name), '01/01/1900')      FROM monitordata.application application"

We'll need a function to make the actual call to SQL and to fill a dataset with the results.

    Function sqlquery ($q) {         $SqlQuery = $q         $SqlCmd = New-Object System.Data.SqlClient.SqlCommand         $SqlCmd.CommandText = $SqlQuery         $SqlCmd.Connection = $SqlConnection         $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter         $SqlAdapter.SelectCommand = $SqlCmd         $DataSet = New-Object System.Data.DataSet         $SqlAdapter.Fill($DataSet)         return $DataSet.tables[0]     }

We'll call the function, passing the SQL query that we created above.

[System.Collections.ArrayList]$apps = sqlquery -q $strQuery | ?{$_ -notlike "*[0-9]*"}

Finally, we calculate the cutoff date, and list the applications not used since then.

    Write-Host "Applications not used in the past $($daysCovered) days:"     $cutoff = (Get-Date).AddDays(-$DaysCovered)     $apps | ? LastUsed -lt $cutoff |         Select AppName, @{Name="Last Used";Expression=`
            {if($_.LastUsed -eq [DateTime]'1/1/1900') {'... never used...'} `
            else {$_.LastUsed}} }

You can download the complete script here:  Get-StaleApplications.ps1. Save the file on a machine with access to the monitoring database. Open a PowerShell command prompt or the PowerShell ISE, and execute:

<path to script>\Get-StaleApplications.ps1  nn

where nn is the cutoff number of days to report on. If you omit nn, the script defaults to 30 days.

Happy scripting!

Sam Jacobs is the Director of Technology at Newtek Technology Solutions (formerly IPM, the longest standing Citrix Platinum Partner on the East Coast). With more than 40 years of IT consulting, Sam is a Citrix NetScaler, StoreFront, and Web Interface customization and integration expert. He holds Microsoft Azure Developer and Citrix CCP-N certifications, and was a frequent contributor to the CUGC CTP blog. He has presented advanced breakout sessions at Citrix Synergy for 6 years on ADC (NetScaler) and StoreFront customizations and integration. He is one of the top Citrix Support Forum contributors, and has earned industry praise for the tools he has developed to make NetScaler, StoreFront, and Web Interface easier to manage for administrators and more intuitive for end users. Sam became a Citrix Technology Professional (CTP) in 2015, and can be reached at sjacobsCTP@gmail.com.

Sunday, January 14, 2024

Custom Desktop Icons for StoreFront

 A forum user asked if it was possible to use their own custom icon for desktops in StoreFront. While the icons are displayed within StoreFront, the actual icon management is done on a Delivery Controller.

Open PowerShell on a DDC and issue the following commands (PowerShell cmdlets are case-insensitive).

# load the Citrix cmdlets
Add-PSSnapin Citrix*

Get-BrokerIcon | Select Uid | ft –auto


This will give you the ID of the last icon in use (#12 in the above) - make a note of it. 

Load the icon with the following command:

Get-CtxIcon -FileName c:\icons\custom.ico | New-BrokerIcon

If you re-issue the Get-BrokerIcon command above, you should see the new ID (#13).


We now need to assign the icon to one or more delivery groups. Let's see what icons are currently assigned to the delivery groups:

Get-BrokerDesktopGroup | Select name, IconUid


Unless you've already made changes, most delivery groups will probably be using icon #1. To change the icon for a specific delivery group, issue the following command:

Set-BrokerDesktopGroup -name “Remote PCs”   -IconUid 13 (the new icon added above)


You could replace the icon for any of the other delivery groups, or you could load and assign a separate icon for each of the delivery groups.

Back on the StoreFront server, you will need to issue the following commands (make sure that the StoreFront console is closed before issuing these commands):

$store = Get-STFStoreService -SiteId 1
Set-STFStoreService -StoreService $store -SubstituteDesktopImage $false -Confirm:$false

Don’t forget to propagate your StoreFront changes to the rest of the StoreFront servers in the group.

Sam Jacobs is the Director of Technology at Newtek Technology Solutions (formerly IPM, the longest standing Citrix Platinum Partner on the East Coast). With more than 40 years of IT consulting, Sam is a Citrix NetScaler, StoreFront, and Web Interface customization and integration expert. He holds Microsoft Azure Developer and Citrix CCP-N certifications, and was a frequent contributor to the CUGC CTP blog. He has presented advanced breakout sessions at Citrix Synergy for 6 years on ADC (NetScaler) and StoreFront customizations and integration. He is one of the top Citrix Support Forum contributors, and has earned industry praise for the tools he has developed to make NetScaler, StoreFront, and Web Interface easier to manage for administrators and more intuitive for end users. Sam became a Citrix Technology Professional (CTP) in 2015, and can be reached at sjacobsCTP@gmail.com.

Tuesday, October 10, 2023

Citrix Releases StoreFront 2308

On September 14, 2023, Citrix released StoreFront 2308. The following features were added to this version:

App Protection through a web browser

App Protection provides an additional level of security by blocking keyloggers and screen capture. Previously, this functionality was only available when accessing a store through Citrix Workspace apps for Windows, Mac and Linux. When viewing a store through a web browser, protected apps were not displayed. With this release it is now possible to configure a store website to display apps requiring App Protection when viewed through a browser, as long as StoreFront has detected that the user has a sufficiently new version of Citrix Workspace app for Windows, Mac or Linux installed that will be used to launch the app.


Advanced Health Check is now enabled by default

StoreFront runs periodic health checks on each Citrix Virtual Apps and Desktops server and Cloud Connector to reduce the impact of intermittent server availability. With Advanced heath check StoreFront performs a more in-depth check that is more likely to detect any issues.

From this release onward, the advance health check feature is enabled by default. Previously it had to be enabled manually.


The following StoreFront features have been deprecated in this release:

XenApp Services

From this release onward, support for XenApp Services (also known as PNAgent) is deprecated. It will be removed in a future release.

XenApp 6.5

It is no longer possible to add new XenApp 6.5 resource feeds using the StoreFront admin console. It is still possible to add them using PowerShell Add-STFStoreFarm specifying the FarmType as XenApp.

There were also a number of fixed issues in the release.

Full documentation on this release.

Sunday, September 10, 2023

Custom Timeouts for Citrix StoreFront - Revisited

In my last blog post I showed you how to create custom StoreFront timeouts based on a user's AD group membership. Once the custom timer expires, the user is logged out of StoreFront. Under certain circumstances this might cause unexpected behavior. 

For example, the default action when the user clicks the logoff button in StoreFront is to disconnect any Citrix sessions launched from that PC. This may be changed under Workspace Control:


You probably don't want your Citrix sessions to disconnect when StoreFront times out (what if you were in the middle of an important document in your Citrix session?). You would need to sign on to StoreFront again to continue working. It would be a lot worse if you had the logout action set to Terminate (you would lose all your work!).

To get around this "gotcha", we need to take advantage of a StoreFront "extension" that allows us to dynamically change the logout action on the fly. We define the new action at the top of the file:
var ICAaction    = "none";

"None" means to leave any running Citrix sessions alone - do not disconnect or terminate them. We then call the beforeWebLogoffIca StoreFront extension, and tell it to swap our new logout action for the default one:

CTXS.Extensions.beforeWebLogoffIca = function(defaultAction) {
log("About to log off ... default ICA action: " + defaultAction + " ... returning: " + ICAaction);
return ICAaction;
}; 

If you activate the console in the browser's Developer Tools, you should see something like:










You can download the updated script.js here.

Sunday, July 16, 2023

Custom Timeouts for Citrix StoreFront

One of the features that I have found missing in StoreFront is the ability to set different timeouts for different categories of users. For example, you may wish to have a shorter timeout for users in a sensitive department (e.g. Finance). If you feel the same way, read on ...

Let's assume that you would like the Finance department to have a shorter timeout period (e.g. 5 minutes) rather than the default value of 20 minutes. First, you would need a way to determine if the user logging on to StoreFront is in the Finance department. You would then need to set the appropriate timeout based on the user's membership.

The first requirement may be accomplished by adding the following .Net .aspx file (inGroup.aspx) to the custom directory. You pass it the user's ID and the department (OU) you wish to check for membership. and it will return true if the user is a member of that OU or false if the user is not. It is beyond the scope of this post to explain each of the routines in the file, but two points need to be mentioned. 

1) You must edit the file at line #11 to reflect the user root OU and your company's domain:

string rootOU = "OU=Accounts,DC=domain,DC=com";

2) You need to add an assembly to the file web.config in your store's web directory (e.g. /Citrix/StoreWeb). To do this:

- make a backup of the web.config file.

- open the file and search for <assemblies>

      <assemblies>
        <add assembly="System.Web.Mvc, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>

- insert the following line right before the closing </assemblies> tag

        <add assembly="System.DirectoryServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

- which should then look like

      <assemblies>
        <add assembly="System.Web.Mvc, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.DirectoryServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </assemblies>

- save the file

You also need to copy the contents of this script file (script.js) into the script file currently in the custom directory (after backing it up, of course). At the very top of the file you will see:

// group to get a special timeout
var specialGroup       = "Finance";
var specialTimeoutMins = 5;

You will need to modify the above for the AD group to check for and the special timeout (in minutes) for that group.

Note: You need to make sure that the timeout specified in your StoreFront configuration is greater than your special timeout, or StoreFront will log you out before you reach your custom timeout.

The JavaScript code sets a timer based on the timeout value specified and simulates a click on the logoff link when the timer expires.

function logout() {
log("Session timeout has expired ... logging out ... ");
$('#dropdownLogOffBtn').click();
}

Logging code has been added to the above which you can view by activating the console in your browser's Developer Tools. Here is a sample of what you would see if the user is in the special group:


Here is a sample of what you would see if the user is NOT in the special group: