Creating PowerShell Projects and more with Plaster
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
Pleau, Rob
Have you often sat staring off at all the other languages having fun scaffolding their projects with tools like Yeoman, dotnet CLI, or Visual Studio wishing you had something that cool in PowerShell? Wait no longer! With Plaster you can scaffold scripts, functions modules, anything!!!
 So, welcome to creating PowerShell projects in Moore with Plaster. A quick funny note about the title. When I originally submitted it, I had submitted it as let's get plastered. Richard contacted me and said that it might be hard for some folks to justify going to a conference where one of the sessions was let's get plastered. So I did change it, but I still got it in the slides. About me, I'm Rob. It's my Twitter handle. I have a blog that I don't update nearly enough. This presentation will be available on GitHub after today. It's on there now. It's just a private repo. So I'll open it up. I like mechanical keyboards. I'm talking about them after if you want. Yes, that's me with the horse mask. So what we're going to cover today, what plaster even is. How do we create a PowerShell module with Plaster? What's a Plaster manifest? Also kind of the black magic that makes everything work. We're going to create a better PowerShell module with Plaster. We're going to create some non-PowerShell things with Plaster. We'll do some extra stuff and time permitting. We'll look at questions. So long story short, the problem I had was I found myself every time I went to write a new module, I was spending a lot of time scaffolding it. And it's like creating the directory structure, creating the default Pester tests that I wanted to include for the module itself. I like to dot source my modules. So kind of part of that is I'd have a public and private folder for my functions, get in a manifest setup, the module manifest. And it was just tedious. It was a lot of copy and paste. And I was wasting a lot of time and I found it to be very error prone. So what did I do? I actually started writing my own scaffolding and it was about, I think, a week later at the Boston PowerShell user group. I learned that something existed called Plaster and I just decided to scrap what I worked on and use that instead because this was already done. Let's get to the code. So first off, I'm going to do this in VS Code. I picked the ISE theme for the holdouts that still use ISE. If this theme is not good, I can always change it to hotdog stand if you like that better. But if anyone longs for the windows 3.1 days, we'll stick with the ISE theme. So let's get started. I'm not going to do any typing because it's going to be massively error prone and I'm bad at typing. So I'm going to just kind of F8 my way through this. Again, this will all be available on GitHub. So you can find it on there. You can follow along. So we're not going to install it, I'm probably going to make an assumption that most people know how to do a module install from the PowerShell gallery. Just trust me, I already have it installed, the latest version and we're just going to roll with that. So we're going to skip that. So first things first, let's look at what it ships with. Not much. It's only got four functions. Most of them are pretty self-explanatory. We're going to use at least three of the four. We'll see about test plaster manifest. But that's it. There's not much. It's pretty accessible. So basically, like I said, plaster is used to scaffold any kind of coding project really. By default, it ships with a couple templates. So we have one for a script analyzer settings. We have one for a PowerShell module itself. A couple things you'll notice. This is kind of the metadata for the plaster templates themselves. One thing that I think is really important to call out is they're versionable. So if you put your plaster templates in source control, like we do where I work, that's kind of a nice thing. You can tag them for searchability. There's a couple things I'm going to call out about plaster that I don't like through this demo. So we'll talk about that. Has to do with the searchability. But you can also see where the template itself lives. So in this case, you can see they're just in my Windows PowerShell modules plaster. But they're just in that directory. And those are the ones it ships with. One thing I want to note, if you have your own, like I said, we do it where I work. They actually just have the one right now. You can specify a path where you store them. We just keep ours in their own Git repository. So that's the one we use at work. I'm not going to show you that. I'm going to show you something better. So that's about it. So now we're going to use it. The way my demo is set up, I just kind of have this fail-safe line for to make sure I'm always where I need to be. So first thing we're going to do, we're going to create a new module. We're going to call it PS Awesome because I'm bad at thinking in names. And it works. So we're going to need a place to put it. So for the sake of this demo, everything I create is going to go into this demo output directory. You could have this go right to a PS module path if you want. You could have it go to your desktop. You could really specify any destination path. But just to keep everything self-contained, we're going to do it in that demo directory in the output. So we have an empty directory now. Now here's the first quirk. I kind of mentioned it a little bit. Discoverability isn't the best. I don't know a better way to do it. Get plaster template doesn't really allow you to search well. And there's no find plaster template or anything like that. So I'm just doing a where object. And I know there was a built-in one with a tag of module. So that's the one we're going to use. And sure enough, there it is. That's the one we just looked at. You're at that break point I added. Just to make things a little concise, I'll just store these in variables. So let's get to it. Let's invoke plaster. So kind of the first command, you remember there's four. Invoke plaster is really kind of what kicks everything off. So we specified our destination path. We specified the template we want to use. We're going to run it. So first thing you'll notice, you get a nice little ASCII thing. It says plaster in the version. There's a no logo switch. You can use that. I figure someone spent a lot of hard time and effort making a nice logo for us and ASCII art there. So I'm going to keep it for most of these examples. But we're basically in a prompt now. We're in a menu and it's asking us what the name of the module we want to create is. The very little typing I'll do. So I enter the name of the module. We're going to call it PS Awesome. And the version number, it's going to default to 001. But let's call it 100. And then we kind of have a choice here. Select an editor for editor integration. If I don't know what that means, I can hit the question mark and see. So our choices are no editor specified or VS Code. I like to use VS Code because I can do hot dog theme. If I hit C, it'll take that choice. Again, it has a default. So if I just hit enter, it would have been that anyways. So I hit enter and you see some stuff happen. So we see a few creates. It created a PSD1 for us, a PSM1. Looks like it created some tests in a VS Code workspace. And the last thing there, it verified that we have at least Pester 403 installed. So let's take a look at what it actually created for us. I'm just going to scroll down here. Like I said, everything's going to go into output. So if I look here, I have my directory for PS Awesome and I have a VS Code editor workspace. I have this test. One thing I want to call out on the test. You'll see, look at line one. Somehow we got PS Awesome.PSD1. We got the module manifest referenced in there. I haven't done really any typing other than what I told Plaster to do. So we'll take a look at how that happened. It's a relatively simple test. I guess it's better than nothing. Created our manifest file. Remember we versioned this 100? We got that there. It was nice enough to generate a good for us. It took some other defaults. And then we'll look at the PSM1. Very simple. They're just kind of slamming through any kind of function that's start out star. Not ideal, but let's go ahead and create a function. So I have a usable module now. And I didn't have to do any of the setup. I didn't even have to write that Pester test. I can go ahead and import that. Again, I'm not going to worry about moving this to a PS module path. We're going to work right out of the demo. So I just specify the path to it. Let me scoot this up a little bit. You can see it's imported. We got version one. And as a command we just wrote. Again, I can see the command, not that it makes a huge difference. I can use that. Look at that. I already wrote one function for this thing. It didn't take us any time at all. And like I said, it shipped with some tests, so I'll just let it auto import. We'll invoke Pester on that directory. It's basically the Pester test is really simple. It just ships with. It's just going to do a test module manifest. I don't know why it's slow, but there it goes. And we're good to go. But basically, I was able to just start writing functions. I didn't have to waste any time doing all the setup. I really saved a lot of time. But anyone who's probably been doing modules for a while wants a little more flexibility, so slamming everything in the PSM1 and exporting anything that even remotely looks like a function, it's probably not ideal. And I kind of like a little bit better of a default module manifest test in my modules. So we're going to make this better. Before we do that, though, we're going to look at kind of what makes it all happen. That's a little thing called the plaster manifest. So let me reset here. So I'm actually just going to open the one we just ran. This isn't in the demo. It's in the, it ships with plaster. It's in the module itself. Uh-oh. Oh, okay. That way we're about to get hotdog-standard. So this is what a plaster template actually looks like. I'll just expand the whole thing. So we have the VS Code editor workspace. We have the test. That should look familiar. If you look at line one here on this template file, what you'll see is module.t.ps1 has kind of a weird name. We have some kind of funny looking stuff up at the top with the caret percent caret kind of syntax there. This is that kind of Lousy PSM1. But the manifest is really what drives it all. All right. Nobody's left yet. I know it's XML. XML is not my favorite thing. But this does drive everything when you do an invoke plaster. When I first started looking at this, it's kind of turned off by the fact it was XML. But I will say, having used it, the schema is very simple. There's three sections we're going to worry about. We'll talk about that real quick. And I have something that's going to make it even a little bit easier. So first section here is the metadata. And that's kind of similar to what we saw when we did get plaster manifest. So we have our versioning, much like a module manifest. We have a GUID associated with this, a title, a description, and author. So when you do a get plaster manifest, that's what you're seeing. The next section of the three sections is parameters. This is the questions we got asked. So we have module name. It's type is text. That was the prompt. Asked us to enter the module name. There was a version. You can see why it defaulted to 001 because it was declared that it defaulted to 001. And here's the choice we were asked, whether we wanted to do VS Code or none. For the, well, one thing too, plaster is PS Core compatible. So if you use a PowerShell Core and you want to make a plaster template, specify Vim, you could do that. But we took VS Code. And remember how none in VS Code had the brackets like N or C. If you see where that ampersand semicolon is, that's kind of what drives that. So based on what the user selects for the parameters, that's what content uses to actually make all the magic happen. So plaster ships with some built-in variables specific to it. Also every parameter in the parameter block up above, you can reference. You just have to do the capital plaster param and then the name of the parameter. So that module name is going to reference this right here. And VS Code is kind enough to highlight those when I select it. Content has a few sections, has messages, that's just an output of message to the user. But the important things you're going to see a lot of are file, template file, and new module manifest. The new module manifest really just drives creating the PSD1 file. It's very similar to doing new-module manifest in PowerShell. So pretty much any property available in the module manifest is available in this XML schema. There's only five there. And two of them aren't even specific to a module manifest. Plaster can actually set encoding for you. In this case, it's just going to do this UTF-8. And there's this open and editor flag. I haven't really used it. Basically VS Code is supposed to honor that. So when you open this, it pops that file up first. But here's a file. So file basically does a copy. And if you remember, we have this module PSM1. What it's going to do is basically copy that to the destination. That's it. Template file is similar to file where it'll do the copy. And it'll rename on the destination. So remember, our test didn't have this module.t name. But you can see when it copies it, it's going to put it in test. It's going to use the module name. And it's going to make it module name.test.ps1. And template file is responsible for doing what's called token replacement. So remember that weird percent caret syntax on line one of the tests. When a template file is processed by Plaster, it's going to do token replacement. And all the variables we see here that we can use, like Plaster param module name, those are available on the other side. Let's take a look at that in a second. And this is that require module that just made sure we had Pester installed. So remember I said that token replacement. So when template file processes this on line one, it's going to rip out that funny looking caret percent syntax. And it's actually going to put the module name in there. And that's the manifest. I'll show you where you can get some more info on that. And this probably won't work, but I want to try it. All the things, all the choices that are defined in parameter, ideally, it creates dynamic parameters on the fly. I'll just say there. Yeah, I probably won't. This is flaky. I guess this is kind of another quirk. You'll see it later example when we do the non-power shell project. You can specify those. You don't have to be prompted for it. You don't have to interactively enter any of the plaster parameters. You could just specify them up front. It would be good maybe if you're going to have something to your scaffolding that's not a human user. Maybe you're going to have some kind of pipeline to build these things. Kind of a bummer. I don't know. It won't work, but we'll try again later. As far as the manifest goes, you could go get this on the web. It's in the plaster GitHub, but if not, it ships with the pretty beefy about help, which I think is actually pretty helpful. It goes through all the sections we talked about, tells you all the options, has pretty great examples. Like I said, it ships with some built-in variables. You could see them there. You can always reference your own parameters with the plaster underscore parameter underscore name of it. We saw the tests doing that, but you don't have to be on the web. You could just grab the help there if you've already installed it. I don't want to spend too much time. XML is not the most exciting thing, but it is important to know what that file is doing and why it's so important, so I had to show you. We're going to make our own now. I remember there was only four commands. You could probably imagine that we've already used get plaster template and invoke plaster. I'll give you a guess as to what the next command we're going to use is. Yes, it's new plaster manifest. Here's the other quirk. I don't know if this is a bug in plaster. I haven't opened an issue on GitHub yet, but if I run, we're going to create a place to put it first. We're going to call this plaster template my custom module. I'm going to run new plaster manifest. You'll see I'm going to feed it the name of the plaster template. The template type, there's two. There's project and item. Projects for scaffolding, a whole project. If you just want to do a single file, you could use item. Again, templates are versioned. You can have a description and tags. I'm going to go ahead and run this. It's going to blow up. I have access to that path. If I mess with the path, we'll get a different error that's similarly obtuse. It's not ideal, but what we have to do, poor man's way, I'm going to go in the directory we created to create this. Like I said, I don't know if it's a bug. If anyone knows, if anyone's used this, let me know. I'm just going to rerun that command in the directory. We'll crack it open. We have a new plaster manifest file. With the information we provided, like I said, it's nice enough to make a good for us. Now we have to talk about XML again. Like I said, it's not ideal, but it is relatively simple. One thing that's included in this that you can grab on my GitHub if you're interested. I'm going to show you. I made this a little bit more tolerable to use. I created some snippets for VS Code. If you use the ISE, you're out of luck. But if you use VS Code, I made these nice snippets. If we want to create a parameter, and I want to create a choice parameter, I can just select that, and I can put the name, choice one. You can tap through it. I'm not going to put real stuff in there. I'm just showing you. It should save a lot of time. Likewise with content, you want to put a file or a template file. You go right ahead and do that. These will be included. I'm going to grab my GitHub. I just wanted to show you. I made the XML a little bit more tolerable. If you want to create new plaster manifest from scratch, at least you can shortcut some of the XML that way. I'm just going to zip back up to the root of my demo. We just looked at the, well, we could do that. That's the one we just created. But I'm going to take a page out of the cooking showbook. Even with the snippets, rather than just sitting here and watching me type XML for however long it would take me to get through that, I have a done plaster template for a better module. We're just going to jump right into that. Like I said, I like to dot source my functions. I want a slightly better module manifest, kind of meta test for the module. I don't want to get into a debate. The way our source control works, all of our builds look for a source directory. I know a lot of people like to keep the module name the same. So you don't have to rename it. I'll just show you what that looks like. But I create everything in the source directory. The tests live outside of that, the same level. I had to read me. One thing you're going to see, since we usually, the next step after we create something like this is we initialize a Git repository. Since Git can't track empty directories, I put these dummy.git-keep-biles in there. So you'll see that. But that's what they're doing. They really have no purpose for this demo. It's just if we were going to do a git init and send this up to VSTS or GitHub, it would keep those directories at least. So we're just going to call this very creatively. Level one. Give it a description. And we'll call it version one as well. So now you're going to see, unlike the last one, it's starting to ask us some more things. So we'll say nothing for a company name. We'll say the author is Summit. We'll just take some of the defaults. Here's a choice. If you want to specify in your PowerShell module manifest which version of PowerShell that your module requires, I've added that choice. So what we're going to do is, I want to say this one will be for Windows PowerShell. So we'll keep it 5.1. I like to add an about help for my modules. So do you want to include an ENUS with an about help subject? Definitely. So it's going to do that. So I've had a couple modules I had to ship third party libraries with. But for the case of this one, module one that we're making up here on the fly, we're not going to need that. We're not going to need any dependent JSON files or standalone scripts. We will default yes on the manifest pester tests. And of course, we'll take VS code as our editor. So it's going to go through. You can kind of see the folder structure it's creating here. It's the name, like I said, the function itself is going to live in the source directory. I have my pester tests in the test directory. I have my VS code. And I'm still doing the require at least version 403 of pester. We'll take a look at what this looks like. So here it is. I have my manifest tests. I found these, I think, from Warren's blog, someone's blog. And I've been using this kind of format ever since. The one thing I like to do, and you'll see, is that for each function in my public functions folder, I make sure it's exported in the module manifest. I can't tell you how many times I wrote a function, and I forgot to put it as an exported function in the manifest. So that's really, it does a lot of other validation. That's more or less what that's doing. You could see here, we're doing the, you know, we have a function directory with private and public. There's those dummy files, just in case we were to turn this into a Git repository, we wouldn't lose those directories. Here's our about help file. You could see it did some more of that token replacement, line two. It says about underscore module one. We didn't type that. Plaster did that for us. I have my pst one. And because I'm dot sourcing, there's a little bit more that needs to be done when the module loads up. So the psm one really just serves to unblock files if someone was to grab this from the internet. And there's where it's going to dot source, kind of import my private and public functions. So like before, what we can do, let's get rid of this. Let's create a function. We'll call it out. Hello, summit two dot psm one. Kind of ironic. I think it's funny. I'm just going to call it out. I could use plaster to scaffold functions. Just for the sake of this demo, I'm using the VS code snippets because it's just a little bit quicker. I just want to show you that you can have a working module right off the bat and you can start writing code without having to do any of the setup. So that's why I'm doing that. But you absolutely could use this to scaffold functions or pester tests. Let's get a little creative with this. Break some rules. We'll do a right host. Let's make this magenta. That's fun. I'll save it. Remember without sourcing, I have to export this. In my module one, I don't like to just star. I'm going to export my function there. At this point, if I go back in, if I go here, let's say I want to run the tests before I even try to run that function. I'll just show you. This is what my pester tests do when I include it. It just makes sure it runs script analyzer and pester to make sure I have no syntax errors. Like I said, I can't tell you how many times I forgot to export those functions only to get the module to a repository and then wonder where my function is that I just wrote. So we look good from that front. We're going to import this. Let's see what commands it ships with. Look at that. Out hello, summit two. Let's see what that sucker does. Whoa. Pretty cool. Long story short, though, I didn't spend any of the time. There's a lot of scaffolding here, a lot of directories, and I ran Plaster. It did the token replacement to get this created for us. Plaster manifest here is a little bit more involved. This is the one we just ran. You remember it asked a lot more questions. You can see those parameters right there, company name, author. Just serve later in the bottom you'll see to feed that module manifest section of content. You can ignore this. A little live edit there. Live on the edge. There was a bug a while back where you couldn't specify the PowerShell version in the manifest that would blow up, but they fixed it. I just didn't remove that comment. Here's the choice where we picked what PowerShell version we wanted. Nothing really special. It's similar to the Editor one. I'll show you in a multi-choice in a minute. Here's where it asked us about what directories we wanted. These are pretty simple. It was just kind of yes or no. Here's the editor. I just shamelessly poached the Editor one from the built-in. Content section. Here's where. I just wondered what that comment was. I don't think I added that. The new module manifest section, that's where it kind of puts all those properties in. When we specify we want to use PowerShell 6, you can see when it creates the module manifest for the actual PowerShell module, it would put that in or 5.1. We have a lot more template file going on here. You'll remember the about help template file kind of takes care of that tokenization for us. Remember when we specify any parameter really, not only can you reference it in the content, but you can reference it in PowerShell itself, in the files that are contained in the template. That's where we had the about help and had about the module name. This whole thing is token replaced. You don't have to do that. That's just the way I chose to do it. I just wanted this big here string block of text. You can see in there when it generates the about help file, that's how we got that. Here's some more token replacement going on. We'll look at that. We'll look at the more advanced one. This is roughly the same one. Just clean up, pick up our toys. Basically this is the exact same template we ran. We'll call it version 2. Now with class support and 100% more multi-choice. When I say class support, for anyone who knows me, I have beef with PowerShell classes. They're not exportable module members. They definitely are very helpful for DSC. When I want to do classes in my modules, I still write a.cs file and I add type it in the PSM1 when I do an import. From here you'll see I have a template.cs.ps1 and I'm using token replacement to create a really very simple C sharp class. I'm just declaring class. It's going to make the class name the same as the module when it generates this file. Like I said, we have multi-choice now. It's kind of annoying to have to keep saying yes or no to each directory. I'll show you how multi-choice works. You can specify a bunch of things in a single question. We'll do that right now. Call this module 2. We'll put some arbitrary. We'll call it 202. Keep that, keep that, keep that. We'll say this one's for PowerShell 6. This is a multi-choice. Again, if I have any confusion on what these options do, hopefully whoever created the plaster template and the manifest had help for it. If you did it, definitely put help for people using this who aren't yourself. Let's say we're definitely going to want to do an about help. Please give me a class file to start with. We'll just take those two options. Always yes on the tests and yes on the DS code. We'll scaffold module 2. What I'm not going to do is create another dummy function. I think you get the point. I could just go right into module 2. I could start coding. What I want to show you is I have a class directory. First I'll show you that because I have classes, I get child item on every CS file that's in that directory in the module. Like I said, I add type it so then it's usable. I'm not doing anything fancy with my C sharp classes. I just use them as plain old C sharp classes for creating an object that's not a PS custom object so I can pipe it to other functions. Remember we used token replacement to make the class name just reflect the module name. Then at this point I could go crazy, start making my C sharp class. But that's kind of what this did. Pester tests built in. Those are really the same tests we just ran. I just wanted to show you what a multi-choice looked like. We're going to see that again in just one minute. So you can actually use plaster. This doesn't have to be PowerShell. You saw scaffolding of a non-PowerShell thing by doing that, the C sharp class. The only thing, and it feels a little wonky, I don't know if there's a way around it, because you can actually embed PowerShell code and you can have logic in there. It doesn't just have to be straight variable token replacement. You can actually put if statements in your template files when you invoke plaster, it's going to run through that logic. So what I wanted to show you, we're going to scaffold something that's not PowerShell whatsoever. I then started to try and learn Go. I don't know if anyone in here is a Go fan. So I'm really bad at it. I just started trying to learn it. It's kind of weird. I'm not really a C sharp expert either. I know enough to probably be really dangerous. So we're going to scaffold a Go project. None of this at all has anything to do other than the fact we're using plaster to do it. It has nothing to do with PowerShell. It has nothing to do with anything in the.NET world. Go is made by Google. It's open source. It's a completely separate language, 100% unrelated to Microsoft. So let's take a look. I created this Go project plaster template. And I'm going to invoke plaster. So here you can see I have a project name. And that's not part of invoke plaster. Like I said, invoke plaster will actually look at your parameters and it'll create invoke plaster's parameters based on what's in that file. So here's one where I'm going to create, I'm going to just call it hello summit. I'm going to use no logo. We've seen enough of the logo. First question. It's going to ask us if this is the main or secondary package. So in Go, the first package has to be main. It's the entry point to your application. If I didn't know what these meant, I put some help. We're going to pick main because this is a new app. And there's a lot of Go packages have some common imports. It's like a using and C sharp or PowerShell. So I put some up here, format, OS and time. Let's just pick all three. And there's not much. We've got a lot less than our last one, but Go can be relatively simple. So it created a hello summit and a hello summit.go. Let me just make that a half. So I already have Go installed on my machine. I can do a Go run. It's similar to doing a.NET run. It's going to actually read the file, compile it and run it. And I'm just to show you that I used all three of those imports. It's using format to print out hello demo. It's using OS to get my machine name and it's using timed output at time. Very simple. But we basically just scaffolded something that's not related to PowerShell. It's not even a.NET thing. And we're able to run it. It's a Go application. The last thing is really just kind of miscellaneous stuff. It wasn't actually until late March. You can actually recursively search the modules you've installed for included plaster templates. So Michael here is in the front row. He was the first that I knew of. He has a plaster template in his module, Documentarian. I have it installed. I don't know if I have the latest version. I have 0.2. But you can see the plaster template he's included here. And I just think it's really cool that people can start including plaster templates in their modules and you can just walk your PS module path directories recursively and it'll find any. I know I've talked to some people here who are using plaster outside of Michael's but it's just kind of cool. That's really it. I think I've covered it all. If anyone has any questions, I'll take them. If you want to talk about keyboards, the VS Code's hot dog stand theme, we can do that as well. Yeah. So how do I get around finding the templates and extract the path? Doing get plaster templates, type, type, type, type is frustrating. So all I've really done, the question was how do I get around finding the plaster templates? We only really use one at work to do scaffold new modules. It's very similar to the second one we ran where it created the class file. The discoverability is pretty poor. We have a get directory. We just keep it there. If we ever had more plaster templates and get repo, I mean, if we had more plaster templates, we'd probably just throw them in the same get repo. And then when you clone that down, you just specify that path and then just pull out the one you want. I could open a GitHub issue because I think that's one thing they could improve is the discoverability of the plaster templates themselves. I know at one point I heard too that they were going to do, they're talking about having a central repository similar to the gallery where people could upload their plaster templates. I don't know if anything like that exists today, but it would be nice if there was a way to work with them similar how you can work with modules or scripts. But yeah, I just know where the directory lives for the get repo and I just grab them out of there. Did that answer your question? All right. Anybody else? All right. Well, that's it, kids. We made it. We did it. Right.
 So, welcome to creating PowerShell projects in Moore with Plaster.  A quick funny note about the title.  When I originally submitted it, I had submitted it as let's get plastered.  Richard contacted me and said that it might be hard for some folks to justify going to  a conference where one of the sessions was let's get plastered.  So I did change it, but I still got it in the slides.  About me, I'm Rob.  It's my Twitter handle.  I have a blog that I don't update nearly enough.  This presentation will be available on GitHub after today.  It's on there now.  It's just a private repo.  So I'll open it up.  I like mechanical keyboards.  I'm talking about them after if you want.  Yes, that's me with the horse mask.  So what we're going to cover today, what plaster even is.  How do we create a PowerShell module with Plaster?  What's a Plaster manifest?  Also kind of the black magic that makes everything work.  We're going to create a better PowerShell module with Plaster.  We're going to create some non-PowerShell things with Plaster.  We'll do some extra stuff and time permitting.  We'll look at questions.  So long story short, the problem I had was I found myself every time I went to write  a new module, I was spending a lot of time scaffolding it.  And it's like creating the directory structure, creating the default Pester tests that I wanted  to include for the module itself.  I like to dot source my modules.  So kind of part of that is I'd have a public and private folder for my functions, get in  a manifest setup, the module manifest.  And it was just tedious.  It was a lot of copy and paste.  And I was wasting a lot of time and I found it to be very error prone.  So what did I do?  I actually started writing my own scaffolding and it was about, I think, a week later at  the Boston PowerShell user group.  I learned that something existed called Plaster and I just decided to scrap what I worked  on and use that instead because this was already done.  Let's get to the code.  So first off, I'm going to do this in VS Code.  I picked the ISE theme for the holdouts that still use ISE.  If this theme is not good, I can always change it to hotdog stand if you like that better.  But if anyone longs for the windows 3.1 days, we'll stick with the ISE theme.  So let's get started.  I'm not going to do any typing because it's going to be massively error prone and I'm  bad at typing.  So I'm going to just kind of F8 my way through this.  Again, this will all be available on GitHub.  So you can find it on there.  You can follow along.  So we're not going to install it, I'm probably going to make an assumption that most people  know how to do a module install from the PowerShell gallery.  Just trust me, I already have it installed, the latest version and we're just going to  roll with that.  So we're going to skip that.  So first things first, let's look at what it ships with.  Not much.  It's only got four functions.  Most of them are pretty self-explanatory.  We're going to use at least three of the four.  We'll see about test plaster manifest.  But that's it.  There's not much.  It's pretty accessible.  So basically, like I said, plaster is used to scaffold any kind of coding project really.  By default, it ships with a couple templates.  So we have one for a script analyzer settings.  We have one for a PowerShell module itself.  A couple things you'll notice.  This is kind of the metadata for the plaster templates themselves.  One thing that I think is really important to call out is they're versionable.  So if you put your plaster templates in source control, like we do where I work, that's kind  of a nice thing.  You can tag them for searchability.  There's a couple things I'm going to call out about plaster that I don't like through  this demo.  So we'll talk about that.  Has to do with the searchability.  But you can also see where the template itself lives.  So in this case, you can see they're just in my Windows PowerShell modules plaster.  But they're just in that directory.  And those are the ones it ships with.  One thing I want to note, if you have your own, like I said, we do it where I work.  They actually just have the one right now.  You can specify a path where you store them.  We just keep ours in their own Git repository.  So that's the one we use at work.  I'm not going to show you that.  I'm going to show you something better.  So that's about it.  So now we're going to use it.  The way my demo is set up, I just kind of have this fail-safe line for to make sure I'm  always where I need to be.  So first thing we're going to do, we're going to create a new module.  We're going to call it PS Awesome because I'm bad at thinking in names.  And it works.  So we're going to need a place to put it.  So for the sake of this demo, everything I create is going to go into this demo output  directory.  You could have this go right to a PS module path if you want.  You could have it go to your desktop.  You could really specify any destination path.  But just to keep everything self-contained, we're going to do it in that demo directory  in the output.  So we have an empty directory now.  Now here's the first quirk.  I kind of mentioned it a little bit.  Discoverability isn't the best.  I don't know a better way to do it.  Get plaster template doesn't really allow you to search well.  And there's no find plaster template or anything like that.  So I'm just doing a where object.  And I know there was a built-in one with a tag of module.  So that's the one we're going to use.  And sure enough, there it is.  That's the one we just looked at.  You're at that break point I added.  Just to make things a little concise, I'll just store these in variables.  So let's get to it.  Let's invoke plaster.  So kind of the first command, you remember there's four.  Invoke plaster is really kind of what kicks everything off.  So we specified our destination path.  We specified the template we want to use.  We're going to run it.  So first thing you'll notice, you get a nice little ASCII thing.  It says plaster in the version.  There's a no logo switch.  You can use that.  I figure someone spent a lot of hard time and effort making a nice logo for us and ASCII  art there.  So I'm going to keep it for most of these examples.  But we're basically in a prompt now.  We're in a menu and it's asking us what the name of the module we want to create is.  The very little typing I'll do.  So I enter the name of the module.  We're going to call it PS Awesome.  And the version number, it's going to default to 001.  But let's call it 100.  And then we kind of have a choice here.  Select an editor for editor integration.  If I don't know what that means, I can hit the question mark and see.  So our choices are no editor specified or VS Code.  I like to use VS Code because I can do hot dog theme.  If I hit C, it'll take that choice.  Again, it has a default.  So if I just hit enter, it would have been that anyways.  So I hit enter and you see some stuff happen.  So we see a few creates.  It created a PSD1 for us, a PSM1.  Looks like it created some tests in a VS Code workspace.  And the last thing there, it verified that we have at least Pester 403 installed.  So let's take a look at what it actually created for us.  I'm just going to scroll down here.  Like I said, everything's going to go into output.  So if I look here, I have my directory for PS Awesome and I have a VS Code editor workspace.  I have this test.  One thing I want to call out on the test.  You'll see, look at line one.  Somehow we got PS Awesome.PSD1.  We got the module manifest referenced in there.  I haven't done really any typing other than what I told Plaster to do.  So we'll take a look at how that happened.  It's a relatively simple test.  I guess it's better than nothing.  Created our manifest file.  Remember we versioned this 100?  We got that there.  It was nice enough to generate a good for us.  It took some other defaults.  And then we'll look at the PSM1.  Very simple.  They're just kind of slamming through any kind of function that's start out star.  Not ideal, but let's go ahead and create a function.  So I have a usable module now.  And I didn't have to do any of the setup.  I didn't even have to write that Pester test.  I can go ahead and import that.  Again, I'm not going to worry about moving this to a PS module path.  We're going to work right out of the demo.  So I just specify the path to it.  Let me scoot this up a little bit.  You can see it's imported.  We got version one.  And as a command we just wrote.  Again, I can see the command, not that it makes a huge difference.  I can use that.  Look at that.  I already wrote one function for this thing.  It didn't take us any time at all.  And like I said, it shipped with some tests, so I'll just let it auto import.  We'll invoke Pester on that directory.  It's basically the Pester test is really simple.  It just ships with.  It's just going to do a test module manifest.  I don't know why it's slow, but there it goes.  And we're good to go.  But basically, I was able to just start writing functions.  I didn't have to waste any time doing all the setup.  I really saved a lot of time.  But anyone who's probably been doing modules for a while wants a little more flexibility,  so slamming everything in the PSM1 and exporting anything that even remotely looks like a function,  it's probably not ideal.  And I kind of like a little bit better of a default module manifest test in my modules.  So we're going to make this better.  Before we do that, though, we're going to look at kind of what makes it all happen.  That's a little thing called the plaster manifest.  So let me reset here.  So I'm actually just going to open the one we just ran.  This isn't in the demo.  It's in the, it ships with plaster.  It's in the module itself.  Uh-oh.  Oh, okay.  That way we're about to get hotdog-standard.  So this is what a plaster template actually looks like.  I'll just expand the whole thing.  So we have the VS Code editor workspace.  We have the test.  That should look familiar.  If you look at line one here on this template file, what you'll see is module.t.ps1 has  kind of a weird name.  We have some kind of funny looking stuff up at the top with the caret percent caret kind  of syntax there.  This is that kind of Lousy PSM1.  But the manifest is really what drives it all.  All right.  Nobody's left yet.  I know it's XML.  XML is not my favorite thing.  But this does drive everything when you do an invoke plaster.  When I first started looking at this, it's kind of turned off by the fact it was XML.  But I will say, having used it, the schema is very simple.  There's three sections we're going to worry about.  We'll talk about that real quick.  And I have something that's going to make it even a little bit easier.  So first section here is the metadata.  And that's kind of similar to what we saw when we did get plaster manifest.  So we have our versioning, much like a module manifest.  We have a GUID associated with this, a title, a description, and author.  So when you do a get plaster manifest, that's what you're seeing.  The next section of the three sections is parameters.  This is the questions we got asked.  So we have module name.  It's type is text.  That was the prompt.  Asked us to enter the module name.  There was a version.  You can see why it defaulted to 001 because it was declared that it defaulted to 001.  And here's the choice we were asked, whether we wanted to do VS Code or none.  For the, well, one thing too, plaster is PS Core compatible.  So if you use a PowerShell Core and you want to make a plaster template, specify Vim, you  could do that.  But we took VS Code.  And remember how none in VS Code had the brackets like N or C. If you see where that ampersand  semicolon is, that's kind of what drives that.  So based on what the user selects for the parameters, that's what content uses to actually  make all the magic happen.  So plaster ships with some built-in variables specific to it.  Also every parameter in the parameter block up above, you can reference.  You just have to do the capital plaster param and then the name of the parameter.  So that module name is going to reference this right here.  And VS Code is kind enough to highlight those when I select it.  Content has a few sections, has messages, that's just an output of message to the user.  But the important things you're going to see a lot of are file, template file, and new module  manifest.  The new module manifest really just drives creating the PSD1 file.  It's very similar to doing new-module manifest in PowerShell.  So pretty much any property available in the module manifest is available in this XML schema.  There's only five there.  And two of them aren't even specific to a module manifest.  Plaster can actually set encoding for you.  In this case, it's just going to do this UTF-8.  And there's this open and editor flag.  I haven't really used it.  Basically VS Code is supposed to honor that.  So when you open this, it pops that file up first.  But here's a file.  So file basically does a copy.  And if you remember, we have this module PSM1.  What it's going to do is basically copy that to the destination.  That's it.  Template file is similar to file where it'll do the copy.  And it'll rename on the destination.  So remember, our test didn't have this module.t name.  But you can see when it copies it, it's going to put it in test.  It's going to use the module name.  And it's going to make it module name.test.ps1.  And template file is responsible for doing what's called token replacement.  So remember that weird percent caret syntax on line one of the tests.  When a template file is processed by Plaster, it's going to do token replacement.  And all the variables we see here that we can use, like Plaster param module name, those  are available on the other side.  Let's take a look at that in a second.  And this is that require module that just made sure we had Pester installed.  So remember I said that token replacement.  So when template file processes this on line one, it's going to rip out that funny looking  caret percent syntax.  And it's actually going to put the module name in there.  And that's the manifest.  I'll show you where you can get some more info on that.  And this probably won't work, but I want to try it.  All the things, all the choices that are defined in parameter, ideally, it creates dynamic parameters  on the fly.  I'll just say there.  Yeah, I probably won't.  This is flaky.  I guess this is kind of another quirk.  You'll see it later example when we do the non-power shell project.  You can specify those.  You don't have to be prompted for it.  You don't have to interactively enter any of the plaster parameters.  You could just specify them up front.  It would be good maybe if you're going to have something to your scaffolding that's not  a human user.  Maybe you're going to have some kind of pipeline to build these things.  Kind of a bummer.  I don't know.  It won't work, but we'll try again later.  As far as the manifest goes, you could go get this on the web.  It's in the plaster GitHub, but if not, it ships with the pretty beefy about help, which  I think is actually pretty helpful.  It goes through all the sections we talked about, tells you all the options, has pretty  great examples.  Like I said, it ships with some built-in variables.  You could see them there.  You can always reference your own parameters with the plaster underscore parameter underscore  name of it.  We saw the tests doing that, but you don't have to be on the web.  You could just grab the help there if you've already installed it.  I don't want to spend too much time.  XML is not the most exciting thing, but it is important to know what that file is doing  and why it's so important, so I had to show you.  We're going to make our own now.  I remember there was only four commands.  You could probably imagine that we've already used get plaster template and invoke plaster.  I'll give you a guess as to what the next command we're going to use is.  Yes, it's new plaster manifest.  Here's the other quirk.  I don't know if this is a bug in plaster.  I haven't opened an issue on GitHub yet, but if I run, we're going to create a place to  put it first.  We're going to call this plaster template my custom module.  I'm going to run new plaster manifest.  You'll see I'm going to feed it the name of the plaster template.  The template type, there's two.  There's project and item.  Projects for scaffolding, a whole project.  If you just want to do a single file, you could use item.  Again, templates are versioned.  You can have a description and tags.  I'm going to go ahead and run this.  It's going to blow up.  I have access to that path.  If I mess with the path, we'll get a different error that's similarly obtuse.  It's not ideal, but what we have to do, poor man's way, I'm going to go in the directory  we created to create this.  Like I said, I don't know if it's a bug.  If anyone knows, if anyone's used this, let me know.  I'm just going to rerun that command in the directory.  We'll crack it open.  We have a new plaster manifest file.  With the information we provided, like I said, it's nice enough to make a good for us.  Now we have to talk about XML again.  Like I said, it's not ideal, but it is relatively simple.  One thing that's included in this that you can grab on my GitHub if you're interested.  I'm going to show you.  I made this a little bit more tolerable to use.  I created some snippets for VS Code.  If you use the ISE, you're out of luck.  But if you use VS Code, I made these nice snippets.  If we want to create a parameter, and I want to create a choice parameter, I can just select  that, and I can put the name, choice one.  You can tap through it.  I'm not going to put real stuff in there.  I'm just showing you.  It should save a lot of time.  Likewise with content, you want to put a file or a template file.  You go right ahead and do that.  These will be included.  I'm going to grab my GitHub.  I just wanted to show you.  I made the XML a little bit more tolerable.  If you want to create new plaster manifest from scratch, at least you can shortcut some  of the XML that way.  I'm just going to zip back up to the root of my demo.  We just looked at the, well, we could do that.  That's the one we just created.  But I'm going to take a page out of the cooking showbook.  Even with the snippets, rather than just sitting here and watching me type XML for however  long it would take me to get through that, I have a done plaster template for a better  module.  We're just going to jump right into that.  Like I said, I like to dot source my functions.  I want a slightly better module manifest, kind of meta test for the module.  I don't want to get into a debate.  The way our source control works, all of our builds look for a source directory.  I know a lot of people like to keep the module name the same.  So you don't have to rename it.  I'll just show you what that looks like.  But I create everything in the source directory.  The tests live outside of that, the same level.  I had to read me.  One thing you're going to see, since we usually, the next step after we create something like  this is we initialize a Git repository.  Since Git can't track empty directories, I put these dummy.git-keep-biles in there.  So you'll see that.  But that's what they're doing.  They really have no purpose for this demo.  It's just if we were going to do a git init and send this up to VSTS or GitHub, it would  keep those directories at least.  So we're just going to call this very creatively.  Level one.  Give it a description.  And we'll call it version one as well.  So now you're going to see, unlike the last one, it's starting to ask us some more things.  So we'll say nothing for a company name.  We'll say the author is Summit.  We'll just take some of the defaults.  Here's a choice.  If you want to specify in your PowerShell module manifest which version of PowerShell  that your module requires, I've added that choice.  So what we're going to do is, I want to say this one will be for Windows PowerShell.  So we'll keep it 5.1.  I like to add an about help for my modules.  So do you want to include an ENUS with an about help subject?  Definitely.  So it's going to do that.  So I've had a couple modules I had to ship third party libraries with.  But for the case of this one, module one that we're making up here on the fly, we're not  going to need that.  We're not going to need any dependent JSON files or standalone scripts.  We will default yes on the manifest pester tests.  And of course, we'll take VS code as our editor.  So it's going to go through.  You can kind of see the folder structure it's creating here.  It's the name, like I said, the function itself is going to live in the source directory.  I have my pester tests in the test directory.  I have my VS code.  And I'm still doing the require at least version 403 of pester.  We'll take a look at what this looks like.  So here it is.  I have my manifest tests.  I found these, I think, from Warren's blog, someone's blog.  And I've been using this kind of format ever since.  The one thing I like to do, and you'll see, is that for each function in my public functions  folder, I make sure it's exported in the module manifest.  I can't tell you how many times I wrote a function, and I forgot to put it as an exported  function in the manifest.  So that's really, it does a lot of other validation.  That's more or less what that's doing.  You could see here, we're doing the, you know, we have a function directory with private  and public.  There's those dummy files, just in case we were to turn this into a Git repository, we  wouldn't lose those directories.  Here's our about help file.  You could see it did some more of that token replacement, line two.  It says about underscore module one.  We didn't type that.  Plaster did that for us.  I have my pst one.  And because I'm dot sourcing, there's a little bit more that needs to be done when the module  loads up.  So the psm one really just serves to unblock files if someone was to grab this from the  internet.  And there's where it's going to dot source, kind of import my private and public functions.  So like before, what we can do, let's get rid of this.  Let's create a function.  We'll call it out.  Hello, summit two dot psm one.  Kind of ironic.  I think it's funny.  I'm just going to call it out.  I could use plaster to scaffold functions.  Just for the sake of this demo, I'm using the VS code snippets because it's just a  little bit quicker.  I just want to show you that you can have a working module right off the bat and you  can start writing code without having to do any of the setup.  So that's why I'm doing that.  But you absolutely could use this to scaffold functions or pester tests.  Let's get a little creative with this.  Break some rules.  We'll do a right host.  Let's make this magenta.  That's fun.  I'll save it.  Remember without sourcing, I have to export this.  In my module one, I don't like to just star.  I'm going to export my function there.  At this point, if I go back in, if I go here, let's say I want to run the tests before I  even try to run that function.  I'll just show you.  This is what my pester tests do when I include it.  It just makes sure it runs script analyzer and pester to make sure I have no syntax errors.  Like I said, I can't tell you how many times I forgot to export those functions only to  get the module to a repository and then wonder where my function is that I just wrote.  So we look good from that front.  We're going to import this.  Let's see what commands it ships with.  Look at that.  Out hello, summit two.  Let's see what that sucker does.  Whoa.  Pretty cool.  Long story short, though, I didn't spend any of the time.  There's a lot of scaffolding here, a lot of directories, and I ran Plaster.  It did the token replacement to get this created for us.  Plaster manifest here is a little bit more involved.  This is the one we just ran.  You remember it asked a lot more questions.  You can see those parameters right there, company name, author.  Just serve later in the bottom you'll see to feed that module manifest section of content.  You can ignore this.  A little live edit there.  Live on the edge.  There was a bug a while back where you couldn't specify the PowerShell version in the manifest  that would blow up, but they fixed it.  I just didn't remove that comment.  Here's the choice where we picked what PowerShell version we wanted.  Nothing really special.  It's similar to the Editor one.  I'll show you in a multi-choice in a minute.  Here's where it asked us about what directories we wanted.  These are pretty simple.  It was just kind of yes or no.  Here's the editor.  I just shamelessly poached the Editor one from the built-in.  Content section.  Here's where.  I just wondered what that comment was.  I don't think I added that.  The new module manifest section, that's where it kind of puts all those properties in.  When we specify we want to use PowerShell 6, you can see when it creates the module manifest  for the actual PowerShell module, it would put that in or 5.1.  We have a lot more template file going on here.  You'll remember the about help template file kind of takes care of that tokenization for  us.  Remember when we specify any parameter really, not only can you reference it in the content,  but you can reference it in PowerShell itself, in the files that are contained in the template.  That's where we had the about help and had about the module name.  This whole thing is token replaced.  You don't have to do that.  That's just the way I chose to do it.  I just wanted this big here string block of text.  You can see in there when it generates the about help file, that's how we got that.  Here's some more token replacement going on.  We'll look at that.  We'll look at the more advanced one.  This is roughly the same one.  Just clean up, pick up our toys.  Basically this is the exact same template we ran.  We'll call it version 2.  Now with class support and 100% more multi-choice.  When I say class support, for anyone who knows me, I have beef with PowerShell classes.  They're not exportable module members.  They definitely are very helpful for DSC.  When I want to do classes in my modules, I still write a.cs file and I add type it in  the PSM1 when I do an import.  From here you'll see I have a template.cs.ps1 and I'm using token replacement to create  a really very simple C sharp class.  I'm just declaring class.  It's going to make the class name the same as the module when it generates this file.  Like I said, we have multi-choice now.  It's kind of annoying to have to keep saying yes or no to each directory.  I'll show you how multi-choice works.  You can specify a bunch of things in a single question.  We'll do that right now.  Call this module 2.  We'll put some arbitrary.  We'll call it 202.  Keep that, keep that, keep that.  We'll say this one's for PowerShell 6.  This is a multi-choice.  Again, if I have any confusion on what these options do, hopefully whoever created the  plaster template and the manifest had help for it.  If you did it, definitely put help for people using this who aren't yourself.  Let's say we're definitely going to want to do an about help.  Please give me a class file to start with.  We'll just take those two options.  Always yes on the tests and yes on the DS code.  We'll scaffold module 2.  What I'm not going to do is create another dummy function.  I think you get the point.  I could just go right into module 2.  I could start coding.  What I want to show you is I have a class directory.  First I'll show you that because I have classes, I get child item on every CS file that's in  that directory in the module.  Like I said, I add type it so then it's usable.  I'm not doing anything fancy with my C sharp classes.  I just use them as plain old C sharp classes for creating an object that's not a PS custom  object so I can pipe it to other functions.  Remember we used token replacement to make the class name just reflect the module name.  Then at this point I could go crazy, start making my C sharp class.  But that's kind of what this did.  Pester tests built in.  Those are really the same tests we just ran.  I just wanted to show you what a multi-choice looked like.  We're going to see that again in just one minute.  So you can actually use plaster.  This doesn't have to be PowerShell.  You saw scaffolding of a non-PowerShell thing by doing that, the C sharp class.  The only thing, and it feels a little wonky, I don't know if there's a way around it, because  you can actually embed PowerShell code and you can have logic in there.  It doesn't just have to be straight variable token replacement.  You can actually put if statements in your template files when you invoke plaster, it's  going to run through that logic.  So what I wanted to show you, we're going to scaffold something that's not PowerShell  whatsoever.  I then started to try and learn Go.  I don't know if anyone in here is a Go fan.  So I'm really bad at it.  I just started trying to learn it.  It's kind of weird.  I'm not really a C sharp expert either.  I know enough to probably be really dangerous.  So we're going to scaffold a Go project.  None of this at all has anything to do other than the fact we're using plaster to do it.  It has nothing to do with PowerShell.  It has nothing to do with anything in the.NET world.  Go is made by Google.  It's open source.  It's a completely separate language, 100% unrelated to Microsoft.  So let's take a look.  I created this Go project plaster template.  And I'm going to invoke plaster.  So here you can see I have a project name.  And that's not part of invoke plaster.  Like I said, invoke plaster will actually look at your parameters and it'll create invoke  plaster's parameters based on what's in that file.  So here's one where I'm going to create, I'm going to just call it hello summit.  I'm going to use no logo.  We've seen enough of the logo.  First question.  It's going to ask us if this is the main or secondary package.  So in Go, the first package has to be main.  It's the entry point to your application.  If I didn't know what these meant, I put some help.  We're going to pick main because this is a new app.  And there's a lot of Go packages have some common imports.  It's like a using and C sharp or PowerShell.  So I put some up here, format, OS and time.  Let's just pick all three.  And there's not much.  We've got a lot less than our last one, but Go can be relatively simple.  So it created a hello summit and a hello summit.go.  Let me just make that a half.  So I already have Go installed on my machine.  I can do a Go run.  It's similar to doing a.NET run.  It's going to actually read the file, compile it and run it.  And I'm just to show you that I used all three of those imports.  It's using format to print out hello demo.  It's using OS to get my machine name and it's using timed output at time.  Very simple.  But we basically just scaffolded something that's not related to PowerShell.  It's not even a.NET thing.  And we're able to run it.  It's a Go application.  The last thing is really just kind of miscellaneous stuff.  It wasn't actually until late March.  You can actually recursively search the modules you've installed for included plaster templates.  So Michael here is in the front row.  He was the first that I knew of.  He has a plaster template in his module, Documentarian.  I have it installed.  I don't know if I have the latest version.  I have 0.2.  But you can see the plaster template he's included here.  And I just think it's really cool that people can start including plaster templates in their  modules and you can just walk your PS module path directories recursively and it'll find  any.  I know I've talked to some people here who are using plaster outside of Michael's but  it's just kind of cool.  That's really it.  I think I've covered it all.  If anyone has any questions, I'll take them.  If you want to talk about keyboards, the VS Code's hot dog stand theme, we can do that  as well.  Yeah.  So how do I get around finding the templates and extract the path?  Doing get plaster templates, type, type, type, type is frustrating.  So all I've really done, the question was how do I get around finding the plaster templates?  We only really use one at work to do scaffold new modules.  It's very similar to the second one we ran where it created the class file.  The discoverability is pretty poor.  We have a get directory.  We just keep it there.  If we ever had more plaster templates and get repo, I mean, if we had more plaster templates,  we'd probably just throw them in the same get repo.  And then when you clone that down, you just specify that path and then just pull out the  one you want.  I could open a GitHub issue because I think that's one thing they could improve is the  discoverability of the plaster templates themselves.  I know at one point I heard too that they were going to do, they're talking about having  a central repository similar to the gallery where people could upload their plaster templates.  I don't know if anything like that exists today, but it would be nice if there was a  way to work with them similar how you can work with modules or scripts.  But yeah, I just know where the directory lives for the get repo and I just grab them  out of there.  Did that answer your question?  All right.  Anybody else?  All right.  Well, that's it, kids.  We made it.  We did it.  Right.
