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

Tag: powershell Page 3 of 4

You Got Some Of That HSD? : Hosted Shared Desktop Information Gathering Script

Cropped image to remove space from user list

There are times that you created some Hosted Shared Desktops. You published them and gave them out. You want to make sure you don’t duplicate your work and create another one when you may have one that is already available for a user group. How about a script to see what you got, what you named it, what Delivery Group is hosting it, what users are assigned to it, and what servers are assigned to it? I’ve got just the script for you!

# Script to get all Hosted Shared Desktops and user assignments using ISE 5.1 and Citrix Studio SDK installed locally.

asnp Citrix*

$date = Get-Date -Format MMddyyyy

$adminAddress = "ddc.fqdn:80"

$getHSD = Get-BrokerEntitlementPolicyRule -AdminAddress $adminAddress -MaxRecordCount 10000

$report = @()

foreach($hsd in $getHSD){
  $line                  = "" | Select-Object PublishedName, IncludedUsers, DeliveryGroup, ServerNames 
  $desktopGroup          = Get-BrokerDesktopGroup -AdminAddress $adminAddress -uid $hsd.DesktopGroupUid
  $machineNames          = Get-BrokerMachine -AdminAddress $adminAddress -DesktopGroupName $desktopGroup.Name
  
  $line.PublishedName    = $hsd.PublishedName
    
  if($hsd.IncludedUsers.Name -ne $null){
    
    $line.IncludedUsers  = ($hsd.IncludedUsers.Name -join ';').ToString()
    
  }
  
  elseif($hsd.IncludedUsers.Name -eq $null){
   
    $line.IncludedUsers  = "None Assigned"
    
  }
  
  if($desktopGroup.Name -ne $null){
   
    $line.DeliveryGroup  = $desktopGroup.Name -join ';'
    
  }
  
  elseif($desktopGroup.Name -eq $null){

    $line.DeliveryGroup  = "None Assigned"
    
  }
  
  if($machineNames.HostedMachineName -ne $null){
    
    $line.ServerNames    = $machineNames.HostedMachineName -join ';'
    
  }
  
  elseif($machineNames.HostedMachineName -eq $null){

    $line.ServerNames    = "None Assigned"

  }
  
  $report += $line

}

$report | Export-CSV c:\scripts\logs\$date-hostedshareddesktops.csv -Append -NoTypeInformation

Have You Tried A Good Old Fashioned Reboot? : Script To Get Citrix Delivery Group Reboot Schedules

Maybe when you are planning to do some upgrades but don’t remember when you set your reboot schedule times on your Delivery Groups. This will show you all the reboot schedules you have configured with server names. This also shows if you have Delivery Groups with no servers assigned to them, but had previously created a reboot schedule.

Update: I did run into an interesting thing with it. I had to define the if and elseif in order for it to evaluate as being true. Not sure what was going on with that.

# Script to get reboot schedules of Delivery Groups with times and server names using ISE 5.1 and Citrix Studio SDK installed locally.

asnp Citrix*

$date = Get-Date -Format MMddyyyy

$adminAddress = "ddc.fqdn:80"

$ctxRebootSchedule = Get-BrokerRebootScheduleV2 -AdminAddress $adminAddress -MaxRecordCount 100000

$report = @()

foreach($ctx in $ctxRebootSchedule) {
  $line                  = "" | Select-Object DesktopGroupName, ScheduleName, Enabled, Frequency, StartTime, RebootDuration, ServerCount, ServerNames
  $machineNames          = Get-BrokerMachine -AdminAddress $adminAddress -DesktopGroupName $ctx.DesktopGroupName
    
  $line.DesktopGroupName = $ctx.DesktopGroupName
  $line.ScheduleName     = $ctx.Name
  $line.Enabled          = $ctx.Enabled
  $line.Frequency        = $ctx.Frequency
  $line.StartTime        = $ctx.StartTime
  $line.RebootDuration   = $ctx.RebootDuration
  $line.ServerCount      = ($machineNames.HostedMachineName).count 
  
  if(($line.ServerCount) -ne 0){
   
    $line.ServerNames    = ($machineNames.HostedMachineName) -join ';'  
    
  }
  elseif(($line.ServerCount) -eq 0) {
    
    $line.ServerNames    = "None Assigned To DG"
    
  }
  
  $report += $line
  
  }
  
