Author Posts

August 10, 2018 at 10:00 am

Hello,
I've been struggling two weeks with the DSC Pull Server configuration. I had no success configuring an http/https pull server neither with ConfigurationId approach nor using ConfigurationNames
Smb Pull server was the only server configuration that worked for me, but I aspire to https.
I've ruled out some common mistakes I've read in other powershell.org posts,  documentation and forums:

  • Checking Remoting is enabled
  • Avoid using self-signed certificates. (I used IIS Management Console and a Root CA certificate to issue an appropriate server certificate)
  • Check Windows Management Framework (WFM) versions for node-server incompatibilities
  • Checking .Net Framework 4.5.2 or above is installed on Server 2012 for WMF 5.1 to work well.
  • Verify Web Service either using Verify-DSCPullServer function or pasting url https://[pullserver]:8080/PSDSCPullServer.svc in the browser, then checking there aren't SSL warnings and certificate is valid

The following are the machine's configurations for my server and nodes:
Server 2012 + WMF 5.1
Name Value
—- —–
PSVersion 5.1.14409.1012
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14409.1012
CLRVersion 4.0.30319.36440
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

Client Windows 10 Pro 1709
Name Value
—- —–
PSVersion 5.1.16299.547
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.16299.547
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

Configuration Id Approach

  1. Server Configuration
    I'm using xPSDesiredConfiguration 8.4.0.0 and xDscWebService Resource to configure the Server, this way

    configuration HTTPSPullServer
    {
    
        param
        (
            [string[]]$NodeName = 'localhost',
    
            [ValidateNotNullOrEmpty()]
            [string] $certificateThumbPrint
        )
    
        # Modules must exist on target pull server
        Import-DSCResource -ModuleName xPSDesiredStateConfiguration
    
        Node $NodeName
        {
            WindowsFeature DSCServiceFeature
            {
                Ensure = "Present"
                Name   = "DSC-Service"
            }
    
            #IIS Console
            WindowsFeature IISConsole {
                Ensure = "Present"
                Name   = "Web-Mgmt-Console"
            }
    
            xDscWebService PSDSCPullServer
            {
                Ensure                  = "Present"
                EndpointName            = "PSDSCPullServer"
                Port                    = 8080
                PhysicalPath            = "$env:SystemDrive\inetpub\wwwroot\PSDSCPullServer"
                CertificateThumbPrint   = $certificateThumbPrint
                ModulePath              = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Modules"
                ConfigurationPath       = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration"
                State                   = "Started"
                DependsOn               = "[WindowsFeature]DSCServiceFeature"
                UseSecurityBestPractices = $true
            }
        }
    }
    
    HTTPSPullServer -NodeName vmdt01 -certificateThumbPrint '712FCD316ED524F785186DD144DD445A47CB66A5' -OutputPath E:\DSC\HTTPS\
    
    Start-DscConfiguration -ComputerName vmdt01 -Path E:\DSC\HTTPS -Verbose -Wait -Force
    

    (I've tried different combination on UseSecurityBestPractices and DisableSecurityBestPractices properties without success)

  2. Clients LCM Configuration (Using ConfigurationId approach)

    [DSCLocalConfigurationManager()]
    Configuration PullW10ClientsConfigId 
    {
       param
        (
                [Parameter(Mandatory=$true)]
                [string[]]$ComputerName,
    
                [Parameter(Mandatory=$true)]
                [string]$guid
        )
    
    	Node $ComputerName {
    	
    		Settings {
    
    			RefreshMode = 'Pull'
    		        RefreshFrequencyMins = 30
                            ConfigurationMode = 'ApplyAndAutoCorrect'
                            RebootNodeIfNeeded = $true
    			ConfigurationID = $guid
            }
    
                ConfigurationRepositoryWeb DSCHTTPS {
                    ServerURL = 'https://vmdt01.dggh.es:8080/PSDSCPullServer.svc'
                    CertificateID = '712FCD316ED524F785186DD144DD445A47CB66A5'
                }
    
                ReportServerWeb ReportServer {
                    ServerURL = 'https://vmdt01.dggh.es:8080/PSDSCPullServer.svc'
                    CertificateID = '712FCD316ED524F785186DD144DD445A47CB66A5'
                    AllowUnsecureConnection = $True
    
                }
    
    	}
    }
  3. Rename MOF files to match configurationId and apply
    New-DSCChecsum
  4. When I try to do
    Update-StartDscConfiguration -Computer vcontab1-w10 -Wait -Verbose

    I get the following errors and stack trace on the event viewer:


    Trabajo {B3C00709-9C7A-11E8-ACE3-000C2991FEC5}:
    Comando Do-DscAction de WebDownloadManager para configuración e2665f67-3a61-4989-9870-616a065298d6, resultado de llamada GET:
    + FullyQualifiedErrorId : WebDownloadManagerGetActionFailed
    + CategoryInfo : InvalidResult: (:) [], InvalidOperationException
    + ExceptionMessage : No se pudo obtener la acción del servidor https://vmdt01.dggh.es:8080/PSDSCPullServer.svc/Action(ConfigurationId='e2665f67-3a61-4989-9870-616a065298d6')/GetAction.
    + InnerException : System.AggregateException: Se han producido uno o varios errores. ---> System.Net.Http.HttpRequestException: Error al enviar la solicitud. ---> System.Net.WebException: Se ha terminado la conexión: Error inesperado de envío. ---> System.IO.IOException: No se puede escribir datos de en la conexión de transporte: Se ha forzado la interrupción de una conexión existente por el host remoto. ---> System.Net.Sockets.SocketException: Se ha forzado la interrupción de una conexión existente por el host remoto
    en System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
    en System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
    en System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
    en System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
    --- Fin del seguimiento de la pila de la excepción interna ---
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
    en Microsoft.PowerShell.DesiredStateConfiguration.Commands.GetDscActionCommand.IssueRequest(IHttpClient client, String subLink, String& responseStatus, ErrorRecord& errorRecord)
    ---> (Nº de excepción interna 0) System.Net.Http.HttpRequestException: Error al enviar la solicitud. ---> System.Net.WebException: Se ha terminado la conexión: Error inesperado de envío. ---> System.IO.IOException: No se puede escribir datos de en la conexión de transporte: Se ha forzado la interrupción de una conexión existente por el host remoto. ---> System.Net.Sockets.SocketException: Se ha forzado la interrupción de una conexión existente por el host remoto
    en System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
    en System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
    en System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
    en System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
    --- Fin del seguimiento de la pila de la excepción interna ---< ---

    Where error in English are:

    System.Net.Http.HttpRequestException: An error occurred while sending the request
    System.Net.WebException: The underlying connection was closed: unexpected error
    System.IO.IOException: Cannot write data to the transport connection: The remote host forced the interruption of an exixting connection

Whilst if I use Configuration Names approach I get the error earlier, during the node registration.

Configuration Name Approach

  1. Server Configuration

    configuration HTTPSPullServer
    {
        param
        (
            [string[]]$NodeName = 'localhost',
    
            [ValidateNotNullOrEmpty()]
            [string] $certificateThumbPrint,
    
            [Parameter(HelpMessage='This should be a string with enough entropy (randomness) to protect the registration of clients to the pull server.  We will use new GUID by default.')]
            [ValidateNotNullOrEmpty()]
            [string] $RegistrationKey   # A guid that clients use to initiate conversation with pull server
        )
    
        # Modules must exist on target pull server
        Import-DSCResource -ModuleName xPSDesiredStateConfiguration
    
        Node $NodeName
        {
            WindowsFeature DSCServiceFeature
            {
                Ensure = "Present"
                Name   = "DSC-Service"
            }
    
            #Consola de IIS
            WindowsFeature IISConsole {
                Ensure = "Present"
                Name   = "Web-Mgmt-Console"
                DependsOn = '[File]RegistrationKeyFile'
            }
    
            xDscWebService PSDSCPullServer
            {
                Ensure                  = "Present"
                EndpointName            = "PSDSCPullServer"
                Port                    = 8080
                PhysicalPath            = "$env:SystemDrive\inetpub\wwwroot\PSDSCPullServer"
                CertificateThumbPrint   = $certificateThumbPrint
                ModulePath              = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Modules"
                ConfigurationPath       = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration"
                RegistrationKeyPath      = "$env:PROGRAMFILES\WindowsPowerShell\DscService"
                State                   = "Started"
                DependsOn               = "[WindowsFeature]DSCServiceFeature"
                UseSecurityBestPractices = $true          
            }
    
            File RegistrationKeyFile
            {
                Ensure          = 'Present'
                Type            = 'File'
                DestinationPath = "$env:ProgramFiles\WindowsPowerShell\DscService\RegistrationKeys.txt"
                Contents        = $RegistrationKey
            }
        }
    }
    
    # Generate MOF
    HTTPSPullServer -NodeName vmdt01 -certificateThumbPrint '9F00EDBDFB791C7AAD9200E9E0BA8FD59684B419' -RegistrationKey 'e2665f67-3a61-4989-9870-616a065298d6' -OutputPath E:\DSC\HTTPS\
    
    Start-DscConfiguration -ComputerName vmdt01 -Path E:\DSC\HTTPS -Verbose -Wait -Force
  2. Client LCM (Configuration Name Approach)

    [DSCLocalConfigurationManager()]
    Configuration PullW10ClientsConfigNames 
    {
       param
        (
            [ValidateNotNullOrEmpty()]
            [string] $NodeName = 'localhost',
    
            [ValidateNotNullOrEmpty()]
            [string] $RegistrationKey #same as the one used to setup pull server in previous configuration
    
        )
    	Node $NodeName {
    	
    		Settings {
    
    			RefreshMode = 'Pull'
    		        RefreshFrequencyMins = 30
                            ConfigurationMode = 'ApplyAndAutoCorrect'
                            RebootNodeIfNeeded = $true
            }
                
                ConfigurationRepositoryWeb DSCHTTPS {
                    ServerURL = 'https://vmdt01.dggh.es:8080/PSDSCPullServer.svc'
                    RegistrationKey = $RegistrationKey
                    ConfigurationNames = @('w10client')
                    AllowUnsecureConnection = $true
                }
    
                ReportServerWeb ReportServer {
                    ServerURL = 'https://vmdt01.dggh.es:8080/PSDSCPullServer.svc'
                    CertificateID = '712FCD316ED524F785186DD144DD445A47CB66A5'
                    AllowUnsecureConnection = $True
                }
    	}
    }
    
    # Create the Computer.Meta.Mof in folder
    PullW10ClientsConfigNames -NodeName vcontab1-w10 -RegistrationKey 'e2665f67-3a61-4989-9870-616a065298d6' -OutputPath E:\DSC\HTTPS
    
    Set-DscLocalConfigurationManager -ComputerName vcontab1-w10 -Path E:\DSC\HTTPS -Verbose

    At this point, I get an error saying the DSC Agent with an specific AgentId could not be registered on the server.

    Here's the event log throwing the same errors than in the ConfigurationId approach


    Trabajo {0EE9AD70-9C80-11E8-ACE3-000C2991FEC5} :
    el cliente HTTP 3A1CC07C-9BC1-11E8-ACE3-000C2991FEC5 no pudo registrar el agente de Dsc:
    + FullyQualifiedErrorId : RegisterDscAgentCommandFailed
    + CategoryInfo : InvalidResult: (:) [], InvalidOperationException
    + ExceptionMessage : No se pudo registrar el agente de Dsc con AgentId 3A1CC07C-9BC1-11E8-ACE3-000C2991FEC5 con el servidor https://vmdt01.dggh.es:8080/PSDSCPullServer.svc/Nodes(AgentId='3A1CC07C-9BC1-11E8-ACE3-000C2991FEC5').
    + InnerException : System.AggregateException: Se han producido uno o varios errores. ---> System.Net.Http.HttpRequestException: Error al enviar la solicitud. ---> System.Net.WebException: Se ha terminado la conexión: Error inesperado de envío. ---> System.IO.IOException: No se puede escribir datos de en la conexión de transporte: Se ha forzado la interrupción de una conexión existente por el host remoto. ---> System.Net.Sockets.SocketException: Se ha forzado la interrupción de una conexión existente por el host remoto
    en System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
    en System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
    en System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
    en System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
    --- Fin del seguimiento de la pila de la excepción interna ---
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
    en Microsoft.PowerShell.DesiredStateConfiguration.Commands.RegisterDscAgentCommand.IssueRequest(DotNetHttpClient client, String subLink, ErrorRecord& errorRecord)
    ---> (Nº de excepción interna 0) System.Net.Http.HttpRequestException: Error al enviar la solicitud. ---> System.Net.WebException: Se ha terminado la conexión: Error inesperado de envío. ---> System.IO.IOException: No se puede escribir datos de en la conexión de transporte: Se ha forzado la interrupción de una conexión existente por el host remoto. ---> System.Net.Sockets.SocketException: Se ha forzado la interrupción de una conexión existente por el host remoto
    en System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
    en System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
    en System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
    --- Fin del seguimiento de la pila de la excepción interna ---
    en System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
    en System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
    --- Fin del seguimiento de la pila de la excepción interna ---< ---

May somebody in the Powershell Community or the DevOps Collective Inc. give me a hint of where could be the matter?
Is there an issue with the security protocols? Might be something related to Server 2012 OS, which was the first version that supported DSC? I'm lost here.

August 19, 2018 at 11:32 am

Use Wireshark on the client to monitor the negotiation of the session.  The errors look to me like they could be due to TLS negotiation errors.  e.g. the server is expecting TLS 1.2 or higher and the client is requesting 1.0 or lower.

I've not done a lot with DSC but I'm seeing a few .NET applications failing to connect to some servers now.  Fixing it usually involves updating either the client software (which has been built using a later version of .NET framework) or upgrading the .NET framework itself.

Googling some articles on PowerShell and TLS it looks like it may default to TLS 1.0.

On my fully patched Windows 10 an Invoke-WebRequest to PowerShell.org fails.  Wireshark shows it attempts to use TLS 1.0:

TLSv1 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 113
Handshake Protocol: Client Hello

This is immediately follow by the site sending a RST, closing the connection.

You can force PowerShell use to a newer version with

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

The Invoke-WebRequest to PowerShell.org then succeeds:

TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 197
Handshake Protocol: Client Hello

TLSv1.2 Record Layer: Handshake Protocol: Server Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 89
Handshake Protocol: Server Hello

I assume setting SecurityProtocol type will be honoured by DSC but I don't have a set up to test it on.