DSC class based resource - logic question...

This topic contains 10 replies, has 3 voices, and was last updated by Profile photo of Sam H Sam H 2 months, 1 week ago.

  • Author
    Posts
  • #68932
    Profile photo of Sam H
    Sam H
    Participant

    Hi all,

    I am starting to write some Powershell v5 class based resources to plug some gaps; basically if I can't find a module (community or otherwise) that does near enough what I want to do then I'll knock something up myself.

    What I am currently after is a good reference on how to approach the logic of the Set and Test blocks. Say that my DSC resource is ultimately running one cmdlet to set all declared properties:

    
    [DscProperty(Key)]
    [string] $FirstProp
    
    [DscProperty(Mandatory)]
    [string] $SecondProp
    
    [DscProperty(Mandatory)]
    [string] $ThirdProp
    
    [void] Set()
    {
    Set-TheThing -First $FirstProp -Second $SecondProp -Third $ThirdProp
    }
    
    

    What would the logic be for the Test block? Should I be testing each of the current properties in isolation and then having something like "If all properties match the desired state then $True, else $False"? That seems a bit inelegant obviously. Then if only one of the properties is out of line it seems overkill to be run the cmdlet to re-set all three properties when two of them are already correctly configured. (I guess that the set question is dependent on cmdlet behaviour but I am curious to understand the approaches)

    I am currently looking at some MS DSC resources to try to follow the logic used there but it's a bit of a slog for me considering that I am only now spending more time writing Powershell regularly and don't have a coding background (which is why logic is the guts of my question).

    I possibly haven't explained all of this as perfectly as I could so please do ask for more input if I am being too vague...

  • #68947
    Profile photo of Missy Januszko
    Missy Januszko
    Participant

    This is a great question, especially since there aren't many class-based resources available in the community yet. What I've seen in function-based resources is the use of PSBoundParameters – even for your test function. Otherwise the more parameters you have, the more complicated your logic gets. I have not tried using PSBoundParameters in a class-based resource, but it would be a worthy experiment.

    • #68949
      Profile photo of Sam H
      Sam H
      Participant

      Thanks for the reply Missy. PSBoundParameters has (have?!) indeed featured heavily in the examples I have looked at so I'll give that a crack and feed back when I can.

      Do you have an example of a function based resource that you feel handles the parameter logic gracefully? Ideally with a mix of mandatory and optional parameters?

  • #68952
    Profile photo of Missy Januszko
    Missy Januszko
    Participant

    A great example of this is in the xADCSDeployment module – the MSFT_xADCSCertificationAuthority module. There are tons of optional parameters and the code is SO clean.

  • #68959
    Profile photo of Sam H
    Sam H
    Participant

    Much appreciated, I'll have a nose now!

    Edit: There's comment based help 🙂

  • #68988
    Profile photo of Sam H
    Sam H
    Participant

    Bit of an update: looks like PSBoundParameters might not be implemented in Powershell classes yet? Am therefore looking into $MyInvocation.BoundParameters or some variant but no joy yet.

    Will pick this up later, but it's slow going as I'm not familiar with how to work with objects within the class structure – for example simply exploring $this outside of the class scope.

    • #69027
      Profile photo of Missy Januszko
      Missy Januszko
      Participant

      I'm going to dive into this too, because now I want to know the answer. I suspected that PSBoundParameters wouldn't work because of the way the parameters/properties get declared. And now I'm curious. 🙂

    • #69034
      Profile photo of Sam H
      Sam H
      Participant

      Ha, my brain keeps flipping between "I can build a function based resource and be happy with the debugging/testing/(and even concepts!), then migrate over once classes have matured", and "Yeah but I NEED to know how this works"!

      My afternoon has no room for looking into this in any serious way, but let me know if there's any donkey work you want me to do and I'll do what I can when I get home later

    • #69046
      Profile photo of Eric
      Eric
      Participant

      Probably I am missing something in your question, but why the need for PSBoundParameters? With a class-based resource you can see if a non-mandatory parameter has been specified with an "if" statement. E.g.

      If ($this.setting1) {
      #do stuff
      }

    • #69052
      Profile photo of Sam H
      Sam H
      Participant

      Yep, fair question. I am just doing exploratory work at the moment to find the best route. I like the fact the PsBoundParameters gives a hash table to work with. If I am only using one cmdlet in my set method that has three mandatory and five optional parameters I could just match those requirements up to the class properties and then splat PsBoundParameters across the cmdlet. I think the xActiveDirectory module has a helper function hidden away in a module that has all of the if () logic within it; it takes PsBoundParameters then whittles it down to a usable object.

      I know those are very specific examples, I'm not trying to prove WHY I should want to use them and win an argument (I'm not yet proficient enough to win!). It's more a case that Missy mentioned it, its use seemed prevalent across older resources and I wanted to suss out the equivalent in classes. 🙂

      Thanks for your other reply by the way, I agree that the mixing of set and test is a bit scary.

  • #69001
    Profile photo of Eric
    Eric
    Participant

    I usually approach the Test function like this: start by declaring a variable $result = $true. Then I go through and test each setting individually. If I find a misconfiguration, I use write-verbose to describe exactly what failed, then I set $result = $false. Then at the end of Test I just "return $result".

    For the Set, I've taken various approaches; it often depends on the behavior of the cmdlet I'm using to do the setting (does it let you address properties individually or require you to clobber whatever's there?), and depends on how elegant I need to be. (E.g. will clobbering everything be very disruptive to the system? You have to be careful with network settings for instance.) It can certainly make your Set function simpler if you just clobber what's already there.

    I have also taken the approach of creating a separate function that will do testing or setting. It takes a parameter indicating which it's supposed to do. It examines each aspect, then either set a $result variable (if it's in test mode) or makes a change to align just that aspect (if it's in set mode). I mainly did this because the code of Test and Set would have been 99% the same otherwise, and it seemed efficient. In hindsight, however, I don't recommend this approach. I think it's too dangerous to mingle Test and Set code in one place. You'd hate for your routing Test to result in a change if you're in ApplyAndMonitor mode.

You must be logged in to reply to this topic.