Script Center > Repository > Remote Desktop Services > Query Virtual Machine assignment information
TechNet Script Center logo

Welcome to the TechNet Script Center Repository!

Each contribution is licensed to you under a License Agreement by its owner, not Microsoft. Microsoft does not guarantee the contribution or purport to grant rights to it.

Query Virtual Machine assignment information

(Microsoft)
VERIFIED AND TESTED BY THE SCRIPT CENTER TEAM
Rate it:
 
 
 
 
 
Script Code
Windows PowerShell
<# 
.Synopsis 
    Gets the user/pool assignement details of virtual machines that are managed by the RD Connection Broker Server on which the script is being executed.
    
.Description 
    The script displays the user/pool assignement details of virtual machines that are managed by the RD Connection Broker Server on which the script is being executed. It displays the list of all the virtual machines and their associated status - assigned/unassigned to users/pools.
    
    Note: This script requires privileges to query the domain or trusted domains (if required) and hence must be run with the appropriate user credentials.
          To get a summary of the count of virtual machines, based on assignment type, refer to the examples.

.Parameter User
    Name(s) of the user(s) or user group(s) for whom the virtual machine assignment details are to be fetched.

.Parameter VirtualMachine
    Name(s) of the virtual machine(s) to get the assignment status.

.Parameter Pool
    Name(s) of the pool(s) to enumerate virtual machine(s) assigned to it.

.Parameter UserAssigned
    Switch: Displays information only for virtual machines that are assigned to users. If querying with "User" parameter, fetches virtual machine(s) information only for the specific user(s) or user group(s).

.Parameter PoolAssigned
    Switch: Displays information only for virtual machines that are assigned to pool(s).

.Parameter UnAssigned
    Switch: Displays information only for virtual machines that are currently unassigned. If querying with "User" parameter, fetches virtual machine(s) information assigned to all users except the ones specified.

.Example 
    PS C:\> .\Get-VMAssignment.ps1
    
    Displays the list of all the virtual machines managed by the RD Connection Broker server on which the script is executing and their assignment status.
    
.Example 
    PS C:\> .\Get-VMAssignment.ps1 -UserAssigned
    
    Displays the list of all the virtual machines managed by the RD Connection Broker server on which the script is executing that are assigned to users. It also displays the details of the user to which the virtual machine has been assigned.
    
.Example 
    PS C:\> .\Get-VMAssignment.ps1 -PoolAssigned
    
    Displays the list of all the virtual machines managed by the RD Connection Broker server on which the script is executing that are assigned to pools. It also displays the name of the pool to which the virtual machine has been assigned.

.Example 
    PS C:\> .\Get-VMAssignment.ps1 -UnAssigned
    
    Displays the list of all the virtual machines managed by the RD Connection Broker server on which the script is executing that are not assigned to users or pools.

.Example 
    PS C:\> .\Get-VMAssignment.ps1 -User mydomain\user01, trusteddomain\group01
    
    Displays the virtual machine(s) assignment status for the user "mydomain\user01" and all users belonging to the group "trusteddomain\group01".

.Example 
  
.Example 
    PS C:\> .\Get-VMAssignment.ps1 -User trusteddomain\group01 -UnAssigned
    
    Enumerates users belonging to the group "trusteddomain\group01" who do not have virtual machines assigned to them.

.Example 
    PS C:\> .\Get-VMAssignment.ps1 -VirtualMachine VM01.mydomain.myorg.com, VM02.mydomain.myorg.com
    
    Displays the assignment related information for the virtual machines VM01.mydomain.myorg.com and VM02.mydomain.myorg.com.

.Example 
    PS C:\> .\Get-VMAssignment.ps1 -Pool Win7Pool
    
    Displays all the virtual machines assigned to the pool Win7Pool.

.Example 
    PS C:\> .\Get-VMAssignment.ps1 | Group-Object -Property AssignmentType -NoElement
    
    Summarizes the virtual machine assignemnt details, displays the count of virtual machines that have been assigned. 
    
.Outputs 
    PSObject(s).
    These object(s) returned have the following information related to the virtual machine:
    
    Property        Description 
    --------------------------------------------------
    VM              Name of the Virtual Machine.
    Host            RD Virtualization host server on which this virtual machine is running.
    AssignedTo      Name of the user or pool to which this virtual machine is assigned.
    AssignmentType  Has values "User" or "Pool", based on whether the virtual machine is assigned to a user or a pool.

    These object(s) contain following information related to User assignment:
    
    Property        Description 
    --------------------------------------------------
    User            Name of the user.
    VM              Name of the Virtual Machine assigned to this user.
    Host            RD Virtualization host server on which this virtual machine is hosted.
    
