Remote Desktop Connection Manager is a must-have tool. However, it too easily falls out of date.  Depending on your environment, you might be spinning up new machines regularly, especially if you’re in a virtualized environment.  Here’s a quick way to see if your .RDG file and your AD server agree.

At the core, it’s pretty simple:

  • RDG files are XML
  • The XPath to a server’s name is “//server/name”, then take the InnerText.
  • The <displayname /> element, while nice to look at, means very little.

===

function Test-RDGFile
{
    #region header

    <#
    .synopsis
    Validates an RDCManager config file (.RDG)

    .Description
    With change comes opportunity.  RDG files are constantly being rendered obsolete.  Here's a way to see what's missing, and what's outdated.  Requires domain trust with AD server in target domains.

    .parameter Path
    Path to RDG file.  Required.

    .Parameter ADDomain
    List of Active Directory domains to check.  If not set, will pull from all AD domains in the RDG file.

    .parameter OutputPath
    Path to *folder* to store output files.  Defaults to "$home\$basename (datestamp)".

.parameter Filter
Value to Get-ADComputer-Filter –Filter parameter. Defaults to '*'. Output files consiste of three types: suspect.txt - server is in RDG, but unable to check, usually because of failed domain trust. missing.txt - server is not in RDG, but is in Get-ADComputer -server outdated.txt - server is in RDG, but not in Get-ADComputer -server #> param ( [parameter(Mandatory=$true)][string]$Path = $null, [string[]]$ADDomain = @(), [string]$OutputPath = $null,
[string]$Filter = '*' ); #endregion #region setup # used for messaging $scriptName = (&{$MyInvocation}).ScriptName; $baseName = Split-Path -Path $scriptName -Leaf ######################################## # import the ActiveDirectory module if needed if (!(Get-Command -Name Get-ADComputer -ErrorAction SilentlyContinue)) { $local:oldProgressPreference = $ProgressPreference; $ProgressPreference = 'SilentlyContinue'; Import-Module ServerManager; Add-WindowsFeature RSAT-AD-Powershell; $ProgressPreference = $local:oldProgressPreference; } # if (!(Get-Command -Name Get-ADComputer -ErrorAction SilentlyContinue)) ######################################## # input validation if (!(Test-Path -Path $Path)) { Write-Warning "$basename -Path '$Path' not found. Exiting."; return; } # if (!(Test-Path -Path $Path)) # parse input file phase 1: as XML Write-progress $basename "Parsing $Path"; if (!($xml = (Get-Content -Path $Path) -as [xml])) { Write-Warning "$basename -Path '$Path' cannot be parsed as XML. Exiting."; return; } # if (!($xml = (Get-Content -Path $Path) -as [xml])) # parse input file phase 2: extract server names $rdgHosts = $xml.selectNodes("//server/name") | % { $_.InnerText; } | Group-Object | % { # needed in case we have multiple entries of the same hostname in the file $_.Name; } | Sort-Object # $xml.selectNodes("//server/name") | # check all ADDomains if none specified. if (!$ADDomain) { $ADDomain = $rdgHosts -replace '^[^\.]*\.' | Group-Object | % { $_.Name; } | Sort-Object # $rdgDomains = $rdgHosts -replace '^[^\.]*\.' | } # if (!$ADDomain) ######################################## # store output files here if (!$OutputPath) { $OutputPath = "$home\$($baseName -replace '\.[^\.]+$') ($(Get-Date -Format 'yyyy-MM-dd HHmmss'))"; } # if (!$OutputPath) if (!(Test-Path -Path $OutputPath)) { mkdir $OutputPath | Out-Null; } # if (!(Test-Path -Path $OutputPath)) #endregion #region do the real work foreach ($_adDomain in $ADDomain) { Write-Progress $baseName "Checking -ADDomain $_adDomain"; if ($rdgDomainHosts = $rdgHosts | ? { $_ -match "$_adDomain$" }) { try { if (!($adDomainHosts = Get-ADComputer -Filter $Filter -Server $_adDomain -ErrorAction SilentlyContinue | % { $_.DistinguishedName -replace ',DC=', '.' -replace ',[^\.]*\.', '.' -replace '.*='; } | Sort-Object )) { Write-Warning "$basename -ADDomain '$_adDomain' Unable to get server list. Skipping."; $rdgDomainHosts | Out-File -Append -FilePath "$OutputPath\suspect.txt" continue; } # if (!($adComputer = Get-ADComputer -Filter $Filter -Server $_adDomain ... } # try catch { Write-Warning "Get-ADComputer -Filter $Filter -server $_addomain failed with '$($_.exception.message)'"; } # catch if ($compareResults = Compare-Object -ReferenceObject $rdgDomainHosts -DifferenceObject $adDomainHosts) { $compareResults | ? { $_.SideIndicator -eq '=>' } | % { $_.InputObject } | Out-File -Append -FilePath "$OutputPath\missing.txt"; $compareResults | ? { $_.SideIndicator -eq '<=' } | % { $_.InputObject } | Out-File -Append -FilePath "$OutputPath\outdated.txt"; } # if ($compareResults = Compare-Object -ReferenceObject $rdgDomainHosts ... } # if ($rdgDomainHosts = $rdgHosts | ? { $_ -match "$_adDomain$" }) else { try { # have to build up the hostnames because DNSHostnames are often infra.lync.com... if ($adDomainHosts = Get-ADComputer -Filter $Filter -Server $_adDomain -ErrorAction SilentlyContinue | % { $_.DistinguishedName -replace ',DC=', '.' -replace ',[^\.]*\.', '.' -replace '.*='; } | Sort-Object ) { $adDomainHosts | Out-File -Append -FilePath "$OutputPath\missing.txt" continue; } # if ($adComputer = Get-ADComputer -Filter $Filter -Server $_adDomain ... else { Write-Warning "$basename -ADDomain '$_adDomain' Unable to get server list. Skipping."; continue; } # if ($adComputer = Get-ADComputer -Filter $Filter -Server $_adDomain ... } # try catch { Write-Warning "Get-ADComputer -Filter * -server $_addomain failed with '$($_.exception.message)'"; } # catch } # if ($rdgDomainHosts = $rdgHosts | ? { $_ -match "$_adDomain$" }) } # foreach ($_adDomain in $ADDomain) # output results Get-ChildItem $OutputPath | %{ $_.Fullname; } # Get-ChildItem $OutputPath | #endregion }