$report | export-csv c:\scripts\logs\$date-Citrix-Reboot-Schedule.csv -Append -NoTypeInformation

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
    
    

Cross Domain User Add Between Domains With Two-Way Transitive Trust

Quick little script to add users from one domain to a group in another domain.

# Quick cross domain user add with 2 domains in the same forest with two-way transitive trusts using universal / domain local groups for access.
$userDomain  = "userdomain"
$groupDomain = "groupdomain"
$userName    = "useraccountname"
$groupName   = "groupname"
$User        = Get-ADUser -Identity $userName -Server $userDomain
$Group       = Get-ADGroup -Identity $groupName -Server $groupDomain

Add-ADGroupMember -Identity $Group -Members $User -Server $groupDomain

Table For One? : Making DHCP Reservations And Getting Reservations

Using DHCP reservations and you don’t want to have to use the MMC or remote into the server to make those or see what you have reserved? A quick bit of powershell to make and get those reservations at that exclusive table for you, with a nice little glass of CSV with it!

# A couple of commands to create and get reservations from a remote DHCP server. This requires Powershell Remoting, firewall to open to server, admin rights to server, DhcpServer PS module, and used in ISE 5.1.

# DHCP Remote reservation
$sb = {
  $scopeID = "IPsubnet"
  $clientMac = "clientmacaddress"
  $clientName = "clientcomputername"
  $clientIP = "reserveIPaddress"


  Add-DhcpServerv4Reservation -ScopeId $scopeID -Name $clientName -IPAddress $clientIP  -ClientId $clientMac 
 }
  
$dhcpServer = "dhcpservername.fqdn"

Invoke-Command -ComputerName $dhcpServer -ScriptBlock $sb

# Get Remote Reservations
$report =@()

$sb = {
  $scopeID = "IPsubnet"
  
  $output = Get-DhcpServerv4Reservation -ScopeId $scopeID | Select-Object Name, IPAddress, ClientID
  
  $report += $output
}

$dhcpServer = "dhcpservername.fqdn"

Invoke-Command -ComputerName $dhcpServer -ScriptBlock $sb

$report | export-csv c:\scripts\logs\dhcpreservations.csv -Append -NoTypeInformation

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




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!

Keep It On The Level, The MinimumFunctionalLevel