.Link 
    Set-PersonalVirtualDesktop
    Clear-PersonalVirtualDesktop   
#>

[CmdletBinding(DefaultParametersetName="SimpleFilter")]
param (

    [Parameter(Mandatory=$TRUE, ParameterSetName="Users")]
    [String[]]
    $User,

    [Parameter(Mandatory=$TRUE, ParameterSetName="virtual machines")]
    [String[]]
    $VirtualMachine,

    [Parameter(Mandatory=$TRUE, ParameterSetName="Pools")]
    [String[]]
    $Pool,

    [Parameter(Mandatory=$FALSE, ParameterSetName="Users")]
    [Parameter(Mandatory=$FALSE, ParameterSetName="SimpleFilter")]
    [Switch]
    $UserAssigned,
    
    [Parameter(Mandatory=$FALSE, ParameterSetName="SimpleFilter")]
    [Switch]
    $PoolAssigned,
    
    [Parameter(Mandatory=$FALSE, ParameterSetName="Users")]
    [Parameter(Mandatory=$FALSE, ParameterSetName="SimpleFilter")]
    [Switch]
    $UnAssigned
)

$propertyNames = @{
    [System.DirectoryServices.ActiveDirectory.DomainMode]::Windows2008Domain = "mstsproperty01"
    [System.DirectoryServices.ActiveDirectory.DomainMode]::Windows2008R2Domain = "mstsproperty01"
}

