Citrix VDA: The trust relationship between this workstation and the primary domain failed

Citrix VDA: The trust relationship between this workstation and the primary domain failed

September 20, 2019 2 By Amir Joseph Sayes

The trust relationship between this workstation and the primary domain failed

If you get this error for non-persistent RDSH/VDI provisioned using PVS, it could well be that there is a conflict in managing “machine account password” on your computer objects in AD between PVS and Netlogon. 

Machine account password for non-persistent machines provisioned with PVS should be only managed via PVS.

First things first

In a scenario when you have hundreds of machines; proactively catch and fix machines can come handy.

First, we need to make sure Netlogon service on the target machine is not negotiating machine passwords. This can be done by the Group Policy

Computer Configuration\Windows Settings\Security Settings\Local Policies\Security Options\Domain member: Disable machine account password changes – Enabled. 

Now we need to make sure PVS side is configured properly. You will also need to shutdown affected machines and reset their computer account as explained in this Citrix article.

Troubleshoot faster with PowerShell

Luckily, we can interrogate the event logs across all non-persistent machines and proactively find out which ones are going to lose trust with the domain.

Below I list the Event IDs that I look for and what they mean

Event ID






“The system successfully changed its password on the domain controller <Domain Controller Name>



This is a symptom of the problem. PVS is not managing the account password and Netlogon service is stepping in and changing the password.


Unable to negotiate new machine password



PVS is trying to change the password but failing. The password that the PVS is injecting in the target device is not in sync with the one AD has.


Updating machine account password – Client Service



This the the expected behavior when PVS is configured properly.


New machine account password negotiated – Client Service



PVS injects the machine identity (name and password) upon boot, then while the machine is running, PVS software can negotiate a new password on a set intervals. Once negotiated successfully, PVS keeps a record of the new password so it can be injected the next time the target device reboots.

If another service e.g. Netlogon negotiated a new password with Active Directory, PVS will not know about this change and will inject an old password when the target device is rebooted.

To discover which service is changing the password, a script can run across the all target devices to match the password negotiation time with the lastpasswordset value in AD for each computer object.

I use Invoke-parallel to “fan” the script across all machines. You will need to download and import the module as shown below

#Get a list of all targets in your site 
$ListOfMachines = Get-BrokerDesktop -AdminAddress <#Replace with Delivery Controller name#> -MaxRecordCount 99999 | select machinename 
#import Invoke Parallel function
Import-Module Invoke-Parallel.ps1
#Define arrays to store results 
$Results = @() 
$ADPasswordTime = @() 
$EventLogs = @()
$Results = $ListOfMachines | Invoke-Parallel -ImportModules -ImportVariables -ScriptBlock { 
    $machinename = ($_.machinename -split "\\")[1] 
    #Get the time/date of the last password change for the machine from AD.
    $ADPasswordTime = Get-ADComputer -Identity $machinename -properties Name, passwordLastSet | select name, passwordLastSet 
        try { 
            $EventLogs = Invoke-Command -ComputerName $machinename -ErrorAction Stop { 
                    #Look for the latest event from Netlogon (5823) and BNDevice (any) and create an abject for each 
                    $System_res = Get-EventLog -LogName system -Source netlogon -Newest 1 -InstanceId 5823 -ErrorAction SilentlyContinue                 
                    $App_res = Get-EventLog -LogName Application -Source BNDevice -Newest 1 -ErrorAction SilentlyContinue                 
                        New-Object PSObject -Property @{ 
                        "NetLogonEventTime" = $System_res.TimeGenerated 
                        "NetLogonEventID" = $System_res.InstanceId 
                        "NetLogonEventMsg" = $System_res.Message 
                        "BNDeviceEventTime" = $App_res.TimeGenerated 
                        "BNDeviceEventID" = $App_res.InstanceId 
                        "BNDeviceEventMsg" = $App_res.Message 
        catch {$_ } 
                New-Object PSObject -Property @{ 
                "ComputerName" = $ 
                "ADLastPasswordSet" = $ADPasswordTime.passwordLastSet 
                "NetLogonEventTime" = $EventLogs.NetLogonEventTime 
                "NetLogonEventID" = $EventLogs.NetLogonEventID 
                "NetLogonEventMsg" = $($EventLogs.NetLogonEventMsg) 
                "BNDeviceEventTime" = $EventLogs.BNDeviceEventTime 
                "BNDeviceEventID" = $EventLogs.BNDeviceEventID 
                "BNDeviceEventMsg" = $EventLogs.BNDeviceEventMsg 
$Results | Format-Table -AutoSize

Example of results – in this example we can see that the password negotiation was sucessful and was initiated by PVS service (BNDevice). We can also see that the timestamp of the password change in Active Directory corresponds to the event on the target device.

2019-09-20 17_09_00-Capture

Monitor and proactively act with PowerShell!

The following script would try and remotely connect to a machine and check the secure channel between the machine and the domain. if the machine is not contactable, that could be an indication of a failure in trust relationship.

The script also checks if the machine is already in maintenance mode or not

#Get a list of all targets in your site
$ListOfMachines = Get-BrokerDesktop -AdminAddress <#Replace with Delivery Controller name#> -MaxRecordCount 99999 | select machinename, InMaintenanceMode
#import Invoke Parallel function
Import-Module Invoke-Parallel.ps1
$ListOfMachines | Invoke-Parallel -ImportModules -ImportVariables -RunspaceTimeout 15 -ScriptBlock {
    $machinename = ($_.machinename -split "\\")[1]
    $InMaintenanceMode = $_.InMaintenanceMode
        try {
            $PSO = Invoke-Command -ComputerName $machinename -ErrorAction Stop {
                if (Test-ComputerSecureChannel) {$relationstatus= "True"}
                    New-Object PSObject -Property @{
                        "ServerName" = $env:COMPUTERNAME
                        "RelationshipStatus" = $relationstatus
            } -ArgumentList $regpath1, $NameValue
            $PSO | Add-Member -MemberType NoteProperty -Name "InMaintenanceMode" -Value "$InMaintenanceMode"
        catch {
            New-Object PSObject -Property @{
                "ServerName" = $machinename
                "RelationshipStatus" = "Not contactable"
                "InMaintenanceMode" = $InMaintenanceMode

Example of the output: 

2019-09-20 18_07_08-Capture3