Generate a Citrix Desktop Report Based on Active Directory Users

In this post, we are going to merge data from two different sources to generate a report that can provide insight into your Citrix environment. I will show you how to combine Active Directory data for the users in your domain with Citrix data. This report will provide you with the following knowledge:

  • Users that do not have a Citrix Desktop assigned
  • Users that have multiple Citrix Desktops assigned
  • Users that have never used their assigned Citrix Desktop
  • The last time your users connected to their Citrix Desktop
  • Percentage of Active Directory Users that have a Citrix Desktop assigned (manual math required)

Prerequisites

There are a few things needed in order to generate this report. The most obvious is the need for an Active Directory domain with users. If you are going to utilize a dedicated server or desktop to run the report, then you will need to install the RSAT Active Directory Domain Services Tools. RSAT is now included directly from within Windows 10. In order to get it installed, search for “Manage optional features” from the start menu and then click on “Add a feature”. Check the box for “RSAT: Active Directory Domain Services and Lightweight Directory Services Tools” and click “Install”. Once it’s finished installing, the Active Directory PowerShell commands found in the script will run. The second most obvious is to have at least one Citrix Delivery Controller and Desktops assigned to users. The Citrix PowerShell snap-ins that are needed are installed automatically when you install a Delivery Controller or Studio. Ensure that you are running your scripts from a machine that has Studio installed.


Code

GitHub

Time to take a look at the code involved to achieve this report. First, we need to import the custom module that we created in my previous post. Alternatively, you could hard code the Citrix Delivery Controllers directly into the $Random_DCs variable. Then we need to import the Citrix PowerShell Snapins.

### Custom module we made in previous blog post
Import-Module "\\path\to\Infra_Module.psm1" -Force

### Citrix Snapin
try{
    ### Adding Citrix powershell snapins
    Add-PsSnapin *Citrix* -ErrorAction Stop
}
Catch [Exception]{ ### If the command inside the try statement fails the error will be outputted
    Write-host "Citrix Powershell snapins are not present, install the snapins and try again. Script is exiting..." -BackgroundColor Red -ForegroundColor White
    Return
}

Next, we will declare the variables used for the script. We need to specify where the csv file will be written to. You can specify a UNC path or a local directory. By using the Infra_One_Random_Each_Site function from the custom module referenced above, we can dynamically retrieve a random delivery controller from multiple Citrix sites. So, if you have multiple sites, we can search across all of them for user assigned desktops. The final line in this code snippet is just to setup the progress bar that will be used later.

$Time = Get-Date -Format "yyyy-MM-dd_HHmm"
$csvfile = "\\path\to\AD_Users_to_Citrix_Report_$Time.csv"
### Grabbing one random Citrix Delivery Controller server from each site based on the given environment, type and active status
$Random_DCs = Infra_One_Random_Each_Site -Environment prod -Type citrix_dc -Active true ### Custom module we made in previous blog post
$i=0 # setting variable to 0 for the start of the progress bar

Below is the function that we utilize to append the results to the csv file after merging Active Directory and Citrix data together.

Function Write_to_csv {
    ### Creating a custom object to hold all of the pertinent data so we can write it to csv
    $outputcsv = [PSCustomObject] @{
    VM = $VM
    VM_IP = $IP
    User_ID = $AD_User.SamAccountName
    User_DisplayName = $AD_User.DisplayName
    User_Email = $AD_User.Mail
    User_Location = $AD_User.City
    User_Department = $AD_User.Department
    User_Title = $AD_User.Title
    User_Created = $AD_User.whenCreated
    Summary_State = $SummaryState
    Last_Connection = $LastConnection
    VM_Created = $Created
    EndPoint_Name = $EndPoint
    EndPoint_IP = $EndPoint_IP
    }
    ### Appending that custom object to the csv file
    $outputcsv | Export-Csv -Path $csvfile -Append -NoTypeInformation
}

Here we are getting all of the enabled Active Directory users that have a mail and manager value. This may not be an adequate way to identify “real” users in your domain. The goal here is to eliminate any service accounts or accounts that are not specifically tied to a real person.

$AD_Users = Get-ADUser -Filter {Enabled -eq $true}  -Properties UserPrincipalName, City, StreetAddress, Department, Title, DisplayName, whenCreated, mail, manager | Select-Object DisplayName, SamAccountName, UserPrincipalName, City, StreetAddress, Department, Title, whenCreated, mail, manager | Where-Object {$_.mail -ne $null -and $_.manager -ne $null}