function Get-FQDN ([string]$distinguishedName)
{
	$nameTranslator = New-Object -ComObject NameTranslate
	$translatorType = $nameTranslator.GetType()
	[void]$translatorType.InvokeMember("init", ”InvokeMethod”, $NULL, $nameTranslator, @(3, $NULL))
	[void]$translatorType.InvokeMember("set", ”InvokeMethod”, $NULL, $nameTranslator, @(1, $distinguishedName))

	$mName = $translatorType.InvokeMember("get", ”InvokeMethod”, $NULL, $nameTranslator, 3).split("\")[1].trim("$")
	$mDomain = $translatorType.InvokeMember("get", ”InvokeMethod”, $NULL, $nameTranslator, 2).split("/")[0]
	$fqdn = "{0}.{1}" -f $mName, $mDomain

	return $fqdn
}

function Get-DomainNetBIOS ([string]$domain)
{
    $rootDSE = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$domain/rootDSE"
    if (-not $rootDSE.Properties) {return}
    $domainCN = $rootDSE.Properties['defaultNamingContext'][0]

    $parts = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$domain/CN=Partitions,CN=Configuration,$domainCN"
    $parts.Children | ?{$_.Properties["nCName"][0] -eq $domainCN} | %{$_.Properties["NetBIOSName"][0]}
}

function Get-VMAssignmentDictionary ([string[]]$domainNames)
{
    $compUserDict = @{}
    
    $currentDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain()
    $allTrustedDomains = $currentDomain.GetAllTrustRelationships() | ?{$_.TrustDirection -eq "Outbound" -OR $_.TrustDirection -eq "Bidirectional"}

    $domainsToQuery = @($currentDomain.Name)
    $allTrustedDomains | ?{$_} | %{$domainsToQuery += $_.TargetName}

    $domainNetbiosMap = @{}
    $domainsToQuery | %{$domainNetbiosMap[$_] = (Get-DomainNetBIOS $_)}
    
    if (($domainNames -ne $NULL) -AND ($domainNames.Count -ge 1))
    {
        $domainNames | ?{$domainNetbiosMap.Values -notcontains $_} | %{Write-Warning ("Unknown domain : $_")}
        $domainsToQuery =  $domainNetbiosMap.Keys | ?{$domainNames -contains $domainNetbiosMap[$_]}
        
        Write-Verbose "Querying domains $($domainsToQuery -join ", ")"
    }
    
    foreach ($domain in $domainsToQuery)
    {
        $domainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext 'Domain', $domain
        
        $domObject = $NULL
        try { $domObject = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($domainContext) }
        catch {Write-Error "Unable to connect to domain : $domain. $($_.Exception.InnerException.Message)"}
        
        if (-not $domObject) { continue }
        
        $desktopPropertyName = $propertyNames[$domObject.DomainMode]
        if ($desktopPropertyName -eq $NULL) { $desktopPropertyName = "mstsproperty01" }
    
        $dirEntry = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$domain"
        $objsearch = New-Object System.DirectoryServices.DirectorySearcher $dirEntry
        $objsearch.Filter = "(& (ObjectCategory=user)($desktopPropertyName=*))"
        [void]$objsearch.PropertiesToLoad.Add("cn")
        [void]$objsearch.PropertiesToLoad.Add("samaccountname")
        [void]$objsearch.PropertiesToLoad.Add($desktopPropertyName)
        
        foreach ($entry in $objsearch.FindAll())
        {
            if($entry.Properties[$desktopPropertyName] -ne $NULL)
            {
                $distinguishedName = $entry.Properties[$desktopPropertyName] | ?{$_ -like "machine=*"}
                $NULL, $friendlyVMName = $distinguishedName -split "="
                $friendlyUserName = "{0}\{1}" -f ($domainNetbiosMap[$domain]), $entry.Properties["samaccountname"][0]
                
                if ($friendlyVMName)
                {
                    $compUserDict[$friendlyVMName] = $friendlyUserName
                }
            }
        }
        
        $objsearch.Dispose()
    }
    
    return $compUserDict
}


function Convert-ToDomainUserFormat([string]$adsiPath)
{
    if ($adsiPath -match "WinNT://(.*)/(.*)")
    {
        return ("{0}\{1}" -f $matches[1..2])
    }
}

function Get-User([string]$adsiEntry)
{
    if ($adsiEntry -like "*\*")
    {
        $adsiPath = "WinNT://{0}/{1}" -f ($adsiEntry -split "\\")
    }
    else
    {
        $adsiPath = "WinNT://{0}/{1}" -f ((Get-WmiObject Win32_ComputerSystem).Domain.split('.')[0]), $adsiEntry
    }
    $adsiObj = [ADSI]$adsiPath
    
    if(-not $adsiObj.Name)
    {
        Write-Error "Invalid user/group : $adsiEntry"
        return
    }
    
    if ($adsiObj.Class -eq "User")
    {
        return (Convert-ToDomainUserFormat $adsiObj.Path)
    }
    
    $groupMembers = $adsiObj.Members() | %{[System.DirectoryServices.DirectoryEntry]$_}
    foreach ($member in $groupMembers)
    {
        switch($member.Class)
        {
            "Group" {Get-User (Convert-ToDomainUserFormat $member.Path)}
            "User"  {Write-Output (Convert-ToDomainUserFormat $member.Path)}
        }
    }
}



function Get-PoolAssignment()
{
    $vmList = @(Get-WmiObject -Namespace root\cimv2 -Query "Select * from Win32_SessionBrokerTarget where pluginname='VmResource' and farmname != ''")
    
    $poolDict = @{}
    Get-WmiObject -Namespace root\cimv2\terminalservices -Class Win32_TSRemoteDesktop | %{$poolDict[$_.Alias] = $_.Name}
    
    foreach ($vm in $vmList)
    {
        $vmEntry = New-Object PSObject

        $vmEntry | Add-Member -MemberType NoteProperty -Name VM -Value $vm.TargetName
        $vmEntry | Add-Member -MemberType NoteProperty -Name Host -Value $vm.Environment
        $vmEntry | Add-Member -MemberType NoteProperty -Name AssignedTo -Value $poolDict[$vm.FarmName]
        $vmEntry | Add-Member -MemberType NoteProperty -Name AssignmentType -Value "Pool"
        
        $vmEntry
    }
}



function Get-Assignment([string[]]$domainNames)
{
    $vmList = @(Get-WmiObject -Namespace root\cimv2 -Query "Select * from Win32_SessionBrokerTarget where pluginname='VmResource'")
    $vmUserDict = Get-VMAssignmentDictionary $domainNames
    
    $poolDict = @{}
    Get-WmiObject -Namespace root\cimv2\terminalservices -Class Win32_TSRemoteDesktop | %{$poolDict[$_.Alias] = $_.Name}
    
    
    foreach ($vm in $vmList)
    {
        $assignedTo = $NULL
        $assignedType = $NULL

        if ($vmUserDict[$vm.TargetName])
        {
            $assignedTo = $vmUserDict[$vm.TargetName]
            $assignedType = "User"
            
            if ($vm.FarmName -ne "")
            {
                Write-Warning "The virtual machine '$($vm.TargetName)' is assigned to user '$assignedTo' and to pool '$($poolDict[$vm.FarmName])'."
            }
        }
        elseif ($vm.FarmName -ne "")
        {
            $assignedTo = $poolDict[$vm.FarmName]
            $assignedType = "Pool"
        }
    
        $vmEntry = New-Object PSObject

        $vmEntry | Add-Member -MemberType NoteProperty -Name VM -Value $vm.TargetName
        $vmEntry | Add-Member -MemberType NoteProperty -Name Host -Value $vm.Environment
        $vmEntry | Add-Member -MemberType NoteProperty -Name AssignedTo -Value $assignedTo
        $vmEntry | Add-Member -MemberType NoteProperty -Name AssignmentType -Value $assignedType
        
        $vmEntry
    }
}


function Get-UserAssignment
{

param (

    [Parameter(Mandatory=$TRUE)]
    [string[]]
    $User,
    
    [Parameter(Mandatory=$FALSE)]
    [Switch]
    $UserAssigned,
    
    [Parameter(Mandatory=$FALSE)]
    [Switch]
    $UnAssigned

)

    $showAssigned = $UserAssigned -OR -not $UnAssigned
    $showUnAssigned = $UnAssigned -OR -not $UserAssigned

    $users = @($User | %{Get-User $_})
    $domains = $users | %{$_ -split "\\" | Select-Object -First 1} | Sort-Object -Unique
    if ($domains -eq $NULL) { return }

    $vmAssignment = Get-Assignment $domains

    $userAssignment = @{}
    $vmAssignment | ?{$_.AssignmentType -eq "User"} | %{$userAssignment[$_.AssignedTo] = $_}
    
    foreach($entry in $users)
    {
        $vmName = $NULL
        $vmHost = $NULL
        
        if (($showAssigned) -AND ($userAssignment[$entry] -ne $NULL))
        {
            $vmName = ($userAssignment[$entry]).VM
            $vmHost = ($userAssignment[$entry]).Host
        }
        elseif ((-not $showUnAssigned) -OR ($userAssignment[$entry] -ne $NULL))
        {
            continue
        }
        
        $userEntry = New-Object PSObject
        $userEntry | Add-Member -MemberType NoteProperty -Name User -Value $entry
        $userEntry | Add-Member -MemberType NoteProperty -Name VM -Value $vmName
        $userEntry | Add-Member -MemberType NoteProperty -Name Host -Value $vmHost
        
        $userEntry
    }
}


$cbServiceStatus = (Get-Service tssdis -EA SilentlyContinue).Status
if ($cbServiceStatus -ne [System.ServiceProcess.ServiceControllerStatus]::Running)
{
    Write-Error "Connection broker role is not installed or the service is not running."
    exit 1
}

switch ($PsCmdlet.ParameterSetName)
{
    "Users"         {   
                        Get-UserAssignment $User -UserAssigned:$UserAssigned -UnAssigned:$UnAssigned
                        break
                    }

    "Pools"         {
                        $poolNames = Get-WmiObject -Namespace root\cimv2\terminalservices -Class Win32_TSRemoteDesktop | %{$_.Name}
                        $Pool | ?{$poolNames -notcontains $_} | %{Write-Error "Specified pool '$_' does not exist!"}
                        Get-PoolAssignment | ?{$Pool -contains $_.AssignedTo}
                        break
                    }

    "virtual machines"           {
                        $vmNames = Get-WmiObject -Namespace root\cimv2 -Query "Select * from Win32_SessionBrokerTarget where pluginname='VmResource'" | %{$_.TargetName}
                        $VirtualMachine | ?{$vmNames -notcontains $_} | %{Write-Error "Specified virtual machine '$_' does not exist!"}
                        Get-Assignment | ?{$VirtualMachine -contains $_.VM}
                        break
                    }

    "SimpleFilter"  {
                        if (-not $UserAssigned -AND -not $PoolAssigned -AND -not $UnAssigned)
                        {
                            $summary = @{User=0; Pool=0; Free=0}
                            Get-Assignment | %{ if ([string]::IsNullorEmpty($_.AssignmentType)) {$summary['Free']++} else {$summary[$_.AssignmentType]++}; $_}
                            Write-Host "`n`nSummary`n-------"
                            Write-Host "Virtual machines assigned to users : $($summary['User'])"
                            Write-Host "Virtual machines assigned to pools : $($summary['Pool'])"
                            Write-Host "Unassigned Virtual machines        : $($summary['Free'])"
                            Write-Host "Total                 : $(($summary.Values | Measure-Object -Sum).Sum)"
                        }
                        elseif (-not $UserAssigned -AND $PoolAssigned -AND -not $UnAssigned)
                        {
                            Get-PoolAssignment
                        }
                        else
                        {
                            Get-Assignment | ?{($UserAssigned -AND ($_.AssignmentType -eq "User")) `
                                                -OR ($PoolAssigned -AND ($_.AssignmentType -eq "Pool")) `
                                                -OR ($UnAssigned -AND ($_.AssignmentType -eq $NULL))}
                        }
                        break
                    }
}
Platforms
Windows Server 2008 R2 Yes
Windows Server 2008 No
Windows Server 2003 No
Windows 7 No
Windows Vista No
Windows XP No
Windows 2000 No
For online peer support, join The Official Scripting Guys Forum! To provide feedback or report bugs in sample scripts, please start a new discussion on the Discussions tab for this script.
Disclaimer The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
Be the first to create a discussion.