Access Reusable helper function in Script resources

To follow DRY principle, I have created a helper function in my DSC script. However I can’t access it from inside Script resource. After some research I found that SetScript block is actually a string. Do you have a workaround or real solution for this? Here is my sample flow:

function Get-WebsiteCurrentPhysicalPath($webSiteName, $defaultPath) {
    $website = Get-Website -Name "$webSiteName"
    if($website -eq $null) {
        return $defaultPath
    }
    else {
        return Get-ItemProperty IIS:\Sites\$webSiteName -name physicalPath
    }
}

Configuration WebsiteConfiguration {
Node ('localhost')
    {
        ## Bootstrap
        $MasterConfig = @{
            CurrentIISWebsitePhysicalPath = Get-WebsiteCurrentPhysicalPath $siteName $path
        }
        Script NewWebsiteDefaults
        {
            GetScript = {return $using:MasterConfig}
            TestScript = {return $false}
            SetScript = {
                $state = $GetScript
                # Following line doesnot work
                $script:CurrentPhysicalPath = Get-WebsiteCurrentPhysicalPath $siteName $path
                # I tried this following line, even this doesnot work
                $script:CurrentPhysicalPath =  $using:state['CurrentIISWebsitePhysicalPath']
            }
        }
    }
}

Hmm. I don’t think I’ve ever tried that; I tend to avoid Script resources like a plague.

But I’m perhaps not following your need. Do you want your function only available when the Configuration is run? As-is, it looks like you want it available on the target nodes. Just because the function is in the same .ps1 file as the Configuration, doesn’t make the function available on target nodes. The Configuration produces a MOF; your function isn’t included in that.

Can you help me understand the goal?

(similarly, your $script modifiers won’t have any effect when the Script is run on the target node; the Get/Set/Test blocks are run in their own PowerShell process)

Sorry if I confused you. Let me try again.
I have piece of re-useable code logic inside my function which I want to leverage in DSC resources so that i don’t have to repeat myself. In the sample I provided for instance, the function returns the IIS website’s physical path if exists else a default value. Lets assume I want to use this value (function returned) in multiple DSC resources and Script is one of them. If I print the value of Line#25 it is Empty. And same is Line#27.
References:

  1. https://msdn.microsoft.com/en-us/powershell/dsc/scriptresource#example-2
  2. Script Block properties in DSC resources | Dave Wyatt's Blog

HTH
Thanks

If I replace Line#25 with this

$script:CurrentPhysicalPath = Get-ItemProperty IIS:\Sites$using:siteName -name physicalPath

then it works like a charm! So apparently, built-in cmdlets works but not custom functions?

Yeah, so, the thing is, when you run a Configuration, it creates a MOF. That MOF won’t contain your function. And, when Script resource Get/Set/Test blocks run, there’s no shared $script context for them.

So what’s happening to you is this:

  1. You run the Configuration
  2. MOFs are produced
  3. You deploy the MOFs to target nodes
  4. The target nodes try to run Get-WebsiteCurrentPhysicalPath, but it doesn’t exist on the target nodes

The only way to make this work is to put your function into a script module, and deploy it to your target nodes. You’ll also need to resolve your use of $script, which isn’t actually going to work.

The CORRECT answer, from a DSC perspective, is to Never Use Script Resources. Build your own custom resource (which is really just three functions; you’ve already done all the work) and deploy it to your target nodes. Your custom resource is a script module, so it CAN include a helper function like you’ve written here.

If I replace Line#25 with this $script:CurrentPhysicalPath = Get-ItemProperty IIS:\Sites\$using:siteName -name physicalPath then it works like a charm! So apparently, built-in cmdlets works but not custom functions

Also, the $script is completely unnecessary. $CurrentPhysicalPath would do the same thing.

The problem is, I think, that you’re maybe not understanding what the target nodes are running. They are NOT running your Configuration block. The target nodes do not have your .ps1 file, and they do not have your custom function. When a Configuration runs, it doesn’t even execute the Script resource. It simply produces a MOF. Try running your Configuration - and then opening the resulting MOF in Notepad. You’ll see your Script block, plain as day. You’ll also NOT see your custom function - which is why the target nodes don’t have it.

Thanks for the explanation. Very helpful.

Actually, the CORRECT answer, from a DSC perspective, is to NEVER Use Script Resources for Logic, is what Don means more likely :slight_smile:

You should not add logic to your DSC configuration scripts, but if you need a script to run, then yes, that’s why the Script DSC resource exists. Problem is its a bit misused, but I wouldn’t go as far as saying NEVER use the script DSC resources all together :slight_smile:

Yeah I believe you’d be better off writing your own custom resource for what you’re trying to do.

This will allow you to run whatever custom functions/logic you need, as you can just contain them in the resource.

Check this page out for more info