We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Define, Develop and Deploy DSC Resources

00:00

Formal Metadata

Title
Define, Develop and Deploy DSC Resources
Title of Series
Number of Parts
60
Author
License
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language
Producer
Production Year2018

Content Metadata

Subject Area
Genre
Abstract
Even though there is an abundance of DSC resources, there is always room for more. Perhaps there is some Windows feature or setting that hasn't been covered yet. Or you have a home-grown application that needs a resource. In this demo-heavy session you will learn everything you need to know about designing and deploying a DSC resource. We'll start with the legacy DSC resource model and finish with a modern, high-quality DSC resource. Lots of code, best practices and demos abound.
Software repositoryLink (knot theory)Demo (music)Asynchronous Transfer ModeMultiplication signProcess (computing)Computer fileCodeConfiguration spaceQuicksortCuboidServer (computing)Goodness of fitComputer animation
Social classStrategy gameFunction (mathematics)Parameter (computer programming)Common Language InfrastructureSoftware testingSet (mathematics)Demo (music)RoutingFunctional (mathematics)Module (mathematics)Line (geometry)Server (computing)Mixed realityLevel (video gaming)CuboidClient (computing)Error messageConfiguration spaceRevision controlWindowCategory of beingBasis <Mathematik>Order (biology)Time zoneScripting languageCore dumpMathematicsUtility softwareSet (mathematics)Strategy gameParameter (computer programming)Social classLatent heatBuildingMultiplication signMessage passingState of matterPoint (geometry)CodeDemo (music)Connected spaceCross-platformSoftware testingAxiom of choiceProcess (computing)Decision theoryComputer animation
StrutScripting languageMach's principleSimultaneous localization and mappingCategory of beingExecution unitSanitary sewerMetreMaxima and minimaCodeBoolean algebraWindowOpen sourceType theoryException handlingObject (grammar)Machine codeAttribute grammarCategory of beingLocal ringSoftware testingRight angleCASE <Informatik>Traffic reportingNP-hardData structureClassical physicsProcess (computing)Proxy serverDirectory serviceScripting languageModule (mathematics)Demo (music)Computer fileResultantSampling (statistics)Shared memoryHierarchyFunctional (mathematics)Error messageServer (computing)Hand fanHash functionParameter (computer programming)Domain nameBuildingOnline helpLink (knot theory)Projective planeConfiguration spaceBus (computing)LaptopComputer animation
Software testingExecution unitJunction (traffic)Category of beingData Encryption StandardAnnulus (mathematics)Frame problemMIDISineModule (mathematics)Computer iconComputer wormScripting languageComputer fileWeb pageComputer-generated imageryKey (cryptography)Table (information)Online helpException handlingStructural loadFunctional (mathematics)Configuration spaceSet (mathematics)Category of beingSoftware testingWindowHash functionPhysical systemIntegrated development environmentParameter (computer programming)NeuroinformatikComputer fileCodeGame controllerProcess (computing)Web pageError messageResultantQuicksortBootingType theoryMaxima and minimaDemo (music)MereologyVirtual machineUniform resource locatorComputer programmingServer (computing)Revision controlModule (mathematics)SubsetMultiplication signSource codeXML
Data typeExecution unitCellular automatonPlanningSalem, IllinoisChemical equationTime domainData Encryption StandardReading (process)SummierbarkeitUsabilityEmailSuite (music)Attribute grammarDialectString (computer science)Nim-SpielRoyal NavyCategory of beingMenu (computing)InformationPhysical systemMaizeRepeating decimaloutputComputer iconComa BerenicesStrutForceWeb pageMaxima and minimaObject (grammar)PermianWindowMultiplicationClassical physicsServer (computing)Procedural programmingNormal (geometry)Entire functionVideo gameCodePhysical systemWindowLine (geometry)Module (mathematics)Virtual machineRemote procedure callComputer fileHash functionTable (information)MereologyParameter (computer programming)Mechanism designOrder (biology)Directory serviceConfiguration spaceWeb pageSoftwareCategory of beingRead-only memoryFunctional (mathematics)BuildingType theorySoftware testingComputer programmingComputer programGoodness of fitCommitment schemeBackupError messageDampingMaxima and minimaDescriptive statisticsKey (cryptography)Object (grammar)Boolean algebraProcess (computing)Attribute grammarPlanningComputer animation
WindowObject (grammar)PredictabilityData conversionQuicksortString (computer science)Type theoryBoolean algebraSoftware testingSocial classInstance (computer science)Category of beingResultantParameter (computer programming)OvalAttribute grammarKey (cryptography)Error messageHydraulic jumpDemo (music)2 (number)Object (grammar)Revision controlCodeWeightSet (mathematics)Software developerDisk read-and-write headVirtual machineWhiteboardGoodness of fitDefault (computer science)Cellular automatonEnumerated typeModule (mathematics)Scripting languageFunctional (mathematics)QuicksortSampling (statistics)Order (biology)BitMobile appComputer fileWeb page
Data conversionEmailMenu (computing)GradientEmulationMathematicsSocial classTelephone number mappingExecution unitRing (mathematics)CodePlane (geometry)Attribute grammarReading (process)Interior (topology)Inheritance (object-oriented programming)InformationClassical physicsWeb pageStructural loadComputer fileData structureObject (grammar)CodeModule (mathematics)Category of beingDistribution (mathematics)Line (geometry)Function (mathematics)Pairwise comparisonDirectory serviceSoftware testingRevision controlSocial classSoftware developerMultiplication signStatement (computer science)Set (mathematics)Content (media)Common Information Model (computing)Point (geometry)Functional (mathematics)RootFormal verificationMoving averageDescriptive statisticsBuildingDataflowRight angleNumberType theoryInstance (computer science)
SineUtility softwareExecution unitPiComputer wormSocial classLemma (mathematics)Gamma functionMIDIString (computer science)Data typeMenu (computing)Attribute grammarConvex hullSummierbarkeitCategory of beingMeta elementCodeFunctional (mathematics)Configuration spacePerfect groupResultantSubsetInformationData managementInstance (computer science)Goodness of fitSoftware testingFunction (mathematics)Computer fileSocial classError messageComputer programVirtual machineTable (information)Message passingSoftware developerHash functionLine (geometry)Distribution (mathematics)Sampling (statistics)Web pageFlow separationWritingDemo (music)WindowSet (mathematics)DemosceneRight angleElectronic visual displayCASE <Informatik>Category of beingQuicksortType theory
Data typeAttribute grammarDuality (mathematics)String (computer science)Category of beingVacuumExact sequenceLemma (mathematics)CAN busComputer fileWeb pageMaizeStatisticsNormal (geometry)Annulus (mathematics)EstimationPredictabilityHydraulic jumpDemo (music)Source codeSocial classMaxima and minimaCategory of beingWeb pageComputer fileVariable (mathematics)Flow separationModule (mathematics)Limit (category theory)ResultantAuthorizationWeb 2.0Configuration spaceSemiconductor memoryInstance (computer science)Rule of inferenceCodeLine (geometry)Object (grammar)Self-organizationVirtual machineMultiplication signInheritance (object-oriented programming)Software testingRevision controlSoftware frameworkWindowCASE <Informatik>System administratorDemo (music)Goodness of fitDirectory serviceOrder (biology)Functional (mathematics)NumberComputer animation
Data typeDemo (music)Attribute grammarFunction (mathematics)String (computer science)Boolean algebraMIDIFluidExecution unitReading (process)ForestMaß <Mathematik>Social classPlanar graphMenu (computing)AreaNeuroinformatikRule of inferenceVirtual machineComputer fontCategory of beingSet (mathematics)Validity (statistics)Read-only memoryBoolean algebraString (computer science)Software testingCodeWindowServer (computing)CuboidDoubling the cubeOrder (biology)MappingSocial classModule (mathematics)Computer fileReading (process)2 (number)Hash functionMechanism designTable (information)Error messageStructural loadSemiconductor memoryTemplate (C++)Configuration spaceMathematicsMultiplication signMereologyComputer animation
Function (mathematics)CodeEmailData structureComputer filePoint (geometry)Configuration spaceSoftware testingCodeMechanism designRevision controlSet (mathematics)Computer animation
Event horizonStress (mechanics)Directory serviceData structureMathematicsWeightPlanningSocial classSoftware developerComputer fileModule (mathematics)CodeLink (knot theory)WindowMultiplication signExpected valueRevision controlEndliche ModelltheorieComputer animation
Event horizonLink (knot theory)Inclusion mapWeb 2.0Computer fileMedical imagingModule (mathematics)Software testingCartesian coordinate systemWindowGraphical user interfaceRevision controlRight angleFlow separationSet (mathematics)Distribution (mathematics)QuicksortType theoryCodeSocial classComputer animation
Coma BerenicesXMLJSON
Transcript: English(auto-generated)
Good morning, everyone. Welcome to my 1045. Adam will throw stuff at me when I get too close to the end.
Yeah, yeah, I figured that. So in this session, I want to talk about the process of building, and why you would want to build, and how you would build a DSC resource. I only have a handful of slides, most of the time I will just be in demo mode and showing you everything.
Everything that I'm going to show you, and I have a link later, is up on the GitHub repo. So you can go and download all the files that I'm going to be showing you. So the first question is, why is DSC and DSC resources, why do they matter to me?
Well, I guess first I should make sure or ask, does everyone know what a DSC resource is? Everyone's good with that. So a DSC resource is a piece of code that you can use in a DSC configuration to say, I want this server to look like this. There are tons out of the box on the PS Gallery
that will do all sorts of amazing things. But there may be situations where you have some sort of in-house developed application, or some custom configuration. There's nothing out there in the gallery that will do what you need to do.
And that's perfectly fine. You all have amazing PowerShell skills so that you can solve that problem. That's why you're here. Or, and this may be more likely the case, because there are so many modules out there, many of them have been kind of, oh, we gotta get this out, gotta get this out.
I'm not gonna say name names, but some of them might be a little buggy. Or they might have functionality that is like 80% of what you need. Say, oh, this is so close, but I wish it could do this one other thing. Well, you can make your own copy of that module, of that resource, and customize it to meet your needs.
So those are kind of the two main reasons for me as to why you'd even want to go down this route of creating a custom DSC resource. Now, in order to do this, you have a couple choices. This is like your first decision point
that you have to make. So my talk here is supposed to be the whole start to finish process of building a DSC resource. And the first thing is, where am I going to deploy this? Because that's going to determine what approach you take. If you still have a bunch of servers running PowerShell version four,
then you have no choice. You need to use the traditional, what almost now is the legacy approach to building a DSC resource. And I'm going to walk through that so you can see what that looks like. This kind of gives you the most flexibility. One thing I will point out,
be careful on your authoring box with cross-platform connections. If your authoring box is running Windows 10 5.1, and your server is version four, and especially if you're in a push configuration mode,
there may be, I'm not saying there will be, but you might run into some weird error. I know when DSC first came out and PowerShell five first came out, and my client was still, I think Windows 8.1 at the time. So I had this cross-version issue
and I ran into some problems, oh crap. So your best, safest bet is make sure that your authoring box and all your managed nodes are all at the same level. That's the path of least resistance. Your other option, if you have PowerShell five or later on your servers, is a class-based resource.
And again, I'm going to walk through this as well. You can certainly build a resource in both fashions. In fact, I'm going to do that this morning. So you could still have a mix of v4 servers and v5 servers, and that's fine,
you have to keep that straight. But you can certainly do both. PowerShell core, well, I don't know. That's still to be determined. But I would imagine that the concepts and things I'm going to talk about won't change. The tooling might change. So we're not going to be talking about PowerShell core,
I'm going to be doing everything from a Windows 10 box talking to servers running 2016 server core. Now, your strategy here, when you, and this goes really for any PowerShell scripting
or tool making that you're going to do, start with a set of commands that you know already do the thing that you want to do. So if you want to be able to configure the timezone, you have to know the timezone utility commands in order to achieve that result. So start with PowerShell, that works.
Many of you probably already have a bunch of configuration scripts that you run to make something happen. That's great, because then you can take those and those become the basis of your DSC resource. Again, that's something I'm going to show you. This also applies to any CLI-based tool.
Build your scripts that rely on those tools, and more than likely the parameters in your functions or scripts, those are going to become the properties of your DSC resources. So if you build your scripts first, you're 80% done building your resource.
The whole point about a DSC resource is, if you can implement it from a command line, from a PowerShell prompt, you can build a DSC resource. But it has to be completely unattended. You can't have a command that requires prompts.
So it doesn't have to be a PowerShell command. Again, it can be if you have a third-party product, but they give you a command line tool to do its thing, great. You can just write a PowerShell function or a script wrapped around that executable, and you're on your way to building a resource off of it.
With a DSC resource, as most of you hopefully know, you have to be able to do three things. You have to be able to get whatever the configuration is that you are going to be creating. You need to have code that will set it, and you need to have code that will test it, that will basically say true or false.
This is in the state that I want it to be based upon the parameters that we're gonna pass in our code. And you have to decide what constitutes a pass, okay? So you've got something to configure. You have a set of tools, command line tools, that you can wrap in PowerShell code,
and you have to be able to do three things, get, set, and test. If you can do those things, now you're like 85 to 90% done in building a resource. The tools that we're going to use, well, we'll get into that,
will be the XDSC resource designer, and you're gonna use InvokeDSC resource. These are things that I use now all the time when I'm building custom resources, and this makes creating a resource fun. I used to dread doing a legacy resource
because of the requirements for the specific folder structure, and you need a schema.moff, and it's like, oh my god, it's so painful, and classes are so much easier. As you'll see in my demos, using the XDSC resource designer makes this a beautiful, simple, wonderful experience.
All right, so there's the link, and I'll have this again at the end for all of the demos that I'm doing. Any questions before I dive into the demos for the next hour and a half or so? No, okay.
Now the question, do I want to do this from, let's get out of my demo. Well, okay, I'm gonna look dangerously. I'm just gonna do it from here.
So right now, just so everyone understands my setup here, and this also explains if something goes wrong, it's why it went wrong, I'm running all my demos on my laptop, but the server that ultimately we'll be testing are in VMs running in a domain on my laptop.
So eventually I'll be using some remoting to using the VM bus to talk to that server. Hopefully it will all work. Okay, so we're gonna start with something really, really simple, and I always say, start with the code. So let's say that there is a,
I want to be able to use the get-windows-error-reporting commandlet. And what this does, oop, I won't do that. So right now, my system, and I'm testing everything on my laptop, is set so that Windows error reporting is turned on.
This is what turns on the reporting, so when errors, I think they get delivered to Microsoft. And it's just a simple boolean value, and if I wanted to, I also have a way that I can disable it or enable it. So I can turn it on and off. So in this case, I don't really have to build any PowerShell functions,
because I'm really gonna have a resource with one value, right? Enabled, or status, or whatever I wanted to call it, that's basically gonna be enabled or disabled. Although I suppose it could be true or false. But I have PowerShell code that I can run, so I have a way to turn it on,
to set it the way I want it to be. I've enabled or disabled, and the get is already built for me. And my test is basically, if it's supposed to be true, and if I do the get and it's false, then I'm not in configuration, otherwise I am in configuration. So in this case, it's brain dead simple,
I don't even need any other code around it. So we're gonna start with something basic. All right, now I'm gonna go to start building, and I'm gonna start with a class, I'm sorry, with a legacy approach. Go out to the gallery, and this is an open source project on the PowerShell gallery on GitHub,
XDSC Resource Designer. Does anyone use this? Well, more of you will be once you see how awesome this is. So go out, install it, I already have it installed. And when you run this, hopefully everyone can see that,
in the back you get a bunch of cmdlets that will be used to create an actual DSC resource. And that's what I'm going to walk through next. And I have a little link here if you need some other documentation
on what it means to design a resource. Now, every DSC resource has to have one property that is considered the key, which also makes it mandatory. Now in my case, I really only have one property that's gonna be my resource, and I'm going to call that property enabled,
and it's gonna be a boolean property, and I'm gonna make it an attribute key. And you are all smart enough to know how to read help for these commands, so I will trust that you will do that. So I'm gonna run that command, and this is going to create an object
that is just a DSC resource property, special type of object, but it's kind of like the thing that you would see when you run get DSC resource in the syntax, or if you were to look at parameter metadata, if you're diving into scripts
and building proxy functions, same type of thing. So this cmdlet creates that type of object, and as I get to my other demos, I can then repeat that process for other properties, but because my resource only has a single property,
let me get 128, come up here, come on. All right, so now what I'm going to do is I'm gonna create my resource. Again, this is a classic resource, and the DSC classic resource, you have to have a particular folder structure
and file structure and naming convention, and you have to create a schema.mov, and it's mind-numbingly liver-killing hard. This is amazing, so the name of my resource is gonna be mywer, Windows Ever Reporting.
I can then specify all the properties, in this case I just have the single property that enabled property I defined. I'm going to define the path where I'm gonna create this module, right now I'm just gonna create it in my local demo directory. The name of the module, and dash force,
because I want to, when I was developing this, I was redoing it, I need to overwrite what I've done. I'm not gonna run it because I already have it done, but that will then create, it might be, so that's gonna create this folder,
and then a subfolder, my DSC resources, here's the name of the resource. Now remember, when you're building a module, a DSC resource module, you may have multiple resources. There's kind of a hierarchy of things we're working with. I've got the properties that then get bundled
into a resource, and then that resource gets bundled into a module. You can have one resource per module, you may build like the XSMB share module that has several resources, or the Active Directory ones,
but we'll just have a single resource in a single module. And then this also created the actual PSM1 file, and the manifest, it created the schema.mov, which in this case is pretty simple. It gets more complicated the larger, more complex your resources become, but I didn't have to generate any of that code.
Because if you aren't careful, I mean, these mov files are very picky. So once you create these files, you don't have to edit them. If you decide, oh, I screwed something back up, fix your commands to run the DSC resource commands and just regenerate the stuff. Or what I do, if I've already started coding,
which is the next step, make a copy of that, regenerate, and then copy your code back over. So what I have created then is this module file,
and the resource designer will go ahead and create the outlines for the three functions that I need. So a classic or legacy-based DSC resource has three functions, and they are called,
and they're hard-coded into the DSC design, get target resource, which is pretty clear what that does, set target resource, and test target resource. And it will add all of the properties as parameters.
The commented blocks, the cmdlet added that, so it gives you clues as to how to use it. I added that code. That's all I needed to add, because all I need to do is get. And in this case, my get is just simply
running that command. And this is where I say, build your functions first to do all the getting and setting and stuff, because then you know that they work, and then you copy and paste them and adjust slightly as needed in the get, set, or test target resource function.
And I like that the command even gives you, in the comment, shows you what the sample result should be. Up here, you can see it's expecting a hash table, or in this case, the get is, I need to get the enabled property,
and I'm just getting that value from get windows error reporting, and assigning that and then returning that. Now normally, I'm not a big fan of using the return keyword, but in DSC resource design, that's perfectly acceptable.
And let me show you the, so the set then, it's pretty simple, right? I have, if it's set to be enabled, then run enable windows error reporting, otherwise, turn it off. And there's a comment there, if by chance you're doing something that requires a reboot, you can set that global variable, and then DSC will report back,
hey, this requires a reboot. And the test, again, is pretty simple. And it also then added the export. So running that command, once I defined what the properties were, generated the resource, generated all the functions, I just had to go in and add my code
to return whatever result I needed for that thing. The set target resource never returns anything. It just does its thing. Any questions so far? Once that is done,
then I can go ahead and, if I'm happy with the way the code looks, is I can copy this to my program files, Windows PowerShell directory, and I'm just gonna, I can just test this on my local box, or if you have some other development environment. So I'm gonna copy it to the right location.
And let's do that here, because I'm not sure if I've done it on this machine. Oh, and access is denied. And that's because I'm not elevated.
Now, wasn't the way in VS Code supposed to tell me, hey, try again, elevated? Where's that prompt? This is why I don't demo with VS Code. As much as I like it for development, I, just go back in.
Let's try this one more time. All right, so now I've copied it. So now I can test it. And there are a couple things to test. And these tests should just work,
unless you have ignored me, and said, oh yeah, I can modify the schema.mov. Because if you do, more likely you're gonna break it. But there is a command, the test XDSC schema, and you give it the path to the schema.mov. And we can just run that and it should return true, because I haven't touched that file.
And you can also test the XDSC resource, which will also return true or false. Now, to be honest, because I've not looked at the code for this command to see what it's actually doing, I have no idea what it's actually testing. But maybe I don't really care, because if I want to build some sort of pipeline
or some sort of pester test for stuff I'm doing, I can just use those commands for any sort of acceptance testing, and just know I got true or false makes it a nice, easy pester test. But what I can test is I can run get-dsc-resource for the resource I just created.
So there you can see, there's my resource, just the way that I can get any other resource. So that's a pretty good test.
So I've got the resource defined, and you can see it only took me a few minutes, really, to generate it. Now I'm going to test it. And I'm gonna be coming back to these commands. So the command we're gonna use here is called invoke-dsc-resource. This was introduced in version five, I think.
What this will allow you to do is to invoke the test set or get methods on a resource without having to build a configuration and push it and deploy it to the server. Now you still may want to do that at some point, but for quick and dirty testing,
hey, I need to make sure that my code and my functions work, this is what you're going to use. And what you set up is a hash table like this, and the keys in the hash table are basically the settings that you would have in your configuration. Just pretty straightforward.
So in my case, I'm gonna pretend that I would be testing with a DSC configuration using my WER resource, I set the enabled property to true. So let me make sure I run that, load that.
Now I'm going to invoke that resource, specify the name of the resource, the module that it's in. The method is the test set or get, the property, and I'm gonna go ahead and turn on verbose
and try to run this. So now it runs just as if you had deployed it through a DSC resource or DSC configuration. That's good, there's an exception there.
Well, that's helpful. Okay, so, well, I know that the test did not work. Okay, well, I'm gonna plow on. I'm gonna pretend those errors didn't happen because that's what you do, right?
Let's try the set property or set function. All right, so the set works, so now, now in this case, I'm actually doing it, so my system is set to be enabled,
and the get, all right, so it's enabled. I'm gonna try the test one more time, ah, okay.
So in that case, I must have, during my demos, I must have turned off Windows error reporting, and at least invoke DSC resource through an error because it didn't match. I may have to go back and look and see, maybe add some other error handling to suppress that,
but now at least I know the test works. I want it to be enabled, and it is enabled. So without really too much effort, again, I want to start with something really simple, one property in a very basic resource so you can kind of meet the tools and see the process
because now we're gonna get complicated. All right, so I have a more complex example, and I have built a set of functions
that use the SIM cmdlets to get the automatic page file settings. Most of the time, on servers, we just let Windows automatically take care of the page file. Well, but maybe I have to say, you know, I want to have control over the page file. So I have PowerShell commands that I can run
to get whether automatic page filing is turned on. I have code to turn it off. If it's turned off, then I can set a custom page file saying I want it to be initially this size and no larger than this size, right? So I have PowerShell code that I know already works
to do all of those things. Now, and it all runs remotely. I don't need to worry about the computer name parameter because that's part of the DSC, but for example, here's a set page file setting function. So I'm gonna want to create a resource
that will probably implement this code, which means those parameters other than computer name and pass through because I don't really need to see that. So I'm probably gonna have a resource with a parameter, or sorry, with properties of initial size and maximum size.
And it's also very, I think, very useful, if not almost required, to make sure you are using proper types for your parameters because they become very important when you go to doing DSC resources. So I have code that I know already works. I'm not going to demo that.
You'll just have to trust me. So I know in thinking about what I need to enable, I'm probably gonna need two resources. I'm gonna need one to basically turn on or off whether automatic page filing is enabled
because if it's enabled, then I can't create a custom one. So in my scenario, I'm thinking I want to create on server one a custom page file. So my configuration will eventually need two resources. One, and I'll have to use the depends on in the configuration, one to turn off automatic page file,
and then my next resource actually configure the new one. So that's kind of my little planning process. You can see I have my little notes there about what I need. And I also know that I have to have a key. So I'm gonna make the initial size of the key and maximum size, I'm gonna make that mandatory as well.
I probably don't really need to, but I decide for the sake of my resource, yeah, I'm gonna make that mandatory. So I'm now gonna create then, so I'm gonna build a whole new module. It's all over again building a new resource. So I'm gonna run the new DSC resource property
called enabled. It's an attribute of a key, and the type is a Boolean. I'm just piping this to T object just so you can see the output, but I'm gonna save it to a variable, all right? So that's what's in $p1.
So I'm building that first resource, which just has a single key. So I'm gonna build a resource called automatic managed page file just with that one property, and the module name is gonna be my page file setting.
All right, done, just built a module. But I want my module to have two resources, so let's add the second one. I need to create a new resource, so I'm gonna start with new property. So I need initial size.
There's that type from my parameter type in my function. This is a key. You can even add a little description if you want, which could be helpful because the value has to be in megabytes. So in developing this, well, how is it working?
Oh, it has to, then I had to go look in the WMI documentation and go, oh, it's expecting a value in megabytes. So I put that in as a description, and let's do the same thing for the maximum. All right, so boom, just created two new properties,
and let's create a property for name. Now, you can also add other properties to your resource. So I decided in testing and building my functions, I wanna be able to get the path for the page file.
Normally, it's C colon backslash pagefile.sys, but I wanna be able to get that. I'm gonna run get DSC resource. I wanna be able to see, or configuration, I wanna be able to see that. So I'm gonna create another resource property called name, which just has a read-only property
because I'm not gonna modify that. And now, I'm gonna create my second resource, this one called custom pagefile. I have my array of DSC resource properties that I defined, and I'm putting it in the same module that already exists,
and hopefully this will still work. And hopefully, that all took. So now, I've created a module that, or I should say, let me rephrase that. I've created a DSC resource module
that has two submodules, because each resource, like automatic and my custom, are separate modules. So I've got multiple PSM1 files. So if I can go to my automatic, this is similar to the Windows error reporting.
Oh, I did not edit this one. Oh, because I overwrote, but that's okay. I overwrote, and I did not make a backup of that. Well, that's not good.
So now, what I would do, except I'm not gonna do it now, I thought I had already saved that and not meant to overwrite it. Oh yeah, everything's up on, yeah, so I haven't lost it there,
and as long as I don't commit anything here, I'm good. So then I could take my code from my functions and paste it in and modify it as I need to so that I can meet the requirements that they have given me here,
because of course, now none of this is going to work.
All right, well, we're just gonna plow on, because that's what you do.
So same type of thing before. You can copy then the module, which I have completely destroyed now, so I can't do this part of the demo, but it kind of works. So I can deploy the module, copy to my directory, and I can now use invoke-dsc-resource,
again, create my custom hash table, run through invoke-dsc-resource with the resource name, the module, do the get, set, and test, make sure they all work, so I've done that for both of the resources. And then I can also go ahead and create a configuration.
Now, I'm getting the red squiggle, because I haven't copied the module to my program files modules directory. I'm not gonna run this anyway, because I don't have any code to run. You can see, you can use the custom resource just like you would any other resource.
And you would get the IntelliSense and all of that. So then copy it. Now, here's the next part, though, right? This is a custom resource that I built. Maybe, and I probably don't wanna deploy it to the PowerShell gallery,
but I still have to get the resource on the server in order for it to use it. Now, really, I don't really care how you do that, because where that server is may determine how you get it on there. But assuming you've got network connectivity, really, the easiest thing to do
is to just create a PowerShell remoting session and just copy that directory over PowerShell remoting to program files, Windows PowerShell modules. Don't put anything in system 32 or anything else, do it under program files, modules.
So that's what this code here, starting at line 99, I just have a hash table of parameters that I'm splatting to copy item. This assumes I've already set up my session to my server. So then that will copy all the module files from my machine to the remote machine over PowerShell remoting, which is an amazing thing.
And then once that's done, then I can just use the rest of my PowerShell DSC commands to start the configuration, push it to the server, and verify that it all works. Once it all works, it's up to me as to how I want to then deploy
to the rest of my servers. If I'm just in a pushed model, I can then use whatever mechanisms I have, it's up to push it. If you want, if you have a pull server, you just follow the normal procedures for packaging it and deploying it to your pull server. I tend to push things because it's a whole lot faster and easier.
But you can create a classic resource or module with multiple resources. And once you have the code, I know I keep harping on that, but that's because it makes your life so much easier. Because what you don't want to do
is to try to build all of the set tests, build this entire DSC resource classic module by hand from scratch. That will definitely destroy brain cells and your liver. Just don't do that.
But if you start with code that works already and learn how to use the XDSC resource designer commands, you can almost create scripts that will generate your resources for you. Let's do this.
We're doing it on time here. Oh, we're good. Any questions on the legacy class, you know, v4 type DSC resources? Yeah.
This is for if the managed node is running PowerShell 4, you have to use this approach and build this type of DSC resource. Now, absolutely, even if you're already running v5,
if you wanted to say, yeah, we're just gonna stick across the board to classic resources, that's fine. I used to think that, oh, just, if you're designing resources now, just go to classes, which I still think are cool, and that's what I'm gonna do next. But I'm still kind of debating,
telling someone what's the best approach. And maybe I can't tell you what the best approach is. James. Yeah, I've been really cool with this on at least one occasion where I've written a legacy resource on a PowerShell 5 machine, taken it over to PowerShell 4,
and then found that I was using a command that only came in with PowerShell 5. So really, if you're developing for 4, you need to keep a machine with 4 on it to do the development. Yeah. Otherwise, you get a certain way down and then you find that actually, you've written a resource that will only work on 5 in thinking you were being passed forward.
Yeah, and that's one of those little cross-platform things that can bite you, go, oh, I didn't realize that. And as I said, you can build resources to manage using any sort of tooling, but of course, that tooling has to be on the managed node.
So if you are running, creating a resource that's using some vendor-supplied CLI tool, obviously, that tool has to be available on the remote machine. That's up to you as to how that happens. And I'm assuming if you have some sort of custom app that's running on that server or product,
it already has the tools, but something to keep in mind. So you still have to verify that the remote machine has all of the bits that it needs in order to implement, and that's where using the invoke-dsc-resource comes in really handy, because then if it doesn't have something, then you should get error messages.
Or even before you get to that, you should already know that because you have built your PowerShell functions and commands that you have tested even before you start building your resource. So hopefully, you don't have those surprises, and all you're doing is validating that you put in the right keys and the right types and all of that.
Other questions? All right, so let's move then to class-based modules, DSC resources. And classes in PowerShell are actually pretty simple to use once you get your head around them.
I think developer types, this hurts them more than IT pros because this is PowerShell script, it's not Visual Studio, and it's not a full-blown .NET class that you would, but for our purposes, this is a beautiful thing.
So I'm gonna create a version of my page file resource, but I'm gonna turn it into a class. So we already know that the resource has certain properties, and I will show you how those translate into a class.
So what I have here first here in this demo file is just a sample class resource. I'll come back to the enums here in a moment. So to define a class, use the class keyword and then the name of your resource.
In this case, I'm just calling it my thing, okay? But in order for PowerShell to know that I'm building a resource, add that little attribute at the beginning, DSC resource. So now PowerShell knows, and it processes this, that this class is a resource. You can use classes for all sorts of other things,
and I do in other scripting, but you don't use that resource tag. You then need to define your key property. So in this, my little, this is basically my foo class. In this case, name. So I have that DSC property,
and I want it to be a key, so string $name. This is, there's no parameters. These properties are not parameters, so there's no commas after them. I then have a mandatory property called foo, and if you have other optional properties,
you still need to define them as a property, but you don't have to say if it's mandatory or a key. So in this case, I can take an array of strings. So you've got your properties in your resource, and then you have three methods. Now, the methods are just get, set, and test.
The set doesn't return anything, so you tell it it's returning nothing, so that's what the void is for. The test has to return a boolean, so you need to tell it your result is gonna be a boolean. And then the get has to return an instance of your type of class, so my thing.
Methods in classes have to use the return word. That's required. And as you're developing this, you'll see a little red squiggle saying something about no methods have been defined to return something, and that's because it's waiting for you to see the return.
You then have your code to update the this object, and we'll get to that in a second. So the set code eventually will have my PowerShell code to do the things that I want to do.
You use the $this reference to say, I'm talking about this instance of the class, of the object. And so the properties become like $this.name, $this.foo.
Now you can also use in, and I probably should have used this in my demo here, my class, you can also create your own enumerations. Many times, there are a lot of these resources that have a property of ensure, and the default is absent or present. So you can define your own enum,
and if I was smart, I would have gone through and added that as a property in my demo. Or, and I need to make sure that I didn't jump ahead too far. I don't think I did. No.
Or you can do this. I wrote a function that you can run to convert an existing class-based,
or I'm sorry, an existing v4 legacy-based resource and turn it into a class. And the way that this works is you specify the name of the resource and the module that it's in, and all my code does is go through and get the properties and create
a class-based version of that resource. Anyone wanna see that? Let's hope that this works.
Okay, so, I'm gonna, and I hope that I have this resource on this machine.
And I don't. It is xsmbshare for the module name, right? It's what? Oh, yeah. Thank you.
Now it's verified. All right, so now I have this xsmbshare resource. In fact, I'll show you what that looks like. So, this resource has those properties.
But I'm gonna convert this to a class. And as far as I know, this is still a v4. I should've verified that, but I think this is still a v4 class, or v4 resource. So, I'm gonna run my function and just send the contents to the clipboard.
New file.
So, that created the resource. I copied all of the properties over from the classic resource and made them the appropriate properties in my class. Even copied over the description.
They have a typo. That needs to be fixed. And then I also skeleton out the test set and get. And give you an idea for the get.
You need to have code, if you were to use this, where you can assign and update the properties of all of those settings. However you want to do that.
So, I can do the same thing with, say, my automatic manage page file, which is probably not gonna work because I didn't load that and I screwed that up. So, then I'm gonna run it because I know it's not there. But what I do have is once I copy that,
I can then paste that into a new module file. So, let's create a class-based version of my page file resource, or resources. This type of module is a traditional module.
So, I just have to have the folder name that matches, the PSM1 and the PSD1 file, the names all match. Just a regular module. I don't have to have any of that complicated directory structure that you do with the classic resources. So, you just go ahead, if you were scripting this out,
you can create your directory name, create your PSM1 file. And in this case, I can run my convert mof to class command and copy that content to the PSM1 file. So, these four lines of code will generate
a new class-based module based on v4 resource. And I already have this one created, so I'm not going to run this code other than, and that should be psc-cloud.
All right, so here then is the, after running that code,
this is what was generated into my module. Now, I still had to go back, though, and copy the actual code from the get, set, and test functions and paste them into the appropriate methods here. And then go through and modify
and make sure that I'm using $this to indicate this instance of the object. So, there's the test, set, and get.
And then here is the second resource. Remember, I've got one to turn on or off automatic page file, and then another one that creates the custom page file setting. So, this is the one for the custom page file setting.
Now, one thing that I like to do, especially when building class-based resources, is sometimes it's hard to see what's going on, even with invoked AC resource. So, you'll notice here that I have a number of right verbose lines, and I even include a little prefix to indicate that I'm in the class.
At the beginning of my file here, I can turn on or off the verbose pipeline. So, if I want to troubleshoot, say, what's going on, I want to trace the flow here, I can turn on the verbose pipeline, and then when I run my resource,
when I do it with verbose, when I hit the methods in the class with verbose lines, boom, now I see those. So, that makes it easy to understand, you know, is this even getting called, or where am I in the method here?
So, you see here, I have a verbose line saying, hit, I'm in the test method, and I'm querying the win32 page file setting class. I have some code that I can run to say, this is what I got back when I'm comparing. So, I can look at the actual values
that I'm getting back, and I can see that all in the verbose output. Once I'm all done with that, then I can go back in and turn off the verbose pipeline. So, from a development point of view, I use the right verbose statements all the time.
To me, that's the best way to debug. If I can see what it's doing without having to step through and jump out and roll over, I'm happy to do that.
Completely lost my place. Once I have that module all worked out
with the code that I think will work, then I need to go ahead and create a module manifest. So, here are the things in the module manifest. I'm just gonna run, normally, I'm not gonna actually run it because I've already done this, new module manifest, and I need to specify the path. So, the PSD1 file I'm gonna create,
the root module, which is the PSM1 file. Now, I know that this has to only, this is gonna require at least version five, I decided to make it five one, but this is the important thing that you have to do. When you're building a class-based resource, there's a property in the manifest
called DSC resources to export. If you don't put the names of your resources, you won't see them, they won't exist. So, you have to define the resource using that DSC resource tag in front of the class name, and you have to do this.
In a v4 or classic resource, you don't do any of that. The folder structure tells PowerShell, this is where the resources are. So, you don't have to do that, but this you do. So, if you are building a class-based resource and wondering, how come I don't see it,
check your manifest, and you should see, in fact, let me go, I'll open up the manifest, that I built, and down here, you have to have those lines. Otherwise, your resources don't exist.
So, this should all work. Let's hope. So, I'm gonna copy the... Now, the deployment is pretty much the same.
I'm gonna copy that class, that module, to my program files folder, and if all went well,
I should have a DSC resource for automatic manage page file two. You have to make sure that your resources have a unique name. All right, so there's the one resource. That's encouraging.
All right, so there are the syntax of my new resources class-based. Perfect. Now that I know that they are in the right places, I can test them. So, let's try to use InvokeDC resource.
So, again, this is like a sample configuration, the hash table of sending initial size and maximum size. Now, this might fail because I bet my page file is still set to automatic, but that's okay.
That looks pretty good. So, I'm not in the desired state, and if I do the get, error message error,
I wonder what that was, a warning. Oh, so there's a warning. I could probably have disabled the warning pipeline if I didn't want to, but I like seeing that there, because that's telling me that I can't really use this resource if the automatic page filing is turned on.
That's fine, because my result shows me that I'm not in that configuration. I'm okay with that. But, and the set will probably fail, because I need to do this. So, I were to set that to false.
I could then actually implement it, turn it off, then I could go back, and then I could set the custom page file. Once I know that all of those work, same type of thing, I can then copy it to my remote server, as long as it's running PowerShell 5 or later. I can then.
go into a remoting session and run InvokeDSC resource, and do all those testing that way. You could build a pester test for some sort of acceptance testing that would do all of that. Now one thing I will mention here about pester testing, since I have said that like four times already.
There is a nice reason, or good reason, to consider for the get, set, and test methods in your class, don't have all the code that does that stuff
inside the class. Because you can't really pester test a class. You can only pester test PowerShell functions and commands. Now hopefully you already know your code worse, because you've built it outside of, even before you start building your resources.
If I were to take this to the next step, once I know that this kind of works, maybe in the set, test, and get, is create a separate file that can be in the PSM1 file, that basically are my helper functions. Then my set, get, and test just basically have to call that command, that external helper function,
to do whatever it is I need to do. Because that I can build a pester test for. Then I can build a pester test to import my module, and pester test those functions. If I know those functions work, then as long as the get,
set, and test are running, which I can test with acceptance testing, with invoke DC resource, or other, however else you want to test it, I'm good. So think about, instead of, as I've done here, where I've actually put the code in the class, it might make more sense, especially the more complicated
your code gets, to move it outside of the class into a separate PowerShell set of functions that you can then actually test. My Windows error reporting, I'm probably OK with that inside the class, because it's one command.
And worst case, I can use my little verbose trick to see if it's actually getting called, and all of that. But think about moving all that code outside.
Questions so far? No one has left. Well, last thing then, this is going much faster than, well, it works, sessions really speed along
when the demos don't work. Oh, great, great. Give me a question. OK, thanks. OK, so it's a great question. The question is, what's its purpose?
What's going on behind the scenes? Well, what's going behind the scenes is whatever you decide. So the test, the way the DSC works, is I have some configuration I want to implement. And so I've got these settings, which are exposed as properties in the DSC resource.
When you go in and deploy a configuration, the first thing the resource does, the LCM does, is test the current configuration to make sure that, hey, you already configured the way that you want to be. And that's what you have to decide
what constitutes a test, or what constitutes a pass. So in my case, if I'm creating a resource or a configuration that wants to say, turn on the automatic page file, all my test has to do is have code to run the get sim instance commands
and look at the result for the page file setting class and its automatic page file turned on. If it is, return true. Otherwise, return false. So the test is DSC's way of verifying in configuration. When you go and run test DSC configuration, basically the test functions are getting implemented,
and it returns back the aggregate of whether your machine is in compliance. But what it actually is doing, at least when you're creating a custom thing, that's up to you. So it's saying, you have to decide what's pass. Yeah? One tip that I found doing this was that actually,
it helps sometimes not to just think of it as am I in compliance? Because if you come back and you say no, and I think this is what your page file one does, if you come back and say the settings aren't how I want them to be, then it will immediately go and run set.
You're right, right. Sometimes you can spot in the test that you're out of compliance, and you can write a warning there, but you can also say, and I can see I'm so badly out of compliance that running set is going to fade. So I'm gonna return true so that I don't run set
because I can see from the test that set will not work. And in a bunch of cases that I've met, I'll actually return true even though I'm out of compliance to prevent set doing something that's gonna be not what I want. But you have to make sure that you are providing feedback,
and when you are running any sort of like start DSC configuration or invoke the test, that you use the dash verbose output so that you can see that information. Absolutely, if you're going to do that, you've got to have tons and tons of write verboses, which is what you were doing in your example.
Yeah, and when you build your write verbose, one of the reasons I use the class, that little class little tag in the beginning of my message is so that it lines up nicer in the output, and I can look at it. So if you are using write verbose as a development technique, write your messages so that you can easily
read the display. And it's especially true with DSC resources because remember, all this is happening, in essence, out of sight, out of mind, unless you use dash verbose. In which case, I want to know what's going on. But I also don't want to have to try to struggle.
When you get old and crotchety like me, it's like, what the, what's going on on this machine? I want to be able to, at a glance, be able to see what is happening. Other questions, that's a good question. Yeah?
Does this lend itself to a flat or higher goal class structure? Classes do support some limited inheritance. So if you have a more complex setup, you can do that. I've been trying to keep things simple. And of course, my number one recommendation for you
if you are starting down this path is start really simple. Build a resource with only one or two or three properties. Don't try to build an active directory designed resource. Unless you really hate yourself.
But yes, you can. There are ways to do inheritance with classes. Sure, but does this lend itself to one or the other? That's my question. No. Do you have any other questions? I tend to, when I build a class-based resource, I tend to do it just like this. I haven't yet come up with a need
where I need anything more complicated than what I have in my demos here. I mean, I may add an enumeration or two, but that's about it. Also on my GitHub repo, if you want another example,
a year or so or even older, I built a class-based resource to configure PowerShell web access authorization rules based on the code that Jason Helmick had. He had some v4 stuff that kind of worked. I built a class-based module or resource around that. So if there's something else you want to look at as an example,
it's up on, actually, it's in the gallery, too. I forget what it's called, but it's something, at the time we were using the C naming convention, so it's like CPSWA authorization rules, but you can also see another example there. Yeah.
Yeah, the purpose of the GET, yes, is informational. So if you were to run DSC configuration, it's going to return back how that machine is configured. Remember, DSC is just a framework. For what you're defining in the GET. That's up to you.
Well, the GET has to return, in essence, the mandatory properties and the key property. It can also return additional information, such as, if we were to look in my code, like the name of the page file, in the class resource,
I think I probably glossed over this. Let me go back to the, all right, so that's the automatic.
All right, so if I'm creating my resource for creating the custom page file, I've got two properties that I have to define, the initial size and the maximum size. But I also have a DSC property there called not configurable that will return the name.
This makes it a read-only property. So in my GET code, what I need to return is an instance of my class, in this case, custom page file two. So I'm running my get some instance command.
If there is the name, which would be the name of the page file, then I can just set the value of this instance, $this.name equals the name of the page file, the initial size, maximum size. And then I just return that object at the end,
return $this. If it doesn't exist, if I didn't get a page file name, then I know, oh, automatic page filing must be turned on, and that's why I have that warning turned on.
And this is the kind of thing that he was talking about where maybe you want to, when I do the test, maybe I want to return true even though it's really not the case. In my situation for this class, so for the test,
so I'm getting the page file setting, because I had to decide what makes true. So in order for this to be true, the defined, the configured page size, initial page size, has to be equal
to what I'm expecting it to be, and the maximum size has to be what I'm expecting it to be. If both of those things are true, then I'm good. Otherwise, if either of those is out of whack, then I'm not in compliance. You decide whatever, how much code does it take
to decide true or false. No, they can. You don't really call the get.
I suppose you could. Get is for you as the administrator to go and say, show me how this thing is configured based upon what I think it should be. Yeah, you can do that.
And that's another reason for maybe moving all your code in the methods, move them outside the class so that you can test your test and develop separately.
Let me get the guy in the back here first, Mike. So to get the test, the methodology I think about is, the get is how I understand what it says here, right? So what does it look like right now? Exactly, yes. And I'll use some of that. Sometimes I'll take those variables and pass them into test and test with those variables. And that's how I tie the two together. You don't have to do that.
I understand that there were completely different scopes where you could actually just make a global variable from get and reference that from test. What does that mean? You could. I've seen classes where the first line in the text is variable equals get.
And then the result of the text is actually from pulling get first. Yeah, I like, I don't know. Well, we'll see what Mike says, because he's. The thing was deployed for my session at 4 p.m. and I understand that. Yeah, yeah, I don't want to do everything.
Otherwise, Mike will have nothing to talk about. Yeah. I haven't actually fought this for a few months now. So my memory of this particular issue that I think I haven't met could be wrong. But in looking at your example of the class-based resources you have your PSM1 module file there, which has both classes defined
for the two resources you want to expose. Yes. Organizationally speaking, I would much prefer to see one file per class. But my recollection is that there wasn't a way to pull those multiple files in to be able to expose,
like your PSM1 file would almost be more like a dummy file. You have your DSC resource classes and separate files get kind of pulled in but still exposed as. Yeah, I have run into issues, and of course, it depends on what version
of window PowerShell you're running. But yes, I have run into issues where if the class-based definition is in a separate file and I dot source in the PSM1, it doesn't seem to work. I, so I have taken to putting my PSM1 files, that's for the classes.
I've had mostly success with having, then dot sourcing my helper functions in a separate PS1 file. That mostly seems to work. But yeah, I have found it's easier to just put the class definitions all in one PSM1 file. That's not to say that might not change in the next release or something, but.
Maybe try to extract what that, the limitation of those methods, I guess that test method is almost purely to functions like you're kind of suggesting anyway to test the building, but also potential for benefits of code organization. Yeah, you know, you might find it easier to get started. Put everything in the PSM1 file
to make sure that everything works, and then see if you can, what will survive reorganizing the code. There's another. I have two questions. So, the first is when you're actually invoking your DSC resource to a session.
Well, what you can do, because invoke DSC resource is a way of saying, run this, load this resource into memory and run it like you would any other command. Now you may be running a, have something that you want to run that, and I can't run it on my Windows 10 desktop because it's on the server.
So all I need to do, I can still run an invoke DSC resource. Invoke DSC resource does not have a computer name parameter, but I can use remoting and run it on the remote machine from my Windows 10 box. That's what I'm talking about. So, double hop issues with some stuff that you might be setting up. Well, yeah, I don't know.
That might depend upon your resource. I guess I've not built any resources where I've run into that. And my second question is, what happens if in my test I, for whatever reason, it throws an error? Does it try to set anyways afterwards,
or does the whole DSC stop functioning? Well, are we talking about like running invoke DSC resource? Or when you're talking about a configuration? Okay, so if you have a resource, and the set fails, then it just fails, and you'll get a, that's why you want to,
as you're developing, you use, basically I push configurations, dash wait, dash verbose, with start DSC configuration, so I can see what it's doing. And yeah, it's just gonna fail. You can include your kind of code to have error handling, try catch, throw exceptions,
but you have to be able, you have to, as you're implementing that, you have to be able to watch for that. And like your second hop question, and you still, you would eventually want to do this anyway, is actually build a configuration, and do a test deployment to it, make sure that it all works. Invoke DSC resource is a great granular mechanism
to test one thing at a time. But at some point, you will still want to test the actual resource in a configuration to make sure that it works. Yes? If you're having a hard time writing the test part of the function,
or if you write it erroneously, and don't recognize it, will it just not generate, or will, that's what he's asking, I think, is what happens to the set if your test fails? It'll just, well, if your test, oh, wait a minute, I'm not sure I followed that question. You get an error. You get an error, right? And if you get an error, then you're failed, yeah.
Now the last thing I want to show you here is you can also create a class-based resource using the XDC resource cmdlets. Now those are designed to create legacy resources,
but I'm never satisfied with that. I like bending the rules. So this is just, again, kind of a sample. So I'm gonna create an array, and I'm gonna create a bunch of resource properties. The name's gonna be a string that's required.
Enabled is gonna be a boolean. I'm gonna create a property called setting. Oh, because you can also provide, so my little throwaway resource here, the setting property can require only apple, banana, or cherry, all right?
So those are the required settings. So you can add like a little validate set. The bar is gonna require, can take an array of strings, and the size is a string, which is gonna be read-only. So I can run my, create a DSC resource property for all of those settings.
And hope that that worked. Let's run, look at dollar props and see if it did. All right, so now I've created a bunch of DSC resources,
I'm sorry, resource properties using that module. So what I came up with next, in order for this to work, is a little mapping hash table.
Because remember, my ultimate goal is create a class-based resource, but I define the resources, resource properties using the commands. And now I'm going to go through each item,
and I'm going to create a little variable here called dollar items. You'll see how this looks in a second. Where in essence, I create the class-based definition from the legacy-based resource that I,
property that I defined with the resource designer. And then I can take each of those items, add the attribute, add the validate set, and then I have a here string that is the template.
Set that to the clipboard.
No, shoot, nope, that didn't work. That's the old stuff. Let's just run all of this.
There we go. So there I used the XDC resource designer to define my properties,
and then I got some magic code that then created a class-based resource out of it. Paste it into my file, and I'm good to go. Now I can add my other code, build my module file like I would anything else. So in essence, I kind of duplicated,
I took like the same code, so I include the little comment about if you needed to reboot. I thought that was kind of fun. In fact, I was going to wrap up and say, oh, you could create a plaster template, which is actually too bad, because they're talking about, oh, no, platypuses now. There's another plaster session, I think,
this week you should go to. So I thought, I'll just mention it, and I thought, no, I'm just going to make one. Anyone here use plaster? All right, so I created a plaster template that when I run this, get this to work great.
All right, so you can kind of see at the bottom here, it's asking me for the name of my new resource, and oh, I was going to call this here. Call the resource my foo keyword.
Let's say name, that's a string, and it needs to be ensured that it exists. Now the name of my module, my resource, module version,
and within seconds, if I can get this to work, get the whole line,
my plaster template created the manifest, the module, created all the class definition stuff. So there's the manifest. Here's the module, creates a read me,
creates a little license, a little change log, creates a pester outline. That's the really cool stuff with plaster. So you can create custom resources
really pretty easily. Let me come back here and wrap up some recommendations. When you're deciding which way should I go, probably traditional resources provide the least amount of problems.
Now, the most finicky, because you have to have that folder structure and the schema.mov and all of that, but now if you use the X resource designer, that simplifies that process. And now I'm not so hesitant to create that resource
now that I have this tool set and I understand how it works. That is a terrific thing to do. Write code that you can test with pester. If you're doing class-based stuff, make sure that I would move the mechanisms in your get, set, and test,
move them to external files that you can easily pester test. Ideally, you have built your code that works outside of a resource already, and then you're just kind of resourceifying, if that's a thing, your commands. Yes, sir?
I think there's some session. I know. No, I'm not gonna take the pain. Use invoke-decent-resource as much as you can. You have to obviously figure out
where you're gonna be authoring these things. Watch for version compatibility issues. If you have remoting needs, so let's say the thing that you are configuring is only gonna exist on a server, then use remoting capabilities to run invoke-decent-resource
either through a PS session, through invoke command. Ultimately, again, you'll still at some point want to run an actual configuration to make sure that everything works in that regard, but invoke-decent-resource is a great way for granularly testing the get, set, and test method.
And again, there's the link for all the demos, and then we have questions. Yes, no, I'll get out of the way. No one needs to see me. Yeah, way in the back. So, I'm talking about the traditional versus the class resource, right, sir?
Why? Why classes, why traditional, what do I get, should I keep code doing everything now, and the classes, should I be moving all my stuff to that, or is it a six or seven dozen or the other, it's just a new feature kit? You know, that's a great question. So, the question for those of you who didn't hear it is why would I use a class,
why did Microsoft introduce classes? And I think one of the reasons was to simplify the process so that you don't have that complicated, and some of this is just my opinion, so that you don't have that, you do not have to have that complicated directory structure and the schema.moth and all of that.
I think people who are developing resources, which tended to kind of like be developer types, wanted a class-based approach. They didn't like the PowerShell scripting approach, so they wanted something that was more devish.
I don't know, you have to have someone at Microsoft why they really decide. Some developer said, we want classes, so that's probably why. Yeah, Mike, Mike knows. Yeah, go to his session, he'll explain. I'm not gonna tell you, Mike will tell you. I'm just curious, the ultimate goal, right,
is should I be? The class-based one delineates the moth, which is the same as the moth file. Right, and this was all before this invoke XDC resource designer module came out. You know, if this had existed, I don't know if we ever really would have needed classes
because before this module, you had to do all of the stuff that I showed you all by hand, and it was incredibly tedious. You had to create the moth file by hand, and that moth file has to follow a specific format, which most IT pros don't really care at all about,
but you have to care enough because it has to work. Going forward, and this is where I've heard that the rumors are that maybe we don't really need to have class-based resources, and let's just stick with the traditional legacy approach, because now we've got some tooling
that makes it easier to create those things. I'm not aware necessarily of any performance benefit. I don't think that classes necessarily run any faster than a traditional resource, because ultimately you're still running your PowerShell code or your command line tools
under the hood. Those are gonna run the same speed regardless. There were some issues with versioning on class-based tools. But I think those have been resolved now. The big story is gonna be PowerShell Core,
because really, we all know Windows PowerShell 5.1 is done. So in essence, everything I've shown you is pretty much it. I don't expect DSA resources in version 5 or 5.1 to change.
Going forward with PowerShell Core, I think we'll see some additional changes in how DSA resources are built, and those may be class-based, I don't know. Some of it depends on the .NET framework, which as far as I know supports. I know it supports classes. I've run other modules,
and you can run other things in Windows 6, or PowerShell 6 on Windows that use classes, but we'll just have to see. Other questions? Oh, well, why didn't you tell me? Why don't you pipe up? You don't have any plans to get rid of either model. Developers definitely favor the classes,
because it's just a nice intuitive way for them to do it. For them, because they're dev. Exactly. It is simpler to maintain, because you don't have to worry about, oops, I forgot my schema file, things like that. But go whichever one's more comfortable. That's the idea. It's one of those classic times where Microsoft gives you five ways to do the same thing.
But go with one that feels more comfortable. Go with whatever is the simplest, and as you're building your first custom resources, again, can't stress this enough, start simple. Don't build a resource with 50 different properties, because you have to understand the structure
of whichever way you go. And the little nuances, like if you forget to export the DC resources in a class, you wonder, why doesn't this work? That's an easy thing to forget.
Yeah, I wish there was a way to have one module
that would have both, and then it would just determine, oh, you're running v4, you're running v5 or v1, but can't do that. Now, what you could do, though, is, again, you could start with, if you have a mixed environment, build your class base first,
and then use my code to convert it to a class, tweak it, and you're done. You then have, obviously, still have to control, make sure the right version gets to the right managed node, but I hopefully have given you a tool that you can create either type of resource that you need.
What else? Can we go back to when you were talking about externalizing the functionality? Uh-huh. In separate PS1 files, so the advantage is, you know, if you want to do that. Pasteur testing. Any gotchas, like, because I can imagine where, maybe I already had a test function that I wrote
as a PS1 in another module. Does that... Well, you don't want to, be very careful. So the question is, you know, if I am externalizing my get set and test code, you know, if I've got a test that's in another module, how might I use that?
I would not try personally to try to add another dependency. I hate dependencies. I like everything that I do to be where it is. If that requires me to copy and paste something, as much as I hate duplication of code, I will do that. I'm not, I hate dependencies. That's just me.
I'd rather install NT 4.0. So in the examples you provided, you're dealing purely in PowerShell, so you're changing Windows features. Yes. Your DSC is actually installing a binary or configuring, like, an application.
Would you include that in your module? No, you don't include the binary or anything. The only thing that's in your module are the command line tools, or the command line expressions, to achieve the three results, the get, set, and test. So, yeah, installation of stuff,
no, you don't, the module itself does not include setup files or anything like that. You would have to accommodate that elsewhere. You could provide a parameter, or a setting in your resource to say, this is the path to the ISO file, for example. That's fine. But you don't include that ISO image with your module.
So there's nothing preventing you, but I would not do that. What else? Yeah. So in theory, anything mixed, any configuration, you can use a set PowerShell command board, you can use DSC. Yeah, I don't see any reason. If I can type something at a command prompt,
through a PowerShell command, a VB, well, maybe not VB script, but a command line executable, if I can type it, I should be able to build a resource, run it, as long as you can do the get, set, and test. Yeah, let me see, why not? You've been covering like exchange configuration?
Sure, why not? Now remember, this all exists, though, out of sight, out of mind, so whatever commands you're running can't require any sort of user interaction, no GUI stuff, but as long as it's something you can run, in essence, unattended, yeah, you should be able to build a resource around it.
What else? Well, no one left, so this wasn't, I guess, a total waste. Anyway, so there's the link. I'm around through tomorrow, so if you want, talk more or ask more. And again, also, I said up on the GitHub repo,
if you drill down, you'll find the PowerShell Web Access resource I did last year or so, that's also class-based, if you wanna see how that works. Otherwise, I guess we are done here. Fill out your app, enjoy the rest of your day, and you have seven extra minutes.