Author Posts

August 6, 2017 at 7:16 am

I've been trying to test and evaluate different methods of applying multiple configurations to a node, then audit them long term. I'm aware of different options including partial configurations, dot-sourcing, and composite configurations. I created 2 unique dsc configurations for a node, one installed sql, one installed the docker service, and applied them successfully. Perhaps not real world realistic, but just a test of dot-sourcing. I then wanted to audit the node for both groups of changes. I found that test-dscconfiguration only reads one .mof, the current.mof on the node (I know about -referenceconfiguration, but getting an audit of multiple applied configs would still require multiple passes). I wanted to both perform multiple, separate configurations, without having to combine everything into one large, monolithic configuration script, and also get be able to run one test-dscconfiguration command and return one audit result, without having to combine multiple test-dscconfiguration commands using -referenceconfiguration. I was unable to get partial-configurations to work, so I turned to dot-sourcing the separate dsc scripts within one, and removing the configuration and node separations in the lower level scripts. I found that the separate scripts worked fine standalone, but the sql script throws an error when dot-sourced.

The docker service install script works fine, as standalone and in the dot-sourced script. The sql install script works fine standalone, but throws an error when dot-sourced.

DSC script containing 2 dot-sourced scripts

#DSC_install_docker-sql-test.ps1

$Nodelist = get-content dsc_install_docker_and_SQL-nodelist.txt 
$Config = 'DSC_install_docker_and_SQL_test'

$dockersqlnodeconfigdata =
@{
    AllNodes = @(
        @{
            NodeName 			= '*'
            PSDscAllowPlainTextPassword = $true
            PSDscAllowDomainUser	= $true 
            DomainAdminCredential    = (Get-Credential -message "Enter a Domain Admin ID for the Server Node")              
         }
    )
}		

ForEach ($Node in $Nodelist) 
{

	Configuration DSC_install_docker_and_SQL_test
	{	
		Import-DscResource –ModuleName 'PSDesiredStateConfiguration'
		
		node $node 
			{ 
				. ./dsc_install_docker-dotsourced.ps1
				. ./dscconfig_sqlnodes_serial-dotsourced.ps1
			}
	}	
write-output ".mof file should be in: $config"
pause
DSC_install_docker_and_SQL_test -configurationdata $dockersqlnodeconfigdata -outputpath "c:\PROGRAM FILES\WindowsPowerShell\DscService\Configuration\$Config"
write-host "if you don't see the name of a .mof file here, one was not created"
pause #good place to pause to verify $node.mof and/or $node.meta.mof file creation.
}

foreach ($node in $nodelist)
{
	$cimsession = ''
    $cimsession = new-cimsession -credential $DomainAdminCredential -computername $Node
    Start-DSCConfiguration -cimsession $cimsession -Path "c:\PROGRAM FILES\WindowsPowerShell\DscService\Configuration\$Config" -wait -Verbose -force 
    $sleepseconds  = 20
	write-output "Sleeping $sleepseconds seconds before checking DSC Configuration Status...Please wait."
	start-sleep -seconds $sleepseconds
    Get-DscConfigurationstatus -CimSession $cimsession | select pscomputername,startdate,type,status,mode,numberofresources | format-table -autosize
    (test-dscconfiguration -detailed -cimsession $cimsession).resourcesindesiredstate | select pscomputername,ResourceID,InDesiredState | format-table -autosize
}     

DSC sql install script standalone

#DSCconfig_SQLNodes_serial.ps1

$Nodelist = get-content dscconfig_sqlnodelist.txt 
$Config = 'ConfigDSC_SQLNodes_Serial'
$mofconfigpath = "c:\PROGRAM FILES\WindowsPowerShell\DscService\Configuration\$Config"
$DomainAdminCredential = Get-Credential -username $env:userdomain\$env:username -message "Domain Administrator UserID and Password for module source, module destination, SQL source, and SQL install"
$SourceCredential = $DomainAdminCredential
$Module_Source = "\\se123456\dsc\module_storage"
$Module_Destination = "c$\program files\windowspowershell\modules"

get-cimsession | remove-cimsession
$cimsessions = new-cimsession -ComputerName $Nodelist -Credential $SQLInstallCredential 

get-smbmapping | Remove-SmbMapping -Force
$source_userid = $Sourcecredential.username
$source_password = $Sourcecredential.getnetworkcredential().password