Sometimes, over time, you upgrade and upgrade. But maybe you forgot to upgrade your functional levels for your Machine Catalogs and Delivery Groups. If you don’t have the right functional level, you may be missing out on features. (Link to functional levels: https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/install-configure/machine-catalogs-create.html#vda-versions-and-functional-levels)

So here is a quick way to upgrade the functional level. This is done for “L7_20” level. As newer levels come out, you can change the value.

# This will upgrade functional levels on Delivery Groups and Machine Catalogs. This will need to be ran on either a Delivery Controller or somewhere you have the Citrix Powershell SDK installed.
asnp Citrix*
$adminAddress = "deliverycontroller-FQDN:80"
$brokerCatalog = Get-BrokerCatalog -AdminAddress $adminAddress |Where MinimumFunctionalLevel -lt "L7_20"|Select Name, MinimumFunctionalLevel
$brokerDesktopGroup = Get-BrokerDesktopGroup -AdminAddress $adminAddress |Where MinimumFunctionalLevel -lt "L7_20"| Select Name, MinimumFunctionalLevel
foreach($brokerCat in $brokerCatalog) {
    Get-BrokerCatalog -AdminAddress $adminAddress -name $brokerCat.name | Set-BrokerCatalog -MinimumFunctionalLevel L7_20
    }
foreach($brokerDesk in $brokerDesktopGroup) {
    Get-BrokerDesktopGroup -AdminAddress $adminAddress -name $brokerDesk.name | Set-BrokerDesktopGroup -MinimumFunctionalLevel L7_20
    }
# Check Machine Catalogs after upgrading functional levels
Get-BrokerCatalog -AdminAddress $adminAddress |Where MinimumFunctionalLevel -lt "L7_20"| Select Name, MinimumFunctionalLevel
# Check Delivery Groups after upgrading functional levels
Get-BrokerDesktopGroup -AdminAddress $adminAddress |Where MinimumFunctionalLevel -lt "L7_20" | Select Name, MinimumFunctionalLevel

Under My SSL Thumbprint

Wouldn’t you know it!? A vCenter certificate got changed out and now your hypervisor connector is showing it no worky. Come to find out you missed the email memo that the certificate was getting changed. Or you might’ve been busy and didn’t think too much of it. Well, now you have to get it fixed! What if there was a way to get that information quickly and easily so that you just had to do some copy / paste magic to resolve it? Well…. There is! This handy dandy little script will get those pesky thumbprints and kick them out as a csv so you can use them to update your connector in the XenDesktop database.

# A script to check SSL thumbprints on your Citrix hypervisor connections. This will get all of the thumbprints of your connectors and will get the SSL thumbprints of your vCenters if you happen to have more than one.
# This is for running on in-premise Citrix farm (7.x) on a Delivery Controller with 10.1.0 VMware.PowerCLI module and the Citrix SDK installed with VMware ESXi 7.0U1 or later. This also is ran in ISE. Get-SSLThumbprint function is from https://gist.github.com/lamw/988e4599c0f88d9fc25c9f2af8b72c92
# with the return $SSL_THUMBPRINT -replace '(..(?!$))','$1' changed from ending in '$1:' The instructions for changing the SSL thumbprint can be found at https://support.citrix.com/article/CTX224551. 

asnp Citrix*

Function Get-SSLThumbprint {
    param(
    [Parameter(
        Position=0,
        Mandatory=$true,
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true)
    ]
    [Alias('FullName')]
    [String]$URL
    )

add-type @"
        using System.Net;
        using System.Security.Cryptography.X509Certificates;
            public class IDontCarePolicy : ICertificatePolicy {
            public IDontCarePolicy() {}
            public bool CheckValidationResult(
                ServicePoint sPoint, X509Certificate cert,
                WebRequest wRequest, int certProb) {
                return true;
            }
        }
"@
    [System.Net.ServicePointManager]::CertificatePolicy = new-object IDontCarePolicy

    # Need to connect using simple GET operation for this to work
    Invoke-RestMethod -Uri $URL -Method Get | Out-Null

    $ENDPOINT_REQUEST = [System.Net.Webrequest]::Create("$URL")
    $SSL_THUMBPRINT = $ENDPOINT_REQUEST.ServicePoint.Certificate.GetCertHashString()

    return $SSL_THUMBPRINT -replace '(..(?!$))','$1'
}


$xdConnections = Get-ChildItem XDHyp:\Connections | Select HypervisorConnectionName, HypervisorAddress, SslThumbprints

$xdThumbprints = @()

foreach($xdc in $xdConnections) 
    {
    $line = ""| Select HypervisorConnectionName, HypervisorAddress, SslThumbprints, vCenterThumbprints, SameThumbprint
              
    $line.HypervisorConnectionName = ($xdc).HypervisorConnectionName
    $line.HypervisorAddress        = ($xdc).HypervisorAddress | Out-String
    $line.SslThumbprints           = ($xdc).SslThumbprints | Out-String
    $line.vCenterThumbprints       = Get-SSLThumbprint (($xdc).HypervisorAddress | Out-String)
    $line.SameThumbprint           = ($line.SslThumbprints -match $line.vCenterThumbprints)

    $xdThumbprints += $line
        
    }

$xdThumbprints | Export-Csv c:\scripts\logs\sslthumbprints.csv

Page 3 of 4

Powered by WordPress & Theme by Anders Norén