dsccommunity / xRemoteDesktopSessionHost

This module contains DSC resources for the management and configuration of Microsoft Remote Desktop Session Host (RDSH).
MIT License
36 stars 47 forks source link

xRDSessionDeployment Results in "You cannot call a method on a null-valued expression." #39

Closed mjcarrabine closed 6 years ago

mjcarrabine commented 6 years ago

When I try to deploy the xRDSessionDeployment resource on a new Windows Server 2016 machine, I am getting this error message:

"Message": "The PowerShell DSC resource \u0027[xRDSessionDeployment]Deployment\u0027 with SourceInfo \u0027::184::3::xRDSessionDeployment\u0027 threw one or more non-terminating errors while running the Test-TargetResource functionality. These errors are logged to the ETW channel called Microsoft-Windows-DSC/Operational. Refer to this channel for more details.", "Data": { }, "InnerException": { "ErrorRecord": "You cannot call a method on a null-valued expression.",

In #24 Fix Issue where DSC configuration gets into a reboot loop, line 72

(Get-TargetResource @PSBoundParameters).SessionHost -ieq $SessionHost

was changed to

# We need to perform the following check case insensitive because in some
# cases the SessionHost of Get-TargetResource is uppercase while the
# $sessionHost parameter is lowercase causing a reboot loop to happen.
(Get-TargetResource @PSBoundParameters).SessionHost.ToLower() -ieq $SessionHost.ToLower()

If New-RDSessionDeployment has not yet been run, then (Get-TargetResource @PSBoundParameters).SessionHost is null and calling .ToLower() results in the exception.

On a related note, -ieq is already case-insensitive so is .ToLower() needed here? Unit tests would help verify whether #24 is resolving the issue mentioned in the code comments.

johlju commented 6 years ago

Both -ieq and -eq are case insensitive, so doesn't understand the need to make the strings lower-case. Looking at the initial reported issues it feels to me that this had to be something else. 🤔

Agree that there should be a unit test to test this!

Labeling this as a bug and help wanted so anyone in the community can run with this.

danielboth commented 6 years ago

Hi @mjcarrabine, can you share the configuration you are using that triggers this error please? I feel that xRDSessionDeployment needs a proper redesign anyway (as is discussed in #21 as well). So if I get some spare time I'll be on that. In the mean time, I'm running this in production without any errors, so I'm wondering what is triggering the issues on your side.

mjcarrabine commented 6 years ago

@danielboth ,

xRDSessionDeployment works in its current version as long as New-RDSessionDeployment has been successfully run prior to applying the DSC configuration.

In Get-TargetResource, this returns a null SessionHost if New-RDSessionDeployment has not yet been run. This is okay because the errors are being handled.

$Deployed = Get-RDServer -ErrorAction SilentlyContinue
        @{
        "SessionHost" = $Deployed | Where-Object Roles -contains "RDS-RD-SERVER" | ForEach-Object Server;
        "ConnectionBroker" = $Deployed | Where-Object Roles -contains "RDS-CONNECTION-BROKER" | ForEach-Object Server;
        "WebAccessServer" = $Deployed | Where-Object Roles -contains "RDS-WEB-ACCESS" | ForEach-Object Server;
        }

The issue is that Test-TargetResource is successfully calling Get-TargetResource, but then failing on SessionHost.ToLower() because .SessionHost is null. This unhandled exception results in Set-TargetResource (and New-RDSessionDeployment) never being called on a fresh server install.

As soon as New-RDSessionDeployment is run successfully, everything is fine because .SessionHost is no longer null.

On a 2016-Datacenter image in Azure, this Config.ps1 file:

Configuration Config {

    Import-DscResource -ModuleName xRemoteDesktopSessionHost

    Node DEV_RDS01 {    

    xRDSessionDeployment Deployment{
    SessionHost = "DEV-RDS01.mydomain.com"
    ConnectionBroker = "DEV-RDS1.mydomain.com"
    WebAccessServer = "DEV-RDS01.mydomain.com"
    }
    }   
}

Results in this error:

{
    "Exception":  {
                      "Message":  "The PowerShell DSC resource \u0027[xRDSessionDeployment]Deployment\u0027 with SourceInfo \u0027::43::3::xRDSessionDeployment\u0027 threw one or more non-terminating errors while running the Test-TargetResource functionality. These errors are logged to the ETW channel called Microsoft-Windows-DSC/Operational. Refer to this channel for more details.",
                      "Data":  {

                               },
                      "InnerException":  {
                                             "ErrorRecord":  "You cannot call a method on a null-valued expression.",
                                             "WasThrownFromThrowStatement":  false,
                                             "Message":  "You cannot call a method on a null-valued expression.",
                                             "Data":  "System.Collections.ListDictionaryInternal",
                                             "InnerException":  null,
                                             "TargetSite":  "System.Object CallSite.Target(System.Runtime.CompilerServices.Closure, System.Runtime.CompilerServices.CallSite, System.Object)",
                                             "StackTrace":  "   at CallSite.Target(Closure , CallSite , Object )\r\n   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)\r\n   at System.Management.Automation.Interpreter.DynamicInstruction`2.Run(InterpretedFrame frame)\r\n   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)",
                                             "HelpLink":  null,
                                             "Source":  "Anonymously Hosted DynamicMethods Assembly",
                                             "HResult":  -2146233087
                                         },
                      "TargetSite":  null,
                      "StackTrace":  null,
                      "HelpLink":  null,
                      "Source":  null,
                      "HResult":  -2146233079
                  },
    "TargetObject":  null,
    "CategoryInfo":  {
                         "Category":  7,
                         "Activity":  "",
                         "Reason":  "InvalidOperationException",
                         "TargetName":  "",
                         "TargetType":  ""
                     },
    "FullyQualifiedErrorId":  "NonTerminatingErrorFromProvider",
    "ErrorDetails":  null,
    "InvocationInfo":  null,
    "ScriptStackTrace":  null,
    "PipelineIterationInfo":  [

                              ]
}

Or, to be a little closer to the end to end example in the readme, this config also produces the above error.

Configuration Config{

    Import-DscResource -ModuleName xRemoteDesktopSessionHost

    Node DEV_RDS01 {    

        WindowsFeature Remote-Desktop-Services
        {
            Ensure = "Present"
            Name = "Remote-Desktop-Services"
        }

        WindowsFeature RDS-RD-Server
        {
            Ensure = "Present"
            Name = "RDS-RD-Server"
        }

        xRDSessionDeployment Deployment{
        SessionHost = "DEV-RDS04-04.mydomain.com"
        ConnectionBroker = "DEV-RDS04-04.mydomain.com"
        WebAccessServer = "DEV-RDS04-04.mydomain.com"
        DependsOn = "[WindowsFeature]Remote-Desktop-Services", "[WindowsFeature]RDS-RD-Server"
        }
    }

}
danielboth commented 6 years ago

Thanks for the detailed reply @mjcarrabine ! I think the .toLower() part was done in error in a previous PR, so I have reverted that in PR #42. Also, I changed the logic to actually compare the CollectionBroker name instead of the SessionHost, since SessionHosts can be added & removed from a deployment. I think this will fix your issue as well.