Creating_PowerShell_Projects_and_more_with_Plaster_0_59.png Creating_PowerShell_Projects_and_more_with_Plaster_60_131.png Creating_PowerShell_Projects_and_more_with_Plaster_132_239.png Creating_PowerShell_Projects_and_more_with_Plaster_240_887.png Creating_PowerShell_Projects_and_more_with_Plaster_888_995.png Creating_PowerShell_Projects_and_more_with_Plaster_996_1607.png Creating_PowerShell_Projects_and_more_with_Plaster_1608_4115.png Creating_PowerShell_Projects_and_more_with_Plaster_4116_4307.png Creating_PowerShell_Projects_and_more_with_Plaster_4308_11687.png Creating_PowerShell_Projects_and_more_with_Plaster_11688_11891.png Creating_PowerShell_Projects_and_more_with_Plaster_11892_12311.png Creating_PowerShell_Projects_and_more_with_Plaster_12312_12851.png Creating_PowerShell_Projects_and_more_with_Plaster_12852_15323.png Creating_PowerShell_Projects_and_more_with_Plaster_15324_17855.png Creating_PowerShell_Projects_and_more_with_Plaster_17856_18899.png Creating_PowerShell_Projects_and_more_with_Plaster_18900_20159.png Creating_PowerShell_Projects_and_more_with_Plaster_20160_20615.png Creating_PowerShell_Projects_and_more_with_Plaster_20616_21587.png Creating_PowerShell_Projects_and_more_with_Plaster_21588_22307.png Creating_PowerShell_Projects_and_more_with_Plaster_22308_22571.png Creating_PowerShell_Projects_and_more_with_Plaster_22572_23699.png Creating_PowerShell_Projects_and_more_with_Plaster_23700_23963.png Creating_PowerShell_Projects_and_more_with_Plaster_23964_27455.png Creating_PowerShell_Projects_and_more_with_Plaster_27456_27551.png Creating_PowerShell_Projects_and_more_with_Plaster_27552_27599.png Creating_PowerShell_Projects_and_more_with_Plaster_27600_27695.png Creating_PowerShell_Projects_and_more_with_Plaster_27696_27755.png Creating_PowerShell_Projects_and_more_with_Plaster_27756_30659.png Creating_PowerShell_Projects_and_more_with_Plaster_30660_32891.png Creating_PowerShell_Projects_and_more_with_Plaster_32892_35135.png Creating_PowerShell_Projects_and_more_with_Plaster_35136_35783.png Creating_PowerShell_Projects_and_more_with_Plaster_35784_36407.png Creating_PowerShell_Projects_and_more_with_Plaster_36408_36467.png Creating_PowerShell_Projects_and_more_with_Plaster_36468_36683.png Creating_PowerShell_Projects_and_more_with_Plaster_36684_36755.png Creating_PowerShell_Projects_and_more_with_Plaster_36756_37007.png Creating_PowerShell_Projects_and_more_with_Plaster_37008_37091.png Creating_PowerShell_Projects_and_more_with_Plaster_37092_37163.png Creating_PowerShell_Projects_and_more_with_Plaster_37164_37607.png Creating_PowerShell_Projects_and_more_with_Plaster_37608_41399.png Creating_PowerShell_Projects_and_more_with_Plaster_41400_43835.png Creating_PowerShell_Projects_and_more_with_Plaster_43836_45179.png Creating_PowerShell_Projects_and_more_with_Plaster_45180_46775.png Creating_PowerShell_Projects_and_more_with_Plaster_46776_47771.png Creating_PowerShell_Projects_and_more_with_Plaster_47772_56531.png Creating_PowerShell_Projects_and_more_with_Plaster_56532_62531.png Creating_PowerShell_Projects_and_more_with_Plaster_62532_62687.png Creating_PowerShell_Projects_and_more_with_Plaster_62688_62722.png