Thursday, October 14, 2021

Retrieve Local Administrators from Multiple Computers

 A forum user asked for assistance with a PowerShell script that would read a list of servers from a text file and then either show the list of users in the local administrator groups on each server.

The script below, Get-LocalMembers, takes things a bit further. While it will default to the local administrators group, you can supply any number of groups to the script. It even supports wildcards! By default, the results are displayed on the console, but can also export the results as a .csv file.

The script takes 2 parameters (both optional):

Computers

A list of computers to query. The list may be provided as a parameter to the script, or read from a text file. Default: localhost

Groups

A list of local groups to query on each of the computers. Wildcards are support (see examples below). Default: Administrators

Examples

Get-LocalMembers

    Retrieves the members of the default group (Administrators) on the default computer(localhost).

Get-LocalMembers -Computers (Get-Content -Path "c:\temp\computers.txt")

    Will retrieve the members of the Administrators group on all the computers in the file computers.txt.

Get-LocalMembers -groups 'Remote*','Admin*'

    Will retrieve the members of the Administrators, Remote Desktop Users and Remote Management Users groups on localhost.

Get-LocalMembers | Export-Csv -Path "c:\reports\GroupMembers.csv" -NoTypeInformation

    Retrieves the members of the default group (Administrators) on the default computer(localhost) and exports them to the specified .csv file.

