4

TLDR; What is the best way to create a DSC configuration file dynamically?

I am tasked with maintaining a complex folder structure including permissions. This is currently done with custom PowerShell modules. The problems arise when changes are made to the folder structure itself.

Using DSC would eliminate the compliance aspect of the problem. Generating a DSC Configuration for 20k folders by hand is absolutely out of the question. I would like to create the DSC configuration from some input via PowerShell. That way, changes can be introduced in a timely manner and applied once the DSC configuration has reviewed.

Or am I completely on the wrong track and I can just generate the structure from input within the DSC configuration?

  • I have a similar challenge, I have a system composed of several different resource types, and want to create a DSC configuration script from the running system. I've scripted this before (about five years ago) and it was awful. Wondering if there are any helper functions for this now, similar to the DSC resource designer, but for DSC configuration items. Anybody know of such thing? – Craig - MSFT Feb 14 '19 at 17:12

2 Answers2

2

When you write your DSC configuration, it's a script that gets executed at design time to ultimately generate the MOF file. So you can do something like this:

Configuration Folders {

    Get-Content 'myfolderlist.txt' | ForEach-Object {

        File $($_ -replace '\\','_')
        {
            DestinationPath = $_
            Ensure = "Present"
        }
    }
}

This doesn't address permissions, but it shows how a loop can be used in a DSC configuration. The important thing to remember here is that what this will do, is generate a static configuration (MOF) file with 20k File resources at design time. The loop doesn't get run (nor is it at all present) when DSC is running.

DSC is not the fastest thing.. doing a test/set on 20,000 resources is likely to be really slow and somewhat resource intensive. I kind of feel like this might not be the tool for the job.

Or, you could create a custom DSC resource that does all the logic of testing and setting the folder structure and permissions, so it happens all in one resource.

Essentially then this is a glorified scheduled task, but that might be ok, especially if you want to use DSC in a wider sense. There are lots of articles (and books) out there about how to create a custom resource if you want to take a look at those.

briantist
  • 45,546
  • 6
  • 82
  • 127
  • Thanks that was the missing link. I will report back what my test environment has to say about the speed of things. – Martin Adler Aug 26 '16 at 15:38
2

It's not pretty, but I do stuff like below for NTFS permissions, where you may need to expand if you set no subfolder access, etc. I didn't see of an easy way to create the configuration dynamically so I repurpose with different params set. Obviously this is 5 years later so you've probably come up with something. The switches up top are basically to replace variables from your node definition file.

        Function NtfsPermissions
        {
            Param (
                [Parameter(Mandatory=$true)]
                [ValidateSet("Present","Absent")]
                [string]$Ensure,
                [Parameter(Mandatory=$true)]
                [string]$Account,
                [Parameter(Mandatory=$true)]
                [string]$Path,
                [string[]]$FileSystemRights,
                [string]$Inheritance,
                [string]$Depends
            )
        #Switches are used to dynamically replace accounts and paths that can't be set in nodedefinition file
            switch ($Account)
            {
                "SQLAGENT"
                {
                    $Account = $Node.gSqlAgt
                    break
                }
                "SQLSVC"
                {
                    $Account = $Node.gSqlSvc
                    break
                }
                "SQLIS"
                {
                    $Account = $Node.gSqlIs
                    break
                }
            }
            switch ($Path)
            {
                "AuditPath"
                {
                    $Path = $Node.AuditPath
                    break
                }
                "LogDir"
                {
                    $Path = $Node.LogDir
                    break
                }
                "DataDir"
                {
                    $Path = $Node.DataDir
                    break
                }
                "TempdbDir"
                {
                    $Path = $Node.TempdbDir
                    break
                }
            }
            if ($Ensure -ne "Absent")
            {
                cNtfsPermissionEntry $($Account + $Path.Replace(':','_'))
                {
                    Ensure = $Ensure
                    Path = $Path
                    Principal = $Account
                    AccessControlInformation = @(
                        cNtfsAccessControlInformation
                        {
                            AccessControlType = 'Allow'
                            FileSystemRights = $FileSystemRights
                            Inheritance = $Inheritance
                            NoPropagateInherit = $false
                        }
                        )
                    DependsOn = $("[File]$Depends")
                    }
                    
            }
            else
            {
                cNtfsPermissionEntry $($Account + $Path.Replace(':','_'))
                    {
                        Ensure = $Ensure
                        Path = $Path
                        Principal = $Account
                        #Need depends on, just not sure how to structure yet
                        DependsOn = "[File]" + $Depends
                }
            
            }
    }
    $NtfsEntries = $ConfigurationData.NonNodeData.Roles.($Node.Role[0]).NtfsPerms #Need to find a better approach to reference Role
        foreach ($ntfs in $NtfsEntries) {
            NtfsPermissions -Ensure $ntfs[0] -Account $ntfs[1] -Path $ntfs[2] -FileSystemRights $ntfs[3] -Inheritance $ntfs[4] -Depends $ntfs[5]
        }