Dynamically supply parameters to DSC resource?

Hey guys,

I’ve asked the following on both /r/Powershell and on StackOverflow but I’ve had no results, so I’m hoping you can help me out!

I was working on a composite resource when I came across the issue of being able to dynamically pass parameters to a DSC resource and wondered if there’s another way to tackle this that I’m missing.

Basically, I have the an array (Below) that contains one PSObject per desired file-share. Each of these PSObjects has properties that are used as parameters for my DSC resource (In this case the cLocalFileShare community resource).

The issue is, not all of these objects have all of the parameters defined. For example, some of my shares don’t have any users/groups assigned to the ReadAccess permission, but in my ForEach loop (Below), a $null value is being passed to the actual resource as this permissions isn’t defined, and this causes the resource to error as it is trying to set ReadAccess permissions to user $null.

My issue is, how do I tackle this - for this resource and others?

  • I’ve tried splatting the parameters in the DSC resource, but this doesn’t seem to be supported. If this worked, I could build a different parameter list and pass that.
  • Somebody on Reddit suggested passing a string that contained all of the parameters, but again this doesn’t seem to be supported.
  • My worst fear is, I will have to edit each resource to support (and ultimately ignore) $null values which seems like a really bad way to tackle this.

So, here’s my array containing a PSObject per file share.

    $MyConfig = @(
        @{ 
            Path = 'D:\Shares\Accounting'
            Name = 'Accounting'
            Ensure = 'Present'
            ChangeAccess = 'AccountingAdmins'
            ReadAccess = 'AccountingInterns,FinanceDepartment'
        } 
        @{ 
            Path = 'D:\Shares\Software'
            Name = 'Software$'
            Ensure = 'Present'
            ReadAccess = 'DomainUsers'
        }
    )

Now, within the actual DSC configuration…

    configuration {
        ForEach ($ShareProperties in $MyConfig) {
            # Each resource is named after the Path specified, but with the colon replaced as that's not valid character for the resource name
            cLocalFileShare $ShareProperties.Path.Replace(':','__') {
                Path = $ShareProperties.Path
                Name = $ShareProperties.Name
                Ensure = $ShareProperties.Ensure
                ChangeAccess = $ShareProperties.ChangeAccess
                ReadAccess = $ShareProperties.ReadAccess
            }
        }
    }

For now, there’s no good way to do this, but it’s something we’ve asked Microsoft to support in the future. The problem is that DSC currently does a lot of this stuff at parse time, and gives us no way to have execution-time tricks like splatting.

“My worst fear is, I will have to edit each resource to support (and ultimately ignore) $null values which seems like a really bad way to tackle this.”

That’s exactly where things stand for now. I’ve had to do this a couple of times myself.

Thanks Dave, I thought it might come to that.

Wherever I have a PowerShell issue, your name seems to crop up with a solution!

I literally just ran into this problem myself. It’s not too bad as long as you sit back and come out with a “model” to base breaking up your various resources by. SO know that the plan is to make a resources per system, for example, then within said resource you can handle the possible NULL for it. If you get too random with your resources (this resource is for Exchange, that one is for the New York Site), then it becomes a massive mess fast.

At the end of the day “cattle not pets”. Look at what yo’re supporting and justify if a specific node really needs special attributes.

It’s an idea/process as much as anything else.

I know it’s an old post, but I haven’t seen this ‘trick’ below, so I thought I’d share…

To allow splatting, or something as close as I could get, I’ve created a simple function:

function Get-DscSplattedResource {
    [CmdletBinding()]
    Param(
        [String]
        $ResourceName,

        [String]
        $ExecutionName,

        [hashtable]
        $Properties
    )
    
    $stringBuilder = [System.Text.StringBuilder]::new()
    $null = $stringBuilder.AppendLine("Param([hashtable]`$Parameters)")
    $null = $stringBuilder.AppendLine(" $ResourceName $ExecutionName { ")
    foreach($PropertyName in $Properties.keys) {
        $null = $stringBuilder.AppendLine("$PropertyName = `$(`$Parameters['$PropertyName'])")
    }
    $null = $stringBuilder.AppendLine("}")
    Write-Debug ("Generated Resource Block = {0}" -f $stringBuilder.ToString())
    
    [scriptblock]::Create($stringBuilder.ToString()).Invoke($Properties)
}
Set-Alias -Name x -Value Get-DscSplattedResource

That way I can call the alias, and write something like:

Configuration MyConfig {
    x File MyFile @{
        Ensure          = 'Present'
        DestinationPath = 'C:\test.txt'
        Contents        = 'This is my content'
    }
}

Since it now accepts an hashtable as input, it’s easier to make it handle $Null values (which I do when constructing the hashtables).
One of the downside is that it removes some of the sugar coating of the DSL (like in the IDE).