Author Posts

November 27, 2014 at 1:49 pm

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?

November 28, 2014 at 6:31 am

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.)

November 28, 2014 at 6:53 am

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.

November 28, 2014 at 8:33 am

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.