Virtualization, technology, and random rantings with a focus on Citrix and VMware.

Category: XenApp Page 4 of 7

It Just Didn’t Register: Find Unregistered Machines

Just a quick little script you can add to your daily checks. This has been helpful for me to see if I have something that didn’t want to play nice BEFORE someone calls me and says it is broken. Good to have also if you have multiple hypervisor connections so you can see where at least it is running. Saves you looking around to figure out where it be.

# Get unregistered machine information

$adminAddress = "ddcaddress.fqdn:80"

$unregisteredMachines = get-brokermachine -AdminAddress $adminAddress -MaxRecordCount 25000| where registrationstate -eq "unregistered"
$report = @()
    foreach($unreg in $unregisteredMachines){

      $line = "" | select HostedMachineName, RegistrationState, AssociatedUserNames, DesktopGroupName, CatalogName, InMaintenanceMode, OSType, LastConnectionUser, LastConnectionTime, HypervisorConnectionName, SessionCount

      $line.HostedMachineName        = $unreg.HostedMachineName
      $line.RegistrationState        = $unreg.RegistrationState
      $line.AssociatedUserNames      = $unreg.AssociatedUserNames -join ','
      $line.DesktopGroupName         = $unreg.DesktopGroupName
      $line.CatalogName              = $unreg.CatalogName
      $line.InMaintenanceMode        = $unreg.InMaintenanceMode
      $line.OSType                   = $unreg.OSType
      $line.LastConnectionUser       = $unreg.LastConnectionUser
      $line.LastConnectionTime       = $unreg.LastConnectionTime
      $line.HypervisorConnectionName = $unreg.HypervisorConnectionName
      $line.SessionCount             = $unreg.SessionCount

      $report += $line

    }

    $report |format-table
    
    

VDA Upgrade… Oh Yeah!