Function Get-LocalMembers {
<#
.SYNOPSIS
    Gets the members of one or more local groups of the specified computer(s) 
    and optionally outputs the results to a CSV file.

.PARAMETER Computers
    Specifies the computers to query.
    Can be a string or a list retrieved from a file via Get-Content (see examples).
    Default: $env:computername (localhost)

.PARAMETER Groups
    Specifies the groups to query. Supports wildcards. 
    Can be a string or a list retrieved from a file via Get-Content (see examples).
    (e.g. Remote* will enumerate both Remote Desktop Users and Remote Management Users)
    Default: Administrators

.EXAMPLE
    Get-LocalMembers
    Retrieves the members of the default group (Administrators) on the default computer(localhost)

.EXAMPLE
    Get-LocalMembers -Computers (Get-Content -Path "c:\temp\computers.txt")
    Will retrieve the members of the Administrators group on all the computers in the file computers.text

.EXAMPLE
    Get-LocalMembers -groups 'Remote*'
    Will retrieve the members of the Remote Desktop Users and Remote Management Users groups on localhost

.EXAMPLE
    Get-LocalMembers | Export-Csv -Path "c:\reports\GroupMembers.csv" -NoTypeInformation

.LINK
    Heavily modified from script: https://gallery.technet.microsoft.com/223cd1cd-2804-408b-9677-5d62c2964883
#>

    Param(
        [string[]]$Computers,
        [string[]]$Groups
    )

    # defaults
    if ($Computers -eq $null) {
        $Computers = $env:COMPUTERNAME
    }
    if ($Groups -eq $null) {
        $groups = 'Administrators'
    }

    # testing the connection to each computer via ping before executing the script
    foreach ($computer in $Computers) {
        if (Test-Connection -ComputerName $computer -Quiet -count 1) {
            $livePCs += $computer
        } else {
            Write-Host ('Computer {0} is unreachable.' -f $computer) -ForegroundColor DarkRed -BackgroundColor White
        }
    }

    $list = new-object -TypeName System.Collections.ArrayList

    # cycle through each computer in the list
    foreach ($computer in $livePCs) {

        # cycle through each group in the list
        foreach($groupToTest in $groups) {
            $err = @()
            $admins = @(Get-WmiObject -Class win32_groupuser -ComputerName $computer -EA SilentlyContinue -EV err | 
                Where-Object {$_.groupcomponent -like "*`"$($groupToTest)`""})

            if ($err.Count -gt 0) {
                $errMsg =  $err[0].Exception.Message
                Write-Host ('Error accessing WMI on {0} ... {1}' -f $computer, $err[0].Exception.Message) `
                            -ForegroundColor DarkRed -BackgroundColor White
            } else {
               if ($admins.Count -gt 0) {
                    # get the group name
                    $null =  $admins[0].Groupcomponent -match '.+Domain\=(.+)\,Name\=(.+)$'
                    $group = $matches[2].trim('"')

                    # get the members of the group
                    $aAdmins = @() 
                    foreach ($admin in $admins) {
                        $null = $admin.partcomponent -match '.+Domain\=(.+)\,Name\=(.+)$' 
                        $null = $matches[1].trim('"') + '\' + $matches[2].trim('"') + "`n"
                        $aAdmins += $matches[1].trim('"') + '\' + $matches[2].trim('"')
                    }
                    $obj = New-Object -TypeName PSObject -Property @{
                        Computer = $computer
                        Group    = $group
                        Members  = ($aAdmins -join ',')
                    }
                    $null = $list.add($obj)
                }
            }
        }
    }
    $list | select computer, group, members
}

Sam Jacobs is the Director of Technology at Newtek Technology Systems (formerly IPM), the longest standing Citrix Platinum Partner on the East Coast. With more than 30 years of IT consulting, Sam is a NetScaler and StoreFront customizations and integrations industry expert. He holds Microsoft and Citrix certifications, and is the editor of TechDevCorner.com, a technical resource blog for IT professionals. 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: sjacobs@newtekone.com or on Twitter at: @WIGuru.


Sunday, September 12, 2021

Log Off Idle Citrix Sessions

The simple PowerShell snippet below will log off any session that has been idle for more than the specified number of hours.


# sessions that have been idle for longer than 
# the below number of hours will be logged off
$maxIdleHours = 24

# load the Citrix snapin
Add-PSSnapin Citrix*

# function to calculate the number of hours
# that a session has been idle
Function Get-IdleHours {
    param ([TimeSpan] $IdleTime)
    ($IdleTime.Days * 24) + $IdleTime.Hours
}

# get sessions that are idle
$sessions = @(Get-Brokersession | ? IdleDuration -ne $null)

# cycle through the list, and log off sessions that
# have been idle for > the specified number of hours
foreach ($sess in $sessions) {
    if ((Get-IdleHours($sess.IdleDuration)) -gt $maxIdleHours) {
        Stop-BrokerSession $sess
    }
}


Sam Jacobs is the Director of Technology at Newtek Technology Systems (formerly IPM), the longest standing Citrix Platinum Partner on the East Coast. With more than 30 years of IT consulting, Sam is a NetScaler and StoreFront customizations and integrations industry expert. He holds Microsoft and Citrix certifications, and is the editor of TechDevCorner.com, a technical resource blog for IT professionals. 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: sjacobs@newtekone.com or on Twitter at: @WIGuru.

Monday, October 26, 2020

Quickly Disconnect All ICA Sessions

A client recently asked for a way to quickly and easily disconnect all ICA sessions. This seemed like an easy task, which could be accomplished by enabling the Disconnect button within StoreFront. The problem was that the client wanted the ability for users to disconnect their sessions without logging in! Since we don't know who the user is until after login, how would we know which session(s) to disconnect?

I then found out that the Citrix Receiver Self-Service Plug-in had a parameter that will allow you to disconnect all of your applications by simply running the following:

SelfService.exe -disconnectapps

Then it became a matter of creating a new URL Protocol to invoke the above when browsing to the specified protocol. With the assistance of my colleague Jacques Bensimon, we created the attached .REG file. An explanation of the keys in the .REG file follows.

[HKEY_CLASSES_ROOT\xica] defines a new URL protocol called xica.

[HKEY_CLASSES_ROOT\xica\shell\open\command] specifies the registered handler to execute when the URL protocol is invoked.

The final REG key:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ProtocolExecute\xica]

eliminates the IE prompt asking permission to run the registered handler. (Note: Other browsers may or may not prompt, and may have their own way of eliminating prompts, including possibly giving the user the option to no longer be prompted for these protocols. Those settings may not be in the Registry at all, but rather in some config files in the user profile.)

To invoke the new protocol, you simply needed to browse to it. This could be accomplished in many ways. For example, you could create a shortcut on the desktop with the URL xica://DisconnectApps. You could also invoke the protocol via a hyperlink or a button on a web page.


Sam Jacobs is the Director of Technology Development at IPM, the longest standing Citrix Platinum Partner on the East Coast. With more than 30 years of IT consulting, Sam is a NetScaler and StoreFront customizations and integrations industry expert. He holds Microsoft MCSD, Citrix and CCP-N certifications, and is the editor of TechDevCorner.com, a technical resource blog for IT professionals. 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: sam.jacobs@ipm.com or on Twitter at: @WIGuru.

Tuesday, September 10, 2019

Have PowerShell Keep Your Confidential Information … Confidential!


As an IT professional, you have no doubt needed to run processes with elevated privileges. PowerShell makes it quite easy with the Get-Credential cmdlet:
$creds = Get-Credential
This pops up a window for you to securely enter your credentials:


You can then use the credentials in cmdlets that support the -Credential parameter. So, if I wanted to connect to a DDC to get a list of all Citrix sessions, I might do something similar to the following:
$sessions = Invoke-Command -ComputerName CitrixDDC01 -Credential $creds -ScriptBlock {
       Add-PSSnapin Citrix*
       @(Get-BrokerSession)
}

What if I wanted to create an automated script to retrieve sessions multiple times during the day (and maybe night)? I may not want to remain up until 3 AM to run the above script. PowerShell’s got you covered there, as well, with a way to securely save your credentials.
# Securely store user credentials
$creds = Get-Credential
$pwLocation = "C:\PowerShell\Credentials\securePW.txt"
$creds.Password | ConvertFrom-SecureString | Set-Content $pwLocation

The above snippet will securely encrypt your password and store it in the specified location. This only needs to be done once, and then the above credentials can be used in any number of scripts by simply adding the following:

$userName = "username specified above"
$pwLocation = "C:\PowerShell\Credentials\securePW.txt"
$securePW = Get-Content $pwLocation | ConvertTo-SecureString
$creds        = New-object System.Management.Automation.PSCredential($userName,$securePW)

Now, if you’re a Network Security admin, you may be wondering “How secure is that? What happens if someone gets hold of the file with the encrypted password? They now have the keys to all your scripts!” Not to worry. The file is encrypted using your security context. This simply means that only you can decrypt the secure file. If someone else tries to copy and use the file, it would be totally useless.

It’s not just for passwords anymore!

I am constantly giving demos of PowerShell scripts, and some of them, in addition to passwords, may contain other confidential information. For example, database connection strings, or even the names of servers, such as the DDC in the example above. Get-Credential can be used for these as well.

# Securely store DDC name
$SecureDDC = Get-Credential
$ddcLocation = "C:\PowerShell\Credentials\secureDDC.txt"
$SecureDDC.Password | ConvertFrom-SecureString | Set-Content $ddcLocation



Again, the above need only be done once. I can then securely retrieve the name of my DDC without showing it in scripts with the following:

$DDCName = "SecureDDC"
$ddcLocation = "C:\PowerShell\Credentials\secureDDC.txt"
$encryptedDDC = Get-Content $ddcLocation | ConvertTo-SecureString
$secureDDC  = New-object System.Management.Automation.PSCredential($DDCName,$encryptedDDC)
$DDC  = $secureDDC.GetNetworkCredential().Password

$sessions = Invoke-Command -ComputerName $DDC -Credential $creds …

If you plan to use Task Scheduler to run your script, make sure that you run the task under the same context used to create the encrypted string. Otherwise, the secured string returned will be blank!

Monday, March 4, 2019

Adding Text, Links and Other Elements to the NetScaler Logon Page - Part 2


As we discussed in Part 1 of this post, there are three categories of NetScaler customizations:
1) Customizations that do not require any rewrite policies/actions (“policies”) or source code modifications (“modifications”),
2) Customizations that can be accomplished using either policies or modification, and
3) Customizations that will most probably need modification of the source code.
In Part 1, we focused on the DefaultGreen Bubble, and X1 (the "original") themes. In part 2, we will discuss the newest theme - Receiver for Web UI (RfWebUI), which uses a completely new mechanism.
While the logon page looks like the X1 theme:
... if you will be using the RfWebUI theme, you can forget pretty much everything you've learned about customizing the NetScaler logon page.  
Let's begin with the location of the logon page. When using the original themes, the logon page (index.html) was served from the  /netscaler/ns_gui/vpn/ directory. With the RfWebUI theme, the file is now served from /var/netscaler/logon/LogonPoint/. The good news is that since the page is now in the /var partition, any modifications to the page (or copies of the logon page) are automatically persisted across a reboot. No longer do you need to add lines to rc.netscaler to copy modified files into the flash partition.
The next major change is how you modify text. The portal wizard allows you to easily make changes to commonly updated text. Let's say you wanted to change the labels on the logon screen. After clicking OK at the bottom of the wizard, you will then be prompted for the language you wish to use:
After clicking OK, you will see the pages you can modify on the right-hand side of the page.   

Click Login Page. You are presented with the default labels for the page:
Let's modify them as follows:
Click Ok.
Finally, click Done. Now, let's refresh the page (you may need to clear your cache).

If you've had experience customizing the original NetScaler themes, at this point you are probably thinking "Tell me something that I don't already know ... this is no different than modifying any of the other themes"! Not quite ... The portal wizard functions differently depending on which theme has been chosen. For the original themes, the portal wizard would modify the values in the appropriate XML file in the resources directory (e.g. /var/netscaler/logon/themes/<theme>/resources/en.xml). The keys affected are located under the Partition ID of Logon. Now, what if you wished to modify the text of the logon button above, which you can't do from the portal wizard? No problem. In the same file, as few lines down, we find:
<Property id="Log_On" property="value">Log On</Property>
Simply change it to:
<Property id="Log_On" property="value">Click to log on</Property>
... and then save the file.
Try that with a theme based on RfWebUI and you will find that it doesn't work. In fact, if you look at the en.xml file in the resources directory of a theme based on RfWebUI, you will notice that the portal wizard did *not* modify ANY of the keys in that file. What gives??
For RfWebUI-based themes, those text changes are written to /var/netscaler/logon/themes/<theme>/strings.<language code>.json:
The portal wizard writes all the values on a single line. I would suggest placing each override on a separate line for readability and maintainability. Also note that this "key":"value" format differs from the XML format of the other themes. 
In order to change other text elements on the page, you will need to get the key to be placed in the override file. The keys may be found in the file /var/netscaler/logon/LogonPoint/receiver/js/localization/<language code>/ctxs.strings.js. The key for the logon button is nsg_LogOnbutton. Let's add an override for it in the above file:
Then save the file, and refresh the page. In addition to clearing the cache on your PC, it may take 2-3 minutes for the cache to be cleared on the NetScaler.
Now, let's try to add our own custom text fields as we did with the X1 theme in part 1.
Here we come to another major difference. In the original themes, we would:
- Add a <div> with a unique id (either via a rewrite action/policy or a modified gateway_login_form_view.js file),
- Add a string with the <div>'s id to the XML file in the resources directory, and finally 
- Add a CSS selector with the <div>'s id to the custom.css file in the selected theme.
Note that everything is keyed off the id of the <div>.
With RfWebUI-based themes, text is keyed off of class names, and the class name must begin with _ctxstxt_. So, to add the "authorized users only" warning (see Part 1), we make a copy of the index.html file (let's call it custom.html), and add our custom <div>:
We then add an entry with the text into strings.en.json:

We also need to add style information, but instead of adding it to custom.css, for RfWebUI-based themes, it must go into theme.css. Here you can either use the <div>'s id (if specified), or the class name, which is required (include the _ctxstxt_ prefix).
We can test by browsing to our custom.html file.
Let's not forget our footer ... add another custom <div>:
Then add the text:
... and then the CSS:
Browsing to our custom page:

Our final step is to create a responder policy and bind it to our AG vServer. This will automatically invoke our custom page when we browse to the AG vServer FQDN:
> add responder action "Logon Page Redirect Action" redirect "\"custom.html\"" -responseStatusCode 302
> add responder policy "Logon Page Redirect Policy" "HTTP.REQ.URL.PATH_AND_QUERY.CONTAINS(\"LogonPoint/index.html\")" "Logon Page Redirect Action"
> bind vpn vserver "AG vServer" -policy "Logon Page Redirect Policy" -priority 100 -gotoPriorityExpression END -type REQUEST
> save config
To remove the customizations, simply unbind the responder policy.
Here’s a handy cheat-sheet summarizing all of the above:

Original Themes
(Default, Green Bubble, X1)
Receiver for Web UI
(RfWebUI) Theme
Logon page directory
/netscaler/ns_gui/vpn/
/var/netscaler/logon/LogonPoint/
Updates to text strings
/var/netscaler/logon/themes/<theme>/
      resources/<language code>.xml
/var/netscaler/logon/themes/
      <theme>/strings/<language code>.json
String format
<String id=”key”>Value</String>    OR
<Property id="key"
      property="property">Value</Property>

“key” : “value”
Custom text based on
<div> ID
class name (existing keys are in /var/netscaler/
   logon/LogonPoint/receiver/js/localization/
   <language code>/ctxs.strings.js
CSS file
custom.css
theme.css


Thanks to the NetScaler development team for their help, and especially Bidyut H.
Sam Jacobs is the Director of Technology Development at IPM, the longest standing Citrix Platinum Partner on the East Coast. With more than 25 years of IT consulting, Sam is a NetScaler customizations and integrations industry expert. He holds Microsoft MCSD, Citrix CCP-M and CCP-N certifications, and is the editor of TechDevCorner.com, a technical resource blog for IT professionals. 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. Sam can be reached at: sam.jacobs@ipm.com or on Twitter at: @WIGuru.


Friday, March 1, 2019

Adding Text, Links and Other Elements to the NetScaler Logon Page - Part 1



There have been a number of posts, discussions, and KB articles on adding text and links to the NetScaler logon page, such as:

 In this 2-part post, I will divide such customizations of the login page into three categories:
1) Customizations that do not require any rewrite policies/actions (which we’ll call “policies” for brevity) or source code modifications (“modifications”),
2) Customizations that can be accomplished using either policies or modification, and
3) Customizations that will most probably need modification of the source code (usually gateway_login_view.js and/or gateway_login_form_view.js).
In part 1, we will focus on the Default, Green Bubble, and X1 NetScaler 11 themes. In part 2, we will discuss the newest Receiver for Web UI (RfWebUI) theme, which uses a completely new mechanism, which is more similar to modifications made for StoreFront.
First off, regardless of whether modifications are made via policies or modifications, the policies or modifications should be minimized to whatever extent possible. There should never be style information or text strings in the policy or modification. Style information should be confined to the custom.css file, and strings should be placed into the appropriate XML file(s) in the resources directory of the theme, especially if you need localization (multi-language support).
So, for example, instead of:
<div style=’font-family: arial,helvetica,sans-serif;color:white;font-weight:bold;’>WARNING: Use of this system is limited to authorized users. Activities on this system are monitored, and subject to audit.</div>
 ... the policy or modification itself should only contain:
<div id=’unauthorizedUse’ />
Then, add the following to custom.css:
#unauthorizedUse {
      font-family: arial,helvetica,sans-serif;
      color:white;
      font-weight:bold;
}
... and the following to en.xml (with appropriate entries in other language files):
<String id="unauthorizedUse"> WARNING: Use of this system is limited to authorized users. Activities on this system are monitored, and subject to audit.</String>
Let's take it a step further. As mentioned above, the first category of customizations do not require any policies or modifications at all. Included in this category would be the addition of a few lines of footer text (with or without links), such as the customization above. For example, I can create the following:


 ... by adding the following to the bottom of custom.css:
#logonbelt-bottomshadow,
#logonbelt-bottomshadow a {
   text-align: center;
   color: #FFFFFF;
   font-size:12pt;
}   
#logonbelt-bottomshadow a {
   font-weight: bold;
   text-decoration: underline;
} 
... and adding the following text to en.xml (all on one line):
<String id="logonbelt-bottomshadow">WARNING: Use of this system is limited to authorized users. This system contains confidential and proprietary information. Any unauthorized trespass into or use of this system is prohibited. Any such unauthorized trespass or use may be referred to law enforcement agencies for criminal prosecution and may subject you to civil penalties. Activities on this system are monitored and recorded, and subject to audit.&lt;br&gt;Please refer to the firm's &lt;a href='#'&gt;Acceptable Use Policy&lt;/a&gt; for additional details.</String>
The only item you need to be aware of, is that all HTML codes must be converted to their HTML-encoded equivalents. For example:
<a>     
&lt;a&gt;
</a>
&lt;/a&gt; 
<b>
&lt;b&gt;
<br>
&lt;br&gt;

Note that I am not using any policies or modifications for the above. I was able to do this by leveraging the built-in <div> called logonbelt-bottomshadow. There is also a <div> called logonbelt-topshadow that one can use to add text and links above the logon box.
So, when would a policy or modification be called for? When you need to add extra elements to the page. If, for instance, I wanted to add a footer to the previous example:


... I could inject a <div> called footer (following our "Keep It Small" rule, the added code would simply be <div id='footer' />), and then add <String id="footer">myCUGC.org - All Rights Reserved.</String> to en.xml, and the following to custom.css:
#footer {
   position: absolute;
   bottom: 5px;
   height: 30px;
   font-size: 12px;
   color: white;
   font-weight: bold;
   text-align: center;
   width: 100%;
   background-color: black;
   padding-top: 5px;
}
Finally, there will be times where the number of modifications, or their complexity make using policies impractical. In those cases, it makes more sense to use modifications. Consider the following example:

First, there are all the added elements (color bars and the extra text on the bottom of the screen). Then there are the additional buttons which will need to be backed by JavaScript calls. While it is certainly possible to use policies for all the elements, it would be much simpler to use modifications in a case like this.
When you use modifications, do not modify the original .js file. Instead, make a copy of the original, and make your modifications to the copy. You can then use a rewrite action and policy to swap the modified file for the original.  For example:
add rewrite action act_login_form_replace replace_all "HTTP.RES.BODY(120000)" q{"custom_login_form_view.js"} -search q{text("gateway_login_form_view.js")}

add rewrite policy pol_login_form_replace "HTTP.REQ.URL.EQ(\"/vpn/index.html\")" act_login_form_replace

bind vpn vserver "AG vServer" -policy pol_login_form_replace -priority 200 -gotoPriorityExpression NEXT -type RESPONSE 
You also need to make sure your modified file survives a reboot, so you need to also copy your file into /var/vpn/vpn/js.

Sam Jacobs is the Director of Technology Development at IPM, the longest standing Citrix Platinum Partner on the East Coast. With more than 25 years of IT consulting, Sam is a NetScaler customizations and integrations industry expert. He holds Microsoft MCSD, Citrix CCP-M and CCP-N certifications, and is the editor of TechDevCorner.com, a technical resource blog for IT professionals. 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. Sam can be reached at: sam.jacobs@ipm.com or on Twitter at: @WIGuru.


Sunday, March 19, 2017

Passing Parameters to XenDesktop by Rewriting the StoreFront ClientName


A recent client had the following business requirements:

1) To logon, enumerate and launch a XenDesktop from within their corporate intranet, and

2) To pass department/project information to the desktop. This was necessary so that the correct network drives were mapped for the session.

The first requirement was easily met by using the StoreFront Web API to embed StoreFront functionality into their intranet. The second requirement, however, was a bit more involved, as the same user could possibly be working on multiple projects simultaneously, and would therefore require different drive mappings for each.

Enter the StoreFront Store Customization SDK. The Store Customization SDK has predefined "customization points" which allow you step in and apply custom logic to modify enumerated resources, change launch parameters, and to modify device information. 

You can download the latest version of the Store Customization SDK here.

For an introduction to the SDK, see Citrix Principal Architect Simon Frost's blog post: Introducing the StoreFront Store Customization SDK. You can also check out his Synergy Developer Exchange Series video StoreFront Store Customization SDK.
One such field that can be modified via the Store Customization SDK is the session Clientname, which is easily accessed from within the XenDesktop session. Simon made modification of the Clientname quite easy with the release of his blog post and accompanying DLL Rewriting the Session ClientName from StoreFront. Alas, none of the many tokens defined in the DLL would support passing a dynamic parameter such as department or project information. However, since Simon was kind enough to also supply the source for his DLL, I was able to satisfy that business requirement by extending his DLL to incorporate HTTP headers into the ClientNameRewriteRule.


Simply use the token $H’header name’ (single quotes) within the ClientNameRewriteRule where you would like the value of the specified header placed (please refer to his blog post for a detailed explanation of the ClientNameRewriteRule).

For example, if I wanted the ClientName to contain the user’s roaming status (“I” for internal, and “E” for external), and the value of the Department header, the rule might look something like:

<appSettings>

    <add key=”clientNameRewriteRule”  value=”$R-$H’Department’ “ />

</appSettings>



If the value if the Department header was Dept007, then the ClientName would look like:

 
You must keep in mind the ClientName restrictions - the total length of the result must be 20 characters or less – anything longer will be truncated, and may not contain any of the following characters: “/ []:;|=\,+*?<>.
You must also set the value of overrideIcaClientName to “On”. For newer versions of StoreFront, you can find the setting in the GUI under Configure Store Settings | Advanced Settings. For older versions of StoreFront, see Simon’s blog post for manually modifying the configuration file (always make sure that the GUI console is not open when manually modifying any of the configuration files).
There is one final (but essential) requirement. For security reasons, StoreFront will not forward any unknown headers, so you must add your new header to the StoreFront whitelist:
  • Backup web.config in your <Store>Web directory.
  • Find the <communication> section (under <webReceiver> | <serverSettings>).
  • Add the highlighted lines:

  • Save the file ... an IISRESET is not required.