Show Citrix Studio administrators

Recurses AD groups found to show all user accounts with any access to Citrix Studio.
Needs to be run using an account that has at least read-only Studio access.
Use it to see exactly which users have access and what level.
Arguments:
User Name to Query - an optional username or regular expression to restrict the display to

If a name is specified as a parameter then only that account is reported on
Version 1.6.11
Created on 2018-10-24
Modified on 2018-11-26
Created by Guy Leech
Downloads: 50

The Script Copy Script Copied to clipboard
#requires -version 3.0

<#
    Retrieve all user accounts which have Citrix Studio admin access

    Guy Leech

    Modification History:
    
    31/10/18  GRL  Add unidentified accounts to the output
#>

[string]$userName = $null
if( $args.Count -and $args[0] )
{
    $userName = $args[0]
}

[int]$outputWidth = 400
[hashtable]$global:groups = @{}

Function Get-GroupMembers( $admin , $group )
{
    $group.psbase.invoke('members') | ForEach-Object `
    {
        $adspath = $_.GetType().InvokeMember( 'ADSPath' ,  'GetProperty',  $null,  $_, $null)
        $class = $_.GetType().InvokeMember( 'Class' ,  'GetProperty',  $null,  $_, $null)

        if( $class -eq 'group' )
        {
            try
            {
                $groups.Add( $adspath , $global:groups )
                Get-GroupMembers -group ([ADSI]"$adspath,$class") -admin $admin
            }
            catch
            {
                Write-Warning "Group $adspath is nested recursively"
            }
        }
        elseif( $class -eq 'user' )
        {
            $accountbits = $adspath -split '/'
            Get-UserProperties -name "$($accountbits[-2])\$($accountbits[-1])" -user ([ADSI]"$adspath,$class") -viaGroup $group.Name.Value -admin $admin
        }
    }
}

Function Get-UserProperties( $name , $admin , $user , $viaGroup )
{
    $lastLogin = if( $user )
    {
        try
        {
            [math]::round( (New-TimeSpan -End ([datetime]::Now)  -Start $user.LastLogin.Value).TotalDays , 1 )
        }
        catch
        {
            'Never'
        }
    }
    else
    {
        '?'
    }

    [pscustomobject][ordered]@{ 
        'Name' = $name 
        'Full Name' = $user.FullName.Value
        'Admin Group' = $viaGroup 
        'Admin Enabled' = if( $admin.Enabled ) { 'Yes' } else { 'No' }
        'Rights' = $admin.Rights -join ','
        ##'Description' = $user.Description.Value
        'Last AD Login (days)' = $lastLogin
        ##'Password Last Changed' = (Get-Date).AddSeconds( -($user.PasswordAge.Value) )
        'Password Expired' = if( $user) { if( $user.PasswordExpired )  { 'Yes' } else { 'No' } } else { '?' }
        'Account Disabled' = if( $user) { if( ( $user.UserFlags.Value -band 0x02 ) )  { 'Yes' } else { 'No' }} else { '?' }
        'Account Locked' =   if( $user) { if( ( $user.UserFlags.Value -band 0x10 ) ) { 'Yes' } else { 'No' }} else { '?' }
        ##'Bad Passwords' = $user.BadPasswordAttempts.Value
    }
}

Add-PSSnapin 'Citrix.DelegatedAdmin.Admin.*' -ErrorAction Stop

## can't search at this level for account as will only work if assigned at the to level, not via a group
[array]$admins = @( Get-AdminAdministrator -ErrorAction Stop )

$results = @( ForEach( $admin in $admins )
{
    $user = $null
    $group = $null

    [string]$domain,[string]$account = $admin.Name -split '\\'
    
    $group = [ADSI]"WinNT://$domain/$account,group"
    if( ! $group -or ! $group.PSObject.properties[ 'Path' ] )
    {
        $group = $null
        $user = [ADSI]"WinNT://$domain/$account,user"
    }

    if( $group )
    {
        Get-GroupMembers -admin $admin -group $group 
    }
    elseif( $user -and $user.PSObject.properties[ 'Path' ]  )
    {
        Get-UserProperties -admin $admin -user $user -name $admin.Name
    }
    else
    {
        Write-Warning "Unable to find account entity `"$($admin.Name)`""
        Get-UserProperties -admin $admin -user $null -name $admin.Name
    }
}) | Where-Object { $_.Name -match $userName } 

# Altering the size of the PS Buffer
$PSWindow = (Get-Host).UI.RawUI
$WideDimensions = $PSWindow.BufferSize
$WideDimensions.Width = $outputWidth
$PSWindow.BufferSize = $WideDimensions

[string]$summary = "Got $($results.count) individual admins from $($admins.Count) entries"
if( ! [string]::IsNullOrEmpty( $userName ) )
{
    $summary += " matching `"$username`""
}

$summary
$results | Sort 'Rights' | Format-Table -AutoSize