Final config review & thoughts

This topic contains 3 replies, has 2 voices, and was last updated by Profile photo of Dave Wyatt Dave Wyatt 2 years ago.

  • Author
    Posts
  • #20841
    Profile photo of Ryan Young
    Ryan Young
    Participant

    Hi powershell.org! I believe I have my final config in order, and a work-methodology for fellow colleagues/techs who will get involved with the project. I just wanted to refer my setup to you since in a lot of ways it is you who co-authored this with (heck in some cases FOR me). Hoping to get pointers to clean it up, and welcome any thoughts.

    [b]Master Config[/b]

    
    get-dscresource
    function GetAllServers {
        import-module ActiveDirectory
        Get-ADComputer -SearchBase "OU=DSCdev,DC=yourdc,DC=contoso,DC=com" -Filter *
    }
    $AllServers = GetAllServers
    
    function Get-NodeEnvironment {
        [OutputType([string])]
        param (
            [Parameter(Mandatory)]
            [string] $DistinguishedName
        )
     
        switch -Wildcard ($DistinguishedName) {
            '*OU=Stage*' { return 'Stage' }
            '*OU=QA*'    { return 'QA' }
            '*OU=DEV*'   { return 'DEV' }
            default      { return 'Production' }
        }
    }
    
    function Get-NodeRole {
        [OutputType([string])]
        param (
            [Parameter(Mandatory)]
            [string] $DistinguishedName
        )
     
        $cn = ($DistinguishedName -split ',')[0]
     
        switch -Wildcard ($cn) {
            '*IIS*' { return 'WebServer' }
            '*DC*'  { return 'ADDS' }
            '*SQL*' { return 'SQL' }
            default { return 'Vanila' }
        }
    }
    
    # Gather AllNodes and add an environment variable to it based on OU name.
    $AllServerConfigData = @{
        AllNodes = @(
            foreach ($node in $AllServers) {
                @{
                    NodeName        = $node.Name
                    NodeGUID        = $node.objectGUID
                    NodeEnvironment = Get-NodeEnvironment -DistinguishedName $node.DistinguishedName
                    NodeRole = Get-NodeRole -DistinguishedName $node.DistinguishedName
                }
            }
        )
    }
    
    Configuration WindowsBackup {
        WindowsFeature WindowsSbackup 
        {
            Name = "Windows-Server-Backup"
            Ensure = "Present"
            IncludeAllSubFeature = "$True"
        }
    }
    
    Configuration Everything 
    {
        Import-DscResource -name *
     
        Node $allnodes.where({$_.NodeRole -eq "WebServer"}).NodeGuid {
            MyIISPull AllWinFeatures {}
        }
     
        Node $allnodes.where({$_.NodeRole -eq "ADDS"}).NodeGuid {
            RdsServer TerminalServices {}
        }
     
        Node $allnodes.where({$_.NodeRole -eq "SQL"}).NodeGuid {
            rFileServer WinSharesYay {}
            RdsServer TerminalServicesSQL{}
        }
     
        Node $allnodes.where({$_.NodeEnvironment -eq "Production"}).NodeGuid {
            WindowsBackup BackupProductionAlways {}
        }          
    }
    
    Everything -ConfigurationData $AllServerConfigData -outpath "C:\DSCCustom\WorkDir"
    
    write-host "##################Creating checksums....######################"
    New-DSCCheckSum -ConfigurationPath "C:\DSCCustom\WorkDir" -Verbose -Force
    
    Write-host "##################Copying configs to the pull service configuration store###############################"
    $sourcefiles = "C:\DSCCustom\WorkDir\*\*.mof*"
    $sourcechecks = "C:\DSCCustom\WorkDir\*\*.checksum*"
    $targetfiles = "$env:SystemDrive\Program Files\WindowsPowershell\DscService\Configuration"
    copy-item -Recurse $sourcefiles $targetfiles -Force -Verbose
    copy-item -Recurse $sourcechecks $targetfiles -force -Verbose
    
    #Run the below to add a checksum to new modules you zip and place for download
    #New-DSCCheckSum -ConfigurationPath "C:\Program Files\WindowsPowerShell\DscService\Modules" -Verbose -Force
    

    [b]Methodology for maintaining/updating composite resources[/b]

    1) Added a new path to system powershell profile:

    #Save the current value in the $p variable.
    $p = [Environment]::GetEnvironmentVariable("PSModulePath")
    
    #Add the new path to the $p variable. Begin with a semi-colon separator.
    $p += ";C:\DSCCustom\Making Resources\CustomComposite\WindowsPowershell\Modules"
    
    #Add the paths in $p to the PSModulePath value.
    [Environment]::SetEnvironmentVariable("PSModulePath",$p)

    2) All my techs/admins who are involved in creating composite resources create them in the new environment location using a modified version of Steve's "New-DscCompositeResource" script that I found here: [url]https://github.com/PowerShellOrg/DSC/blob/master/Tooling/DscDevelopment/New-DscCompositeResource.ps1[/url]

    The modification is simply taking the original script and modifying line 20:
    original

             $Path = "$($env:ProgramFiles)\WindowsPowerShell\Modules",

    new

             $Path = "C:\DSCCustom\Making Resources\CustomComposite\WindowsPowershell\Modules", 

    So a summary: Powershell has two locations now for its own modules. The original under c:\programfiles\windowspowershell\modules (which I use for unzipped modules from the resource kit) and the c:\DSCCustom\...\ path I added so that techs don't mess around extensively in program files, creating a 'logical' divide between system and custom work.

    3) The above works, when I use the script it creates the resource and the folder/file structure as needed and my techs modify the custom composite resources they made themselves. Get-DSC resource finds all the resources and when referencing them in the configuration as such a mof is generated.

    [b]Small bug:[/b]

    Unless I add get-dscresource, OR I choose to add "import-dscresource -name *" to the master config, running the configuration will generate errors stating that my resources are "unknown commands" . Is this nromal/expected?

  • #20847
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    It's normal that you have to run Import-DscResource when you want to use any resource (including composite) that aren't found in the PSDesiredStateConfiguration module. (Or possibly anywhere in $pshome\modules, which currently amounts to the same thing.) I'm not sure why running Get-DscResource would help.

    Personally, I don't see much point in this arrangement:

    Configuration WindowsBackup {
        WindowsFeature WindowsSbackup 
        {
            Name = "Windows-Server-Backup"
            Ensure = "Present"
            IncludeAllSubFeature = "$True"
        }
    }
    
    # . . .
    
    node Whatever {
        WindowsBackup BackupProductionAlways {}
    }
    

    I would use composite resources to bundle up several different resources that are installed together. When the composite resource only contains a single resource, you could just call that resource directly and not bother with the middle man. (One exception I would make here is if you plan to expand the composite resource later, and want to make the change easier. In that case, I would name it something like ProductionFeatures rather than WindowsBackup.)

  • #20848
    Profile photo of Ryan Young
    Ryan Young
    Participant

    I agree completely. I had it there for "demonstration to the boss" purposes to show that we 'could' put it there. When I say this is the 'final product', I mean it's the product we will use as the baseline to make a real production dsc pull server from. IE: this is the documented version before the real fun :). There's also a running joke in our office about the importance of backups, so it was funny to just put there :).

    and yeah it's weird that get-dscresource helped... when I was still learning this, I didn't know you could use a wildcard under import-dscresource so I had my script like this:

    Configuration Everything 
    {
        Import-DscResource -Name rdsserver, myiispull, rfileserver
        Import-DscResource -ModuleName xsmbshare
     
        Node $allnodes.where({$_.NodeRole -eq "WebServer"}).NodeGuid {
            MyIISPull AllWinFeatures {}
    

    Running get-dscresource allowed the above to work somehow, but if I didn't run it the above would fail with errors that "rdsserver is not a valid command"... I categorically tested this with new powershell sessions while moving resources/zipped modules around (original theory was that the bug was related to the mere existence of the config files + modules – I had observed that removing them would 'solve' the problem, but failed to notice that I was running get-dscresource after these actions to 'refresh' the current session. Yeah I was tired and it wasn't making much sense haha) Anyway I disproved the original theory and proved this one.

    In the end, using a wildcard after import-dscresource (while it makes my script take a little longer) ends up being a cleaner solution.

  • #20849
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Interesting. I'll see if I can reproduce that behavior. If so, it may be a bug in Import-DscResource (in conjunction with a modified PSModulePath environment variable, perhaps.) It's possible that this is something they're already aware of and have fixed in the WMF 5.0 preview, though; there are a lot of little improvements along those lines.

You must be logged in to reply to this topic.