Skip to content

Instantly share code, notes, and snippets.

@devblackops
Last active December 17, 2015 07:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devblackops/b47ff0bbf8ecc1374adf to your computer and use it in GitHub Desktop.
Save devblackops/b47ff0bbf8ecc1374adf to your computer and use it in GitHub Desktop.
How can I make Import-DscResource dynamic? I won't know ahead of time what DSC resources will be needed as all the required parameters and the type of resource is passed in by the user.
# Example data to feed into script.
# In real life, this is an array of hashes
# with the required parameters for 1 or more
# custom DSC resources to provision infrastructure
# The types of resources to create will only be
# known at runtime
$ResourceData = @(
@{
Name = 'fileShareTest'
Type = 'cFileShare:cCreateFileShare'
Options = @{
Path = 'c:\temp'
ShareName = 'DscTest'
}
},
@{
Name = 'uacTest'
Type = 'xSystemSecurity:xUAC'
Options = @{
Setting = 'AlwaysNotify'
}
}
)
$DSCConfigData = @{
AllNodes = @(
@{
NodeName = "*"
PSDscAllowPlainTextPassword = $true
PSDscAllowDomainUser = $true
}
@{
NodeName = 'localhost'
Config = $ResourceData
}
)
}
function CreateResource {
param(
$Options
)
switch ($options.Type) {
'cFileShare:cCreateFileShare' {
cCreateFileShare $options.Name {
ShareName = $options.Options.ShareName
Path = $options.Options.Path
}
}
'xSystemSecurity:xUAC' {
xUAC $options.Name {
Setting = $options.options.Setting
}
}
}
}
Configuration DscCompile {
Import-DscResource -ModuleName PSDesiredStateConfiguration
# I don't want to hard code the modules to import because
# the user is passing in the resource options at runtime
# and will be unknown.
# I guess I could just import all DSC resources on the system
Import-DscResource -ModuleName cFileShare
Import-DscResource -ModuleName xSystemSecurity
# Dynamically load DSC resources
# This doesn't work as Import-DscResouce is a keyword
# and it doesn't support variables for ModuleName and Name parameters
foreach ($item in $AllNodes.Config) {
$mod = $item.Type.Split(':')[0]
$res = $item.Type.Split(':')[1]
# This doesn't work. ModuleName must be a constant
#Import-DscResource -ModuleName $mod -Name $res
}
# Call function to create the actual DSC resource based on the given options
Node $AllNodes.NodeName {
$Node.Config | ForEach {
Write-Verbose $_.Type
# I'd like to move the logic of what resource to create to outside
# the Configuration block. Ideally, into a seperate file.
CreateResource -Options $_
# Would prefer not to do this as the types of resources
# I'd be creating will only be known at runtime
<#
if ($_.Type -eq 'cFileShare:cCreateFileShare') {
cCreateFileShare 'FileShareTesting' {
Path = $_.Options.Path
ShareName = $_.Options.ShareName
}
} elseIf ($_.Type -eq 'xSystemSecurity:xUAC') {
xUAC 'xUACTesting' {
Setting = $_.Options.Setting
}
}
#>
}
}
}
$mof = DscCompile -ConfigurationData $DSCConfigData -Verbose
@bgelens
Copy link

bgelens commented Dec 17, 2015

I'm not entirely sure why you would want to do this. I've seen a presentation once by Bartek Bielawski who used AST to do partial configs in WMF4 by combining configurations before MOF compile. I guess what you are trying to accomplish is a bit like this?

Anyway. My first thought about making Import-DscResource use dynamic input is by looking at a configuration from a different perspective. If you treat it like text, it's pretty easy. Probably not what you are looking for though.

$ResourceData = @(
    @{
        Name = 'fileShareTest'
        Type = 'cFileShare:cCreateFileShare'
        Options = @{
            Path = 'c:\temp'
            ShareName = 'DscTest'
        }
    },
    @{
        Name = 'uacTest'
        Type = 'xSystemSecurity:xUAC'
        Options = @{
            Setting = 'AlwaysNotify'
        }
    }
)

function Create-Config {
    param (
        [String] $ModuleName,
        [String] $ResourceName,
        [String] $Name,
        [String] $Options
    )
    "configuration $Name {
        import-dscresource -modulename $ModuleName

        $ResourceName $Name {
            $Options
        }
    }"
}
iex (Create-Config -ModuleName $ResourceData[1].Type.Split(':')[0] -ResourceName $ResourceData[1].Type.Split(':')[1] -Name $ResourceData[1].Name -Options ($ResourceData[1].Options.GetEnumerator() | % { "$($_.Key)='$($_.Value)'" }))
iex (Create-Config -ModuleName $ResourceData[0].Type.Split(':')[0] -ResourceName $ResourceData[0].Type.Split(':')[1] -Name $ResourceData[0].Name -Options ($ResourceData[0].Options.GetEnumerator() | % { "$($_.Key)='$($_.Value)'`n" }))
fileShareTest
uacTest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment