Citrix Direct Workload Connection uses the new Network Location Service (better know as Hairpinning). The problem prior to this service, was that when I connected to Citrix Cloud from my local network in Brasil, it still connected through the Citrix Cloud Gateway in the US.
The configuration is rather simple as explain here, but I wanted a 100% automated solution. As a bonus I’ll will give you my Protect-Password function which you can use to encrypt all your passwords and later decrypt them in PowerShell.
Note: Change Line 2 to <#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
Function Protect-Password{ ## .SYNOPSIS Encrpts the User's Password with AES Encrption Method .DESCRIPTION This function generates and retuns AES Encrpted Secure Password File & Secure Key File.Username, Password, Output Parameters are Mandatory. .LINK Protect-Password .EXAMPLE Protect-Password -Username "TestUser" -Password "TestPassword" -Output "TestFiles" #> [CmdletBinding()] Param( [Parameter(Mandatory=$True,HelpMessage='Username')] [ValidateNotNullOrEmpty()] [string] $UserName , [Parameter(Mandatory=$True,HelpMessage='Password')] [ValidateNotNullOrEmpty()] [string] $Password , [Parameter(Mandatory=$True,HelpMessage='Output')] [ValidateNotNullOrEmpty()] [string] $Output ) Write-Verbose "Encrypting $Username's Password with AES Security Key" -Verbose $SecureStringPwd = ConvertTo-SecureString $Password -AsPlainText -Force $OutputFile = $Output + ".txt" $KeyFile = $Output + ".key" $Key = New-Object Byte[] 16 [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key) $Key | out-file $KeyFile $Encrypted = ConvertFrom-SecureString -SecureString $SecureStringPwd -Key $Key $Encrypted | Set-Content $OutputFile Write-Verbose "$Username's Password is Encrypted with AES Security Key in $OutputFile Files" -Verbose } |
Without the Network Location Service the User Experience is pretty bad, even though the Datacenter is sitting next to me!
The script will automatically download the required NLS PowerShell module, find your external IP address together with Longitude & Latitude required to configure the Network Location Site.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
Clear-Host CD $env:XA\Scripts Write-Verbose "Downloading PowerShell Module" -Verbose $ProgressPreference = 'SilentlyContinue' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri "https://raw.githubusercontent.com/citrix/sample-scripts/master/workspace/nls.psm1" -OutFile "$env:XA\Scripts\nls.psm1" Import-Module ".\nls.psm1" Write-Verbose "Getting Global Settings from XML" -Verbose $MyConfigFileloc = ("$env:Settings\Applications\Settings.xml") [xml]$MyConfigFile = (Get-Content $MyConfigFileLoc) $CCCustomer = $MyConfigFile.Settings.Citrix_Cloud.CustomerID $CCAPI = $MyConfigFile.Settings.Citrix_Cloud.API $CCPasswordFile = $MyConfigFile.Settings.Citrix_Cloud.PasswordFile $CCKeyFile = $MyConfigFile.Settings.Citrix_Cloud.KeyFile Write-Verbose "Getting Encrypted Password from KeyFile" -Verbose $CCSecret = ((Get-Content $CCPasswordFile) | ConvertTo-SecureString -Key (Get-Content $CCKeyFile)) $CCSecretInMemory = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($CCSecret) $PasswordAsString = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($CCSecretInMemory) [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($CCSecretInMemory) Write-Verbose "Importing Citrix Cloud Module" -Verbose Connect-NLS -clientId $CCAPI -clientSecret $PasswordAsString -customer $CCCustomer Write-Verbose "Getting External IP Information" -Verbose $ip = Invoke-RestMethod http://ipinfo.io/json $a = $ip.loc -split "," Write-Verbose "Creating Network Location Site" -Verbose New-NLSSite -name $ip.org -tags @("$($ip.city)") -ipv4Ranges @("$($ip.ip)/32") -longitude $a[1] -latitude $a[0] -ErrorAction SilentlyContinue #Get-NLSSite | Remove-NLSSite |
In the example above I’m using a single IP address with /32 instead of an IP address range. At my customers we simple import the configuration from a CSV file instead. Needless to say, the results are incredible via UDP.