So you want to upgrade some VDAs?! Yeah you do! I’ve done some edits on other scripts. I’m also working out for additional revisions to check for present sessions. This targets the Server VDA version. You can edit the name to VDAWorkstationSetup_1912.exe in the script and accompanying files to upgrade on VDI as well. The base for this is listed below in the script from ChayScripts. You can also change the install switches and copy that into the install.bat file if you need different options (https://www.citrix.com/blogs/2018/01/08/citrix-vda-commandline-helper-tool/)

For the contents of the ServerNameTextFile, you will need FQDN of the servers for the invoke commands. This splits the FQDN off for the powercli aspect to snapshot the server.

# Base VDA removal / reinstall script. This uses Powershell ISE on 5.1 with needing to be ran with account with rights in VMware and on the target server as well as the module for PowerCLI. 
# Modified from https://github.com/ChayScripts/Citrix-VDA-Upgrade-Scripts scripts. Added snapshot for VMware and a report of previous versions.

$vdalist = get-content "C:\pathtotextfilewithfqdnservernames.txt"
$source = "placewherefilesarestored\vdaupgrade"
$dest = "c$\software\vdaupgrade"
$date = Get-Date -Format MMddyyyy
$report = @()

  foreach ($vda in $vdalist) {
    $line = "" | Select Name, PreviousVersion, SnapShot
    $vda1 = ($vda.split('.')[0])
    $line.Name = "$vda"
    $line.PreviousVersion = (invoke-command -ComputerName $vda -ScriptBlock {Get-WmiObject -Class Win32_Product | where name -match "Citrix Virtual Desktop Agent - x64" | select Name,Version}).Version
    $snapshot = (get-vm $vda1  | new-snapshot -name $date-$vda1-preupgrade)
    $line.SnapShot = (get-vm $vda1 | get-snapshot).name
    Write-Host "Working on $vda"
    if (!(Test-Path -Path \\$vda\c$\software\vdaupgrade)) {
        New-Item -ItemType Directory -Path \\$vda\c$\software -Name vdaupgrade
        Copy-Item "\\$source\install.bat" -Destination \\$vda\$dest -Force
        Copy-Item "\\$source\remove.bat" -Destination \\$vda\$dest -Force
        Copy-Item "\\$source\VDAServerSetup_1912.exe" -Destination \\$vda\$dest -Force
    }
    else {
        Copy-Item "\\$source\install.bat" -Destination \\$vda\$dest -Force
        Copy-Item "\\$source\remove.bat" -Destination \\$vda\$dest -Force
        Copy-Item "\\$source\VDAServerSetup_1912.exe" -Destination \\$vda\$dest -Force

    }
    Invoke-Command -ComputerName $vda -Scriptblock {
        $time = (Get-Date).AddMinutes(3)
        $action = New-ScheduledTaskAction -Execute 'c:\software\vdaupgrade\remove.bat'
        $trigger = New-ScheduledTaskTrigger -Once -At $time
        $principal = New-ScheduledTaskPrincipal  -RunLevel Highest -UserID "NT AUTHORITY\SYSTEM" -LogonType S4U

        Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -TaskName "VDAUninstall" -Description "Citrix VDA Uninstall" 
    }

    Invoke-Command -ComputerName $vda -Scriptblock {
        $action = New-ScheduledTaskAction -Execute 'c:\software\vdaupgrade\install.bat'
        $trigger = New-ScheduledTaskTrigger -AtStartup 
        $principal = New-ScheduledTaskPrincipal  -RunLevel Highest -UserID "NT AUTHORITY\SYSTEM" -LogonType S4U

        Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -TaskName "VDAInstall" -Description "Citrix VDA Install" 

    } 

    $report += $line

  }

$report | export-csv c:\scripts\logs\$date-vda-upgrades.csv -Append -NoTypeInformation

You will need to create an install.bat and remove.bat file with the contents below.

Install.bat
REM change port number in below command.
REM Use citrix vda command line helper tool from citrix. https://support.citrix.com/article/CTX234824 if needed
REM Install new VDA agent, delete files and scheduled tasks. Finally reboot.

C:\software\vdaupgrade\VDAServerSetup_1912.exe /masterpvsimage /virtualmachine /components VDA /controllers "DDC1 DDC2 DDC3" /noreboot /quiet /disableexperiencemetrics /enable_hdx_ports /enable_hdx_udp_ports /enable_real_time_transport /enable_remote_assistance
C:\Windows\system32\schtasks.exe /delete /tn VDAInstall /f
C:\Windows\system32\schtasks.exe /delete /tn VDAUninstall /f
del c:\software\vdaupgrade\remove.bat /F
del c:\software\vdaupgrade\VDAServerSetup_1912.exe /F
C:\Windows\System32\timeout.exe /t 5
C:\Windows\System32\shutdown.exe /r /t 20 /f
del c:\software\vdaupgrade\install.bat /F

Remove.bat
"C:\Program Files\Citrix\XenDesktopVdaSetup\XenDesktopVdaSetup.exe" /REMOVEALL /QUIET /NOREBOOT
C:\Windows\System32\shutdown.exe /r /t 5 /f

User Count Breakdown By Delivery Group

This script allows you to get the list of Delivery Groups by “SessionSupport” type and reports back “MultiSession” as “CitrixApp” and SingleSession as “VDI.”

# Script to get MultiSession and SingleSession counts from Delivery Groups with a non-zero user count. This sorts by MultiSession, then SingleSession. This was ran on a machine with Citrix Studio SDK
# installed. This was tested with CVAD 1912 LTSR.
asnp Citrix*
$adminAddress = "deliverycontroller.fqdn"

$getDG = Get-BrokerDesktopGroup -AdminAddress $adminAddress -MaxRecordCount 100000 | Select-Object Name, SessionSupport | Get-Unique -AsString

$report = @()

foreach($dg in $getDG) {
  
  $line = "" | Select DeliveryGroupName, UserCount, SessionSupport
  $userCount = (Get-BrokerSession -AdminAddress $adminAddress -DesktopGroupName $dg.name -MaxRecordCount 100000 | Select-Object BrokeringUserName).count
  
  if ($userCount -ne '0' -and $userCount -ne $null){
    $line.DeliveryGroupName = $dg.name
    $line.UserCount         = $userCount
    
    if($dg.SessionSupport -eq "SingleSession") {
      $line.SessionSupport  = 'VDI'
    }
    else{
      $line.SessionSupport  = 'CitrixApp'
    }
    $report += $line
  }
  }
  
$citrixAppTotal = (($report | Where-Object SessionSupport -eq "CitrixApp"| Select-Object UserCount).UserCount| Measure-Object -Sum).Sum
$citrixVDITotal = (($report | Where-Object SessionSupport -eq "VDI"| Select-Object UserCount).UserCount| Measure-Object -Sum).Sum
$appTotal = write-output "`r`nTotal Citrix App users: $citrixAppTotal"
$vdiTotal = write-output "Total VDI Users: $citrixVDITotal"
  
$report += $apptotal
$report += $vdiTotal
  

$report | sort SessionSupport, @{Expression="UserCount";Descending=$true}|Format-Table




Windows Terminal On Citrix VDI Keyboard No Worky

So ran into this fun on Citrix VDI with Windows Terminal. You get it installed. You start it up. It’s all shiny. You press a button….. And…… NOTHING! So we saw this issue on Windows Terminal on Windows 10 20H2 running CVAD 1912 CU5 VDA. A little bit of searching and this article pointed to part of what was up. https://github.com/microsoft/terminal/issues/4448

The fix that had to be done to resolve it in our case was to set the “Touch Keyboard and Handwriting Panel Service” to “Manual” in Services. Then rebooting. After that, it fired right up and worked!

If You Could Get Those User Counts Today, That Would Be Great.

So you like your reports fresh off the press!? We do too! A quick little script to grab a daily report, running as a scheduled task, and send out some user information. Just in case someone likes to know how many people using the platform.

Gets you this nice little emailed report:

# Get Citrix Daily Users reporting. This requires Powershell, Studio SDK, access rights to the license server.
# This gets the unique users, current sessions, connected and disconnected VDI, and license counts.
# This was tested with 11.17.2.0 build 37000 License Server with 1 license file. Running this as a scheduled task you will need an AD account
# to run this under. A service account works well for this.

asnp Citrix*

$adminAddress = "deliverycontroller.fqdn:80"

$licenseServerAddress = "https://licenseserveraddress:8083"

$licenseServerName = "licenseserver.fqdn"

$cert = Get-LicCertificate -AdminAddress $licenseServerAddress

# This section was gotten from https://lalmohan.co.nz/2015/10/09/citrix-license-usage-monitoring-using-powershell/ and modified for my use.
$licenseInfo = Get-WmiObject -Namespace "ROOT\CitrixLicensing" Citrix_GT_License_Pool -ComputerName $licenseServerName
$licenseModel = ($LicenseInfo | Where-Object{($_.pld -like "XDT*") -or ($_.pld -like "MPS*")}|Select-Object pld -unique).pld
$totalLicenses = ($licenseInfo | Where-Object PLD -like "$licenseModel" | Select-Object count).count
# End section.

# This section was assisted from http://notesofascripter.com and https://www.linkedin.com/in/douglas-ruehrwein-56835869/
# This will run differently for Monday since you are getting data from the last 24 hours and weekends are usually lower use.
$Today = Get-Date
if(($Today.DayOfWeek) -eq 'Monday')
{$when = $Today.AddDays(-3)}
else{$when = $Today.AddDays(-1)}
# End section.

$connections = Get-BrokerConnectionLog -AdminAddress $adminAddress -Filter {BrokeringTime -gt $when} -MaxRecordCount 100000 | Select-Object BrokeringUserName

$licenseCount = (Get-LicUsageDetails -AdminAddress $licenseServerAddress -ProductEditionModel $licenseModel -CertHash $cert.CertHash).count


$ctxUsers = [PSCustomObject] @{

  UniqueCitrixUsers      = ($connections.BrokeringUserName | Select-Object -Unique).count
  CurrentSessions        = (Get-BrokerSession -AdminAddress $adminAddress -MaxRecordCount 100000 | Select-Object BrokeringUserName).count
  CitrixVDIConnected     = (Get-BrokerSession -AdminAddress $adminAddress -MaxRecordCount 100000 | Where-Object SessionSupport -eq "SingleSession" | Where-Object SessionState -eq "Active").count
  CitrixVDIDisconnected  = (Get-BrokerSession -AdminAddress $adminAddress -MaxRecordCount 100000 | Where-Object SessionSupport -eq "SingleSession" | Where-Object SessionState -eq "Disconnected").count
  CitrixLicensesUsed     = $licenseCount
  CitrixTotalLicenses    = $totalLicenses
  CtxLicenseFreePercent  = ((($totalLicenses - $licenseCount) / $totalLicenses ) * 100).ToString("#.##")

}

# HTML Formatting
$style = "<style>BODY{font-family: Arial; font-size: 10pt;}"
$style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}"
$style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }"
$style = $style + "TD{border: 1px solid black; padding: 5px; }"
$style = $style + "</style>"