new-smbmapping -remotepath $module_source -username $source_userid -password $source_password

$source_userid = ""
$source_password = ""

foreach ($Node in $Nodelist)
{
    $DestinationCredential = $DomainAdminCredential
    $destination_userid = $destinationCredential.UserName
	$destination_password = $destinationCredential.getnetworkcredential().password
	new-smbmapping -remotepath "\\$Node\$module_destination" -username $destination_userid -password $destination_password
    $destination_userid = ""
	$destination_password = ""
    
    if (-not (test-path "\\$Node\$module_destination\xSQLServer\7.1.0.0\")) 
    {
	    copy-item -path "$module_source\xSQLServer\7.1.0.0\" -destination "\\$Node\$module_destination\xSQLServer\" -Recurse -Force
    }
    if (-not (test-path "\\$Node\$module_destination\xPSDesiredStateConfiguration\")) 
    {
	    copy-item -path "$module_source\xPSDesiredStateConfiguration\" -destination "\\$Node\$module_destination\" -Recurse -Force
    }
    get-childitem "\\$Node\$module_destination\xSQLServer" | select fullname
	get-childitem "\\$Node\$module_destination\xPSDesiredStateConfiguration" | select fullname
}

$sqlnodeconfigdata = @{
    AllNodes = @(
        @{
            NodeName = '*'
            PSDscAllowPlainTextPassword = $true
            PSDscAllowDomainUser 	= $true
            SQLInstallCredential 	= $DomainAdminCredential
            SQLAdminCredential 		= (Get-Credential -username SA -message "Enter SA credential")
            SourceCredential 		= $DomainAdminCredential
          }
    )  
}

ForEach ($Node in $Nodelist) 
{
    $sqlnodeConfigData.AllNodes += @{
        NodeName = $Node
        }
}

configuration ConfigDSC_SQLNodes_Serial

{    
    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Import-DscResource -Name "xSQLServersetup" -ModuleName "xSQLServer" -ModuleVersion "7.1.0.0"
            
    Node $allnodes.nodename      	
    {     
        WindowsFeature DSC-Service 
        {
            Name    = "DSC-Service"
            Ensure  = "Present"
        }
        WindowsFeature RSAT 
        {
         	Name    = "RSAT"
         	Ensure  = "Present"
        }
        WindowsFeature NET-Framework-Core 
        {
         	Name    = "NET-Framework-Core"
         	Ensure  = "Present"
        }
#========================================================================================

        File xPSDesiredStateConfiguration_Copy 
        {
            Ensure              = "Present"  
            Type                = "Directory" 
            DestinationPath     = "C:\Program Files\WindowsPowerShell\Modules\xPSDesiredStateConfiguration" 
        } 
        File xSQLServer_Add 
        {
            Ensure          = "Present"  
            Type            = "Directory" 
            DestinationPath = "C:\Program Files\WindowsPowerShell\Modules\xSQLServer\7.1.0.0" 
        } 
#====================================================================        
        xSQLServerSetup  'InstallNamedInstance_IN01' 
        {
            DependsOn = "[File]xSQLServer_Add"
            InstanceName = 'IN01'
            Features = 'SQLENGINE,CONN,BC'
            SQLSYSADMINACCOUNTS = "DEVDOMAIN\Server_Local_Admins", "DEVDOMAIN\MSSQL_Admins"
            SetupCredential = $Node.SQLInstallCredential
            SECURITYMODE = "SQL"
            InstallSharedDir = 'F:\Program Files\Microsoft SQL Server'
            InstallSharedWOWDir = 'F:\Program Files (x86)\Microsoft SQL Server'
            InstanceDir = 'F:\Program Files\Microsoft SQL Server'
            InstallSQLDataDir = 'F:\Program Files\Microsoft SQL Server\MSSQL13.INST2016\MSSQL\Data'
            SourceCredential = $Node.SourceCredential
            SourcePath = "\\se123456\dsc\Sql2016x64Ent"
            UpdateEnabled = 'False'
            ForceReboot = $false
            BrowserSvcStartupType = 'Automatic'
            SAPwd = $Node.SQLAdminCredential
         }
    }

}
#================ Create .mof file for server/node ============================================
$sqlnodeconfigdata.allnodes
pause
ConfigDSC_SQLNodes_Serial -configurationdata $sqlnodeconfigdata -outputpath $mofconfigpath

foreach($Node in $Nodelist) 
{
    $cimsession = new-cimsession -ComputerName $Node -Credential $SQLInstallCredential
    Start-DSCConfiguration -cimsession $cimsession -Path $mofconfigpath -wait -Verbose -force
}
write-output "Sleeping for 10 seconds before checking DSC Configuration Status for $node..."
start-sleep -seconds 10

foreach($Node in $Nodelist) 
{
    Get-DscConfigurationstatus -CimSession $cimsession | select pscomputername,startdate,type,status,mode,numberofresources | format-table -autosize
    (test-dscconfiguration -detailed -computername $node).resourcesindesiredstate | select pscomputername,ResourceID,InDesiredState | format-table -autosize
    (test-dscconfiguration -detailed -computername $node).resourcesnotindesiredstate | select pscomputername,ResourceID,InDesiredState | format-table -autosize
}

DSC sql install script when dot-sourced in combined dsc script

#DSCconfig_SQLNodes_serial-dotsourced.ps1

$Nodelist = get-content dscconfig_sqlnodelist.txt 
$Config = 'ConfigDSC_SQLNodes_Serial'
$mofconfigpath = "c:\PROGRAM FILES\WindowsPowerShell\DscService\Configuration\$Config"
$DomainAdminCredential = Get-Credential -username $env:userdomain\$env:username -message "Domain Administrator UserID and Password for module source, module destination, SQL source, and SQL install"
$SourceCredential = $DomainAdminCredential
$Module_Source = "\\se123456\dsc\module_storage"
$Module_Destination = "c$\program files\windowspowershell\modules"

get-cimsession | remove-cimsession
$cimsessions = new-cimsession -ComputerName $Nodelist -Credential $SQLInstallCredential 

get-smbmapping | Remove-SmbMapping -Force
$source_userid = $Sourcecredential.username
$source_password = $Sourcecredential.getnetworkcredential().password

new-smbmapping -remotepath $module_source -username $source_userid -password $source_password

$source_userid = ""
$source_password = ""

foreach ($Node in $Nodelist)
{
    $DestinationCredential = $DomainAdminCredential
    $destination_userid = $destinationCredential.UserName
    $destination_password = $destinationCredential.getnetworkcredential().password
    new-smbmapping -remotepath "\\$Node\$module_destination" -username $destination_userid -password $destination_password
    $destination_userid = ""
    $destination_password = ""
    
    if (-not (test-path "\\$Node\$module_destination\xSQLServer\7.1.0.0\")) 
    {
	    copy-item -path "$module_source\xSQLServer\7.1.0.0\" -destination "\\$Node\$module_destination\xSQLServer\" -Recurse -Force
    }
    if (-not (test-path "\\$Node\$module_destination\xPSDesiredStateConfiguration\")) 
    {
	    copy-item -path "$module_source\xPSDesiredStateConfiguration\" -destination "\\$Node\$module_destination\" -Recurse -Force
    }
    get-childitem "\\$Node\$module_destination\xSQLServer" | select fullname
	get-childitem "\\$Node\$module_destination\xPSDesiredStateConfiguration" | select fullname
}

$sqlnodeconfigdata = @{
    AllNodes = @(
        @{
            NodeName = '*'
            PSDscAllowPlainTextPassword = $true
            PSDscAllowDomainUser 	= $true
            SQLInstallCredential 	= $DomainAdminCredential
            SQLAdminCredential 		= (Get-Credential -username SA -message "Enter SA credential")
            SourceCredential 		= $DomainAdminCredential
          }
    )  
}
ForEach ($Node in $Nodelist) 
{
    $sqlnodeConfigData.AllNodes += @{
        NodeName = $Node
        }
}

    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Import-DscResource -Name "xSQLServersetup" -ModuleName "xSQLServer" -ModuleVersion "7.1.0.0"          	
         
        WindowsFeature DSC-Service 
        {
            Name    = "DSC-Service"
            Ensure  = "Present"
        }
        WindowsFeature RSAT 
        {
         	Name    = "RSAT"
         	Ensure  = "Present"
        }
        WindowsFeature NET-Framework-Core 
        {
         	Name    = "NET-Framework-Core"
         	Ensure  = "Present"
        }
#========================================================================================

        File xPSDesiredStateConfiguration_Copy 
        {
            Ensure              = "Present"  
            Type                = "Directory" 
            DestinationPath     = "C:\Program Files\WindowsPowerShell\Modules\xPSDesiredStateConfiguration" 
        } 
        File xSQLServer_Add 
        {
            Ensure          = "Present"  
            Type            = "Directory" 
            DestinationPath = "C:\Program Files\WindowsPowerShell\Modules\xSQLServer\7.1.0.0" 
        } 
#====================================================================        
        xSQLServerSetup  'InstallNamedInstance_IN01' 
        {
            DependsOn = "[File]xSQLServer_Add"
            InstanceName = 'IN01'
            Features = 'SQLENGINE,CONN,BC'
            SQLSYSADMINACCOUNTS = "DEVDOMAIN\Server_Local_Admins", "DEVDOMAIN\MSSQL_Admins"
            SetupCredential = $Node.SQLInstallCredential
            SECURITYMODE = "SQL"
            InstallSharedDir = 'F:\Program Files\Microsoft SQL Server'
            InstallSharedWOWDir = 'F:\Program Files (x86)\Microsoft SQL Server'
            InstanceDir = 'F:\Program Files\Microsoft SQL Server'
            InstallSQLDataDir = 'F:\Program Files\Microsoft SQL Server\MSSQL13.INST2016\MSSQL\Data'
            SourceCredential = $Node.SourceCredential
            SourcePath = "\\se123456\dsc\Sql2016x64Ent"
            UpdateEnabled = 'False'
            ForceReboot = $false
            BrowserSvcStartupType = 'Automatic'
            SAPwd = $Node.SQLAdminCredential
        }
  

Error when running dsc sql script as dot-sourced

PS C:\Program Files\WindowsPowerShell\DscService\Configuration> .\dsc_install_docker-sql-test.ps1
PSDesiredStateConfiguration\node : The term 'xSQLServer\xSQLServerSetup' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the
path is correct and try again.
At C:\Program Files\WindowsPowerShell\DscService\Configuration\dsc_install_docker-sql-test.ps1:38 char:3
+ node $node
+ ~~~~
+ CategoryInfo : ObjectNotFound: (xSQLServer\xSQLServerSetup:String) [PSDesiredStateConfiguration\node],
ParentContainsErrorRecordException
+ FullyQualifiedErrorId : CommandNotFoundException,PSDesiredStateConfiguration\node

Compilation errors occurred while processing configuration 'DSC_install_docker_and_SQL_test'. Please review the errors
reported in error stream and modify your configuration code appropriately.
At
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psm1:3917
char:5
+ throw $ErrorRecord
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (DSC_install_docker_and_SQL_test:String) [], InvalidOperationException
+ FullyQualifiedErrorId : FailToProcessConfiguration

PS C:\Program Files\WindowsPowerShell\DscService\Configuration>

Does anyone have any advice on what the cause of the error could be, and how to resolve it?

August 6, 2017 at 3:19 pm

Well... line 38 is foreach ($node in $nodelist)
So my quess is that either $nodelist or $node has an invalid value.....

Any way you post the contents of dsc_install_docker_and_SQL-nodelist.txt?

August 8, 2017 at 12:03 am

The values in dsc_install_docker_and_sql-nodelist.txt, dsc_install_docker_nodelist.txt, and dscconfig_sqlnodelist.txt are the same, one line containing "SE123456" no quotes (changed from actual), but same in all 3 files. I was only working against one server which had the dual DSC configs applied.

When used in the dot-sourced script, it asks for credentials, then enters the SQL dot-sourced script to ask for credentials, then after getting them, fails.


#DSC_install_docker-dotsourced.ps1

$Config = 'DSC_Install_Docker'
$Nodelist = get-content dsc_install_docker_nodelist.txt 

$dockerconfigurationdata = @{ 
    AllNodes = @(
    	@{
    	    NodeName 			= '*'
            PSDscAllowPlainTextPassword = $true
            PSDscAllowDomainUser 	= $true
           InstallCredential 		= (Get-Credential -message "Enter an Admin ID to Install Docker on Servers")               	
	}	
    )  
}

ForEach ($Node in $Nodelist) 
{
    $dockerconfigurationdata.AllNodes += @{
        NodeName 	= $Node
        }
    
    Import-DscResource -ModuleName PSDesiredStateConfiguration
                
    
    	LocalConfigurationManager
    	{
    		RebootNodeIfNeeded = $true
    	}	        
        
        WindowsFeature Containers
        {
            Name    	= 'Containers'
            Ensure  	= 'Present'
        }     
    
    File Copy_NugetPackageManagement_Provider 
        {
        	Ensure					= 'Present'  
            Type               		= 'File' 
        	PSDSCRunAsCredential	= $InstallCredential
            SourcePath         		= "\\se131346\dsc\PackageManagement\ProviderAssemblies\nuget\2.8.5.208\Microsoft.PackageManagement.NuGetProvider.dll"
            DestinationPath    		= "C:\Program Files\PackageManagement\ProviderAssemblies\nuget\2.8.5.208\Microsoft.PackageManagement.NuGetProvider.dll" 
        	MatchSource 			= $true
        	Force				= $true
        }     
        
    Script Register_Repositories
        {
        	DependsOn = '[File]Copy_NugetPackageManagement_Provider'     
            GetScript =
            {
                $repository = (Get-PSRepository).name
                return @{ 'Repository' = $repository }
            }

            SetScript =
            {
                register-psrepository -name "RBCDevRepository" -sourcelocation "http://se131348:81/nuget/rbcdevrepository" -installationpolicy trusted –packagemanagementprovider nuget
                #register-psrepository -name "SMBRepository" -sourcelocation "\\se131346\psrepository" -installationpolicy trusted -packagemanagementprovider nuget
            }
            
            TestScript = 
            {
                $CurrentRepository = (Get-PSRepository).name
                $CorrectRepository = 'RBCDevRepository'
                if ($CurrentRepository -eq $CorrectRepository)
                {
                    Write-Verbose -Message "Correct Repository $CorrectRepository IS REGISTERED"
                    return $true
                } else 
                {
                    Write-Verbose -message "Correct Repository $CorrectRepository IS NOT REGISTERED"
                    return $false                     
                }
            }
        }
    
    Script Install_DockerMSFTProvider #don't need if doing manual install?
    	{
            GetScript =
            {
                $PackageInstalled = (get-module -ListAvailable dockermsftprovider).name
                return @{"DockerMsftProvider Package is installed" = ($PackageInstalled -eq "DockerMsftProvider")}                 
            }
          
            SetScript =
            {
                Install-Package -name 'dockermsftprovider' -source 'RBCDevrepository' -force
            }
            TestScript =
            {
                $PackageInstalled = (get-module -ListAvailable dockermsftprovider).name
                if  ($PackageInstalled -eq "DockerMsftProvider")
                    {    
                        Write-Verbose "DockerMsftProvider IS INSTALLED"  
                        return $true                                      
                    } else 
                    {
                        Write-Verbose "DockerMsftProvider IS NOT INSTALLED"
                        return $false
                    }
            }                       
        } 
   
    Script Install_Docker_Service
    {
            GetScript =
            {
                $PackageSaved = (test-path "c:\program files\docker\dockerd.exe")
                return @{"Docker Package is saved" = $PackageSaved}                 
            }
          
            SetScript =
            {
                save-package -name Docker-EE -requiredversion 17.3.0 -source rbcdevrepository -path "c:\temp" -force
                if (! (test-path "c:\program files\docker")) {new-item -path "c:\program files\docker" -type directory} 
                copy-item "c:\temp\docker-ee\17.3.0\docker*.exe" "c:\program files\docker\" 
                start-process "c:\program files\docker\dockerd.exe" -argument '--register-service' -wait               
            }
            
            TestScript =
            {
                $PackageSaved = (test-path "c:\program files\docker\dockerd.exe")
                if  ($PackageSaved -eq "True")
                    {    
                        Write-Verbose "DockerPackage IS SAVED"  
                        return $true                                      
                    } else 
                    {
                        Write-Verbose "DockerPackage IS NOT SAVED"
                        return $false
                    }
            }                       
    } 

    Service Set_and_Verify_Docker_Service
        {
            DependsOn 		= '[Script]Install_Docker_Service'
            BuiltInAccount 	= 'LocalSystem'
	    StartupType 	= 'Automatic'
    	#State 			= 'Running' #possibly eliminate this if an issue? might not be able to check for running during install, but only during subsequent checks
    		Description 	= "Docker Container Service"
    		DisplayName 	= "Docker Engine"
    		Ensure 		= 'Present'
    		Path 		= '"c:\program files\docker\dockerd.exe" --run-service'   
    		Name		= 'Docker'         
        }    
}