Finally, we come to the section of code that does the foreach loop on all the users that are returned from the above Get-ADUser command. The first two lines in the foreach loop are just to create a progress bar so you know how far along the script is; this can be especially helpful if you have a large domain. Then it goes through each Citrix DC and gets assigned Citrix Desktops for that given user. This utilizes the User Principal Name because it is a common value between both Citrix and Active Directory. Next, the script will determine if the user has no Desktops assigned, multiple desktops or just one. From there it will take the data from Active Directory and Citrix (if any) and calls the Write_to_csv function to append the data to the csv file. This continues until all users have been parsed through. Once the script is complete you will have a fully populated csv file with all Active Directory users and their assigned Citrix Desktop that can be filtered and sorted in Excel to reveal data important to you.

Foreach ($AD_User in $AD_Users) {
    $i++ ### incrementing the progress bar by 1 each loop through
    Write-Progress -Activity "All AD Users" -Status ("Checking : {0}" -f $AD_User.SamAccountName) -PercentComplete ($i/$AD_Users.count*100) -Id 0 ### Progress bar
    $Desktop = @() ### creating blank array
    ### Foreach statement to go through each returned Citrix DC and find desktops associated with a given user
    Foreach ($Random_DC in $Random_DCs){
        $Desktop += Get-BrokerDesktop -AssociatedUserUPN $AD_User.UserPrincipalName -DeliveryType DesktopsOnly -AdminAddress $Random_DC -MaxRecordCount 999999 | Select-Object Hostedmachinename, LastConnectionTime, SummaryState, ClientName, ClientAddress, IPAddress, AssociatedUserNames, AssociatedUserUPNs | Sort-Object -Property Hostedmachinename
    }
    #####################################################################
    ### If the given AD User DOESN'T have an assigned Citrix Desktop, we will write to the csv that none is assigned
    If (-not $Desktop){
        $VM = "None Assigned"
        $IP = "None Assigned"
        $SummaryState = "None Assigned"
        $LastConnection = "None Assigned"
        $EndPoint = "None Assigned"
        $EndPoint_IP = "None Assigned"
        $Created = "None Assigned"
        #####################################################################
        ### Calling function to write to CSV
        Write_to_csv
        ### Cleaning up variables
        Clear-Variable VM, IP, Summary_State, LastConnection, Created, EndPoint, EndPoint_IP -ErrorAction SilentlyContinue
        #####################################################################
    }
    #####################################################################
    ### If the given AD user DOES have an assigned Citrix Desktop, we will write the details for it to csv
    Else{
        #####################################################################
        ### If the given AD user has more than one Citrix Desktop assigned we will account for all of them
        If (($Desktop.HostedMachineName).count -ge 2){
            Foreach ($item in $Desktop){
                $VM = $item.Hostedmachinename
                $IP = $item.IPAddress
                $SummaryState = $item.SummaryState
                ### Grabbing the date the active directory computer object was created
                $Created = Get-ADComputer $item.Hostedmachinename -Properties Created | ForEach-Object {$_.Created}
                ### If the AD user has never connected to the Citrix Desktop we will add Never Connected to the csv file for those fields
                If ($null -eq $item.LastConnectionTime){
                    $LastConnection = "Never Connected"
                    $EndPoint = "Never Connected"
                    $EndPoint_IP = "Never Connected"
                }
                Else{
                    $LastConnection = $item.LastConnectionTime
                    $EndPoint = $item.ClientName
                    $EndPoint_IP = $item.ClientAddress
                }
                #####################################################################
                ### Calling function to write to CSV
                Write_to_csv
                ### Cleaning up variables
                Clear-Variable VM, IP, SummaryState, LastConnection, Created, EndPoint, EndPoint_IP -ErrorAction SilentlyContinue
                #####################################################################
            }
        }
        #####################################################################
        ### If the given AD user has only one Citrix Desktop assigned we will write it to the csv
        Else {
            $VM = $Desktop.HostedMachineName
            $IP = $Desktop.IPAddress
            $SummaryState = $Desktop.SummaryState
            ### Grabbing the date the active directory computer object was created
            $Created = Get-ADComputer $Desktop.Hostedmachinename -Properties Created | ForEach-Object {$_.Created}
            ### If the AD user has never connected to the Citrix Desktop we will add Never Connected to the csv file for those fields
            If ($null -eq $Desktop.LastConnectionTime){
                $LastConnection = "Never Connected"
                $EndPoint = "Never Connected"
                $EndPoint_IP = "Never Connected"
            }
            Else{
                $LastConnection = $Desktop.LastConnectionTime
                $EndPoint = $Desktop.ClientName
                $EndPoint_IP = $Desktop.ClientAddress
            }
            #####################################################################
            ### Calling function to write to CSV
            Write_to_csv
            ### Cleaning up variables
            Clear-Variable VM, IP, SummaryState, LastConnection, Created, EndPoint, EndPoint_IP -ErrorAction SilentlyContinue
            #####################################################################
        }
        #####################################################################
    }
    #####################################################################
}
#####################################################################

That’s it for now, thanks for reading!


Check out my other blog posts:

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s