# HTML Email Body
$body = $ctxUsers | ConvertTo-Html -Head $style
 

# Generates email with attachment
$date = Get-date -Format "MM-dd-yyyy"
$emailFrom = "someemail@place.com"
$emailto = "someemail@place.com"
#$emailtwo = "someemail@place.com"
#$emailCC = "someemail@place.com"
$subject="Daily Citrix User Report | $date" 
$email = New-object System.Net.Mail.MailMessage 
$email.to.Add($emailto)
#$email.to.Add($emailtwo)
#$email.CC.Add($emailCC)
$Email.From = New-Object system.net.Mail.MailAddress $emailFrom
$email.Subject = $subject
$email.IsBodyHtml = $true
#$attachment = $Reports[1]
#$email.Attachments.add($attachment)
$email.body = $body
 

$smtpserver="stmp.someplace.com" 
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($email)





That One Time, You Got SMAPP’d!

So you run SiteManager. And somebody done decided they want to make a new server that will host the security.dat file. And… You already did the work to create custom .ini file locations for the users. NOW you have to change all those smapp.ini files with the updated location of the security.dat file. How dare they?! Well. That could be some fun if you have a lot of users. Wait…. Powershell for the rescue! If you happen to use a profile server to host the user files, you can easily replace it with the new location of the security.dat file.

Update: Not sure what happened, but the code paste didn’t take evidently. I blame gremlins. It has been corrected.

# Replace a line / value in .ini file stored in Citrix UPM folder location when a change to the application is made.
# An example is for SiteManager, if you change the location of the .dat file for security.dat file and you are using a custom .ini
# created and stored with the user profile.

$filePath = "e:\locationofupmfolders"

$Files = Get-ChildItem -Path $filePath -Recurse -File -force -Include "smapp.ini"

foreach($file in $files)
    {
        $find = "value-you-want-to-change"
        
        $replace = "value-you-want-to-change-to"
        
        $content = Get-Content $($file.FullName) -Raw
        
        #write replaced content back to the file
        $content -replace $find,$replace | Out-File $($file.FullName) | write-output
        
        
    }  
 

Easy peasy. Now they have the new location of the security.dat file!

Change That Deprecated HTTP.REQ.USER

Get rid of it! In the How To Create The Wow nFactor part one (https://xenapplepie.com/2022/03/13/how-to-create-the-wow-nfactor/), there is a section where you get a popup after configuring your LDAPS authentication. This outlines resolving that by logging into your handy, dandy Netscaler ADC with the power of SSH or putty. I’ll also link from that location the changes listed here to resolve that. This example will use putty as getting in the door. After that point of connection, the commands are the same from an SSH session.

Open up Putty and enter the host name / IP.

Login with your nsroot privilege.

Enter “shell” to drop to the Linux shell.

At the prompt, enter “cd /nsconfig/loginschema/LoginSchema.”

Press “Enter.”

Enter “ls” to list folder contents. You are looking for the PrefilUserFromExpr.xml file.

Enter “cp PrefilUserFromExpr.xml /nsconfig/loginschema/PrefilUserFromExpraaa.xml.” You can change the file name to whatever you wish. I just used this name for the example. This copies the xml file that is the template for the xml file you are going to modify.

Press “Enter.”

Type “cd..” to go up a folder level.

Type “ls” to list folder contents. This is to confirm the file copied correctly.

Type “vi PrefilFromUserExpraaa.xml.” This will open the file in vi editor so that you can make changes to the file.

Press “Enter.”

Use your arrow keys to navigate to the ${http.req.user.name}.

Highlight the first “h.”

Press the “Del” key to delete the text until you have just “{}.”

Press the “i” key to “Insert” and enter “AAA.USER.NAME” in the area so that it looks like ${AAA.USER.NAME}.

Press the “Esc” key and enter “:w!” This will write the file.

Press the “Esc” key and enter “:q” This will quit the vi session.

Type “exit” and press “Enter.” This exits the shell session.

Type “exit” and press “Enter.” This will exit your putty session.

Now you will need to go back to the section for the LDAP schema in your nFactor flow and edit. You will choose the LDAPS_Auth_Test Login Schema.

Click “Edit.”

Click the pencil icon.

Click on the “PrefilFromUserExpraaa.xml.”

Click “Select.” If you do not do this part, you won’t see the change reflected. You will see the ${AAA.USER.NAME} in the “User name” field.

Click “OK.”

Click “Done.”

You have completed the change to the custom XML file to move from the deprecated setting!

What’s New In 2203!? Check It Out!

https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/whats-new.html

CVAD 2203!!! It Is Here!!

https://www.citrix.com/downloads/citrix-virtual-apps-and-desktops/product-software/citrix-virtual-apps-and-desktops-2203.html

Get on over and get it downloaded!

How To Create The Wow nFactor Part 2!

nFactor Flow

This is part 2 of the nFactor setup that outlines how to setup the AAA-TM server and the Authentication Profile that you need in order to implement the nFactor flow you created in part 1. Link to Part 1 below.

Part 1: https://xenapplepie.com/2022/03/13/how-to-create-the-wow-nfactor/

This section outlines setting up the AAA-TM server to replace basic authentication on Citrix Gateway. If you want to make this accessible to things other than just Citrix Gateway, you will need an IP address, a certificate, and a DNS entry to point to said IP address. If you want to ONLY use it for Citrix Gateway, there is an option under the configuration for IP Address Type to select “Non Addressable.” In this example, an IP address will be used.

Login to you Citrix ADC and navigate to Security > AAA – Application Traffic > Authentication Virtual Servers. Select “Add.”

You can do two different assignments with this setting. Under “IP Address Type,” you can select “Non Addressable” if you only wish to use for Citrix Gateway.

Enter “Name.”

Select “IP Address Type” as “IP Address.”

Enter IP address.

Click “OK.”

Click on “No Server Certificate.”

Select the certificate you wish to bind to the AAA-TM server.

Click “Select.”

Select “Bind.”

Select “Bind.”

Select “Continue.”

Click “nFactor Flow.”

Click “Add Binding.”

Select the nFactor flow you created previously and click “Select.”

Enter “true” for the “Expression.”

Click “Bind.”

In the upper-right, select “Portal Themes.”

Select “Add.”

Here you can change the look of the theme. Accepting the defaults, click “OK.”

Click “Done.”

Click “OK.”

Click “Done.”

This completes the setup of the AAA-TM vserver. The next step is to create the Authentication Profile that will be used on Citrix Gateway to utilize the AAA-TM vserver.

Navigate to Security > AAA – Application Traffic > Authentication Profile.

Select “Add.”

Enter “Name” for the profile.

In the drop down for “Authentication Virtual Server,” select the AAA-TM server you created.

Click “Select.”

Click “Create.”

All the pieces have been created, now to apply to Citrix Gateway vserver.

Navigate to Citrix Gateway > Citrix Gateway Virtual Servers.

Select the one you you wish to edit and select “Edit.”

In the upper-right, select “Authentication Profile.”

Select the authentication profile you created earlier and select “OK.”

If you have any policies under “Basic Authentication,” you will need to click the pencil icon and unbind all the policies you have bound there.

Click “OK.”

Click “Done” at the bottom.

Citrix Gateway vserver is now using the Advanced Authentication with nFactor!

Page 4 of 7

Powered by WordPress & Theme by Anders Norén