Developing with PowerShell Classes: Here be Dragons by Brandon Olin

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
you so afternoon everyone my name is Brandon Olin deaf black ops on Twitter this session is about developing with partial classes and here be dragons and this what this really means is what are some of the gotchas that you're more than likely gonna find or at least these are all the things that I found when working with classes and developing with them and creating modules with them so hopefully this is useful to you and this will help guide you when you actually if you do start using them what not to do or you know if you if you do like pain and suffering go ahead these links go to speaker deck and to the github repo for these for these demos the slide this is like five slides so it's useless but the github repo will have all the demo code that I have here so here's our agenda what our power stroke classes I'm gonna give a very brief overview of what they are this session is not really about how to write classes if you went to Jeremy's session about his Infoblox right there he did a good overview of more in depth about classes themselves and what you can do with them this is more about okay after you've decided to use them and you have them what are the headaches you're probably going to run into importing them sharing them with other modules and all that kind of stuff so hopefully that these kind of tight I think pretty well together I'll go over a little bit about why you would use classes and really the bulk of this is all these gotchas and there's a few more of these about what you're probably probably going to encounter and then hopefully we got a little time for Q&A at the end so here's an example or two examples of what a really basic class is on the left hand side you see we have a class that defines what a car will look like and a couple basic properties about that car manufacturer model and year and a method that operates on that class called drive and it obviously you know does what it says it does and at the very bottom is how you would instantiate that class with with the new method one of the ways you can do this on the right hand side is a little bit more advanced stuff aware you can do with classes and this is where you actually start getting more of the benefit of using them is code reuse is I want to create a new class called a Tesla obviously it's gonna inherit a lot of the properties from a car class it's also going to define a couple new ones max speed range and so forth and then we're going to set those when we when we on the default constructor on constructor on this class we're going to set some properties on it this is just really a basic example of what you would do with the class but why would you want to actually use classes I kind of think of it as once you start using PowerShell to create applications versus admin scripts that are pretty linear you start you're starting to move morph into the realm of development and you start need to think about some of these more developing type terms I'm not a developer I've just I know a little C sharp I know some JavaScript I hate it I didn't go to college I'm a I didn't go to college I'm a dumb marine so yeah I've just learned that stuff my trial trial and error and sheer force of will but the main reasons you would use a class is separation of concerns you want to you want this instance of a class to do one thing another class has a different separate set of concerns off it does something entirely differently you don't want these code this code to bleed into each other and this is really about just code reuse and keep you things tidy and orderly and this is much more important when you start developing big applications you need to cordon off what these things do from each other that's it for the slides so demo is really about now you know everything you need to know about how to use the class right okay I'm gonna run through hopefully I have time to run through these twelve scenarios about classes and this intentionally shows you a lot of red and this is a to hide my errors and to fool you but this is really to show you what you're probably going to see once you start using classes and try to work with them this is the stuff you're gonna see and how to work around them so the first scenario here is we all know what import module does imports modules let's say I have a class in a module let's look at this this is my class very basic module has a manifest nothing special there nothing special really in the PSM one it has a class called foo we want to use that class in our Power Cell session well you would think we've all done this we want to use a function or something of a module we import the module and expect that to work do you think that's you think that's gonna work yeah I can't type no of course it doesn't work unable to find type foo why is that there's does anyone actually know that the true reason why that doesn't work I actually don't know the true technical reason if Bruce pyat was in here you probably tell me why I just know it doesn't export the class if you actually dig into the powerful code for import module and using module does you'll probably find out why that is but the gist of it is class is the raw class isn't and the type is not exposed we need to import the module so how do we work around that stealing my thunder using class which was introduced in PowerShell 5 is how are using module I should say is how you would use a module with the class in it let's run let's see what this does and this is a and there's all kinds of gotchas with using module and I'll go over some of them so but this worked this is how you would use a module it will import the module expose that class to your session and now I have access to the raw class type and I can instantiate an instance of it and you can see that it did actually import the my class module so great right you think that ok using module is the answer for all of this no this is and this is where how you were using an info Bacchus module is you can hide all your classes in internally to the module and expose them with just normal partial functions or commandlets let's see what this does and so actually let's let's look at this car module should probably do that this is what I tend to do with my modules is I like to break them up into small little pieces I have public and private in classes and separate files and I think most people do that probably now is that true yeah I like to be tight I don't like a 10,000 line PSM one let's see if this works so I have a class folder I have a simple class called car that's in that my PS m1 dot sources that class file when it imports and then I have a normal power cell function that will create an instance of that car set some properties and then return it so this is this is my this new car function is my way of interacting with with this this class so you can see that work I imported the module I created a new class anyway it's supposed to say an instance of a class do a get member I can see its car I can do everything I want this is a normal power soil object at this point oops script scope it you can see that I can fight that and format list for my table whatever you want to do with that like any other object so that gets around one problem with class is not being exposed from the modules you basically expose them with a function which means you also have to write new function or you have to create a function that new new something to create an instance of your class and give it back to you these could these uh these scenarios kind of go in order of complexity so here's a here's a gnarly one so let's say I have so I have a car class and I have a Tesla or a car module and a Tesla module this Tesla module is completely separate from the car but I want to extend the car for whatever reason I have that someone exposes created this really nice class I want to be able to use it my stuff in my own module I want to be able to inherit from it can you do that let's actually just put these in my path real quick so I'm gonna import Tesla and it doesn't work and why is that anyone have a guess that's good this is how you would normally define a dependency in a module right in the manifest you required modules I had that I required the module by then network it should have imported car before it loaded Tesla what's that I had no idea to say it's the same problem as import module because internally to PowerShell required modules is probably just running an import module or some variation of it so you run into the same issue and the steam of all these things this is a lot of these things stem from that core problem right there so the dragon in this is that ya required modules does not expose the classes just like the import module does same problem as scenario one and you also find with developing with classes at least I I'll be setting up a class and tweaking it oftentimes I get in a weird state and I just end up restarting my session just to make everything sane so let's add so we'll fix the teflon module so we had a heart all right so let's so we had a hard dependency on the on the car module with the required modules in the manifest so let's remove that because we know that that doesn't work so let's comment this out and inside and we'll create a soft dependency and you really shouldn't do this but so now inside when I import that module I'm gonna I'm gonna assume that car is already on the machine and I have to assume that here and there's other issues but doing this now things like pious calorie and stuff you try to him publish these to them all to the powerful gallery you're not telling the gallery that you have it dependency on this other module that's completely hidden from those from those there requires I don't know I don't know if that'll work let's see see if I have time to test that so I think I had that already double-check so let's try to import now it doesn't work anyone have a clue why I'm using a using module I'll have it at the first executable thing and my script in it that's it also another requirement with using module no let's go back to the car dot source did so classes aren't exposed even with using module if they're dot sourced from the PSM one they have to be in the PSM one and that sucks cuz I don't like ten thousand line PSM one files but we got to do what we got to do so let's take let's just pull this out of there and let's stick it in here let's try this again save it works so now I can do a new car new Tesla there you go but that sucks you know it's problematic I don't have I've no I don't I no longer have a hard dependency on the car module it's dangerous for me to publish this because someone else pulling it down is not going to get that dependency and again it's the same core problem is that class is and using module they need to be in the PSM one not dot sourced so let's try this a different way let's try to create to have a hard dependency on the module with required modules and use the class in the PS and actually that's what I did right there you might have a hard - pendency and require in law home no sorry just put that back car the car module is not correct the class is in the PSM one let's take this using module owl and do this how we think it should work anyone know why this when your paste is like really slow didn't anyone see that anyone I have that too yeah yeah it doesn't work so this is what we would think we would need to do is have the requiring that the required modules again court problem is that require modules is not running using module under the covers that use an import module and we already know that doesn't that doesn't work so no joy required modules is not using using module soft dependency on car modules so we already did that one I believe yes we did yeah this works it's you know yuck though like I said things like parcel galley we won't won't know about this dependency when if you try to import it yours you have to assume that that person has already has that dependent module on the box and that's not good and everyone clear on that that's kind of a long set of scenarios there nice just saying it that anyone not clear so let's go let's restart this just in case so we have classes Tesla and car and I want to import this thing assist and assist or assist and see if it works it's gonna work no it's not normally you know functions partial functions you can write them in any order you know the power cell is gonna parse the whole thing before it does anything with them not so with classes order matters so let's fix that and there you go that works this is a real pain in the butt once you have a fairly advanced module and lots of classes and you need though and the things depend on each other and you need the order of them such I don't know I know someone that I've worked with on a way to kind of like recursively try to import classes and then eventually it'll it'll work yeah just keep on going until you've run out of exceptions and that actually does work but that's uh yeah yeah or I told them I was like you could probably use like the abstract syntax tree and and parse this stuff and then do a bunch of magic on your own to parse all these files come up with a graph of things to import and then import them Oh does it I haven't even tried it so okay nice okay so don't do that so this is not really a a dragon this is really just an FYI with with classes you want to hide properties from a class maybe they're they're internal to the the to the class you don't want people to muck with them but you know hidden so you do that with this hidden keyword on a property and so we have a class let's uh let's create a new instance of it so we have our name property it's public we don't see our secret in our super secret password hundred two but we can always get to this if we really want to with force and we can see the secret property there you can also see a bunch of other methods the PowerShell has created for you on this class and get and set and this is internally how these properties are being set so can I actually see that secret one thing it does does not do is give you top completion on these so if I do EFT hit tab I should type expand this and see this property like you would normally expect hidden properties don't do that so you have to know what you're looking for and you can see it and you can also set it of course it's not a locked property so don't use this if you're don't use this to store secrets that you're you're thinking that you're gonna hide from people if people you know and this is the same in c-sharp you know hidden properties are not meant to hide things they're meant to tell people not to use them they're internal to the class and their implementation details of the class or like private api's and you it's a you run the risk of breaking things when you try to use internal things because it's on them to change them that you get they give you public properties to use don't use the internal ones because they're free to change them so that's really the kind of the gist of hidden properties not the hide secrets from you just tell the developer or the user this is stuff that you don't this is just inside baseball stuff don't use it so not really a dragon but you know they're they're not private and even private in c-sharp was not really private you can still get to them it's just hidden and not very well verbose in debug this is not really also a dragon but this is just another stuff that bf is more of an FYI about working with classes I got this this demo class from a fellow on Stack Overflow but this test kinds it gives you a nice rundown of how verbose and debug work inside classes so let's let's let's import this so we have a class and then two functions so inside these functions we have a normal function it's gonna create a new instance of that class run a method on it pretty pretty simple and we have an advanced function with commanded binding that gives us a reverb OS and debug and what if and all that kind of fun stuff all the stuff we should be using for every single function we write right right I don't see any reason not to use advanced functions personally they could just give you a lot of stuff for free so that works just like we would expect did we create a new incense pass at a property let's try to advanced verbose acquit expect it to you see my verbose messages in my a my constructor and in my method debug should work the same way all right you know beers do he ran my debug message right there so that's cool but there's always a but well actually this works so we'll just we'll set our we'll just manually set over bose preference in our session so we're not gonna wrap it around a function and we'll create a new instance I don't have verbose turned on I shouldn't expect any output and that's that's correct let's turn it on and run out again we get our verbose message like we expect because debug work they worked in the function so we'll set it to inquire this will also work with all I should say not work with continue where's my debug message the debug is turned on verbose seem to work not debug did anyone know why or I've seen this cuz I don't know the answer I think this is a bug so does verbose they were there both in separate streams well I mean we do continue it won't do that right yeah I don't see it so I think this is a bug I'm just curious if anyone else has seen this all probably raises but to me I just work just like verbose so that is a potential gotcha if you want to mainly work these classes and you want to turn on debug you got a wrap it in a function and s sucks for debugging purposes alright so that requires how many people user requires module ok some people I personally don't use it I think there's some problems with it this is just yet another one of them I'll show you why so requires at the beginning let me run this in my session make sure I'm all fresh requires also does not import the module correctly using module is the only way to do this that sucks so what requires not not gonna happen let's use that let's do that I worked I should sources and I got my domain instance so using module don't use it if you want to use work with directly with classes it's not gonna work same problem is one and what scenario for or something like that the other problem with requires modules is that it tends to swallow exceptions if you're trying to import a module and that module doesn't it fails to import and is throwing errors your script you're not gonna see the actual reason why that module didn't import it's hiding stuff from yeah it you can lead to some debugging pain if you try to use some recourse so requires doesn't import classes so run me first again refresh so I have to my module here called fruit two versions of it one and two these don't do anything particularly special they have a couple classes in there about you know a fruit based class and an apple that extends it and then I got version two the only real difference between these is I think version 2 added like calories as a property okay so I should be able to see them here so the added that I can see version one and two that's great all using module because we know that's the correct way to do these things I'm gonna import fruit but hey I got two versions of it which one did I import weird aversion to the latest like you would expect if you didn't specify a version and you have multiple versions on the machine it's going to import the the latest what if I want to import an older one what's gonna happen do you think that's gonna work of course not yeah if there's a theme here right so I've got that I got that so anyone know what module specifications are where you can you can basically to have a hash table of them a name and the version and you can use this with import module and just give it that hash table to import that specific one do you think that would work it it does kind of an import of the module correctly why is this here I said version two what version did it you think it actually loaded no well sorry I wanted version one why is version two here strike that reverse it I restarted my session didn't I did I okay why do I have to why did to get loaded hmm I don't know I told it one uh no I told him one I want one this is the module specification I don't it's giving you a specific version to import no it'll learn it'll look the latest always yeah so that's not cool why the latest version I think this is also a bug I got to do some more investigation Friday to figure out some other edge cases to see why this is working this way but module specifications don't work or don't appear to work anyway not the way you you would think so what's the so let's look at a more complex module fittingly named complex module so and this is when I write module this is how our my common structure and probably most of everyone you know a lot of people here is public and private and maybe classes if you have one you got your your manifest and PS m1 and ups and one does dot sources stuff or you know maybe does a couple of initial Aysen initialisation stuff so I have a build script that just kicks off sake anyone not know what sake is okay it's a build it's a task framework kind of like make Raik bake I think does it bake there's a there's one of these for every pretty much every language and they always sound like ache except for sake because PS ache is odd sounding sake sounds cooler but it's it's a build automation framework where you can set up tasks and dependencies so you have to you know usually for compiling code I use it for other things as well as a side I'm I am as of about six months ago on now the maintainer of sake it's gone through a couple maintain errs over the years I'm the current Dread Pirate Roberts for now anyway and if you're interested in sake you can hit me up after this but I have a build script that this is gonna run sake and I can look at my sake tasks I'm not gonna go over too much of this but basically I have a test to clean my output folder just wipe everything I have a task to compile the module you know we're not really compiling stuff in PowerShell but really what I'm doing here is just gathering up all these source files and they're shoving them into a PS m1 just concatenate them all because we we know we saw from other scenarios classes need to be in the PSM one I hate having a giant PS m1 I want to keep everything and source separated so when I build my module I just load up everything and put it in the PS m1 at Build time the other caveat to this so I should say these are my classes we have a planet base class we have Mars and Earth they inherit from planet we know that order matters so the order in which you concatenate them in the PS and one also matters and this is pretty simple with three classes but like my possible module which I talk about on Thursday has like 30 and different dependencies on different ones and initially what I was thinking was oh well I'll just order them o 1 o 2 O 3 and I'll just sort them and concatenate them in order and that just like I was like oh my god this is just like basic and go to 10 and 20 and 30 and then I want to insert a 15 and you know what if I have o 1 and O 2 and then I need to put 1 in the middle you know 1.5 and I was like well this is just stupid so I quickly decided not to depend on the file names to order these I'm just brute force unit I just defined them in the order that I know that they're gonna import it works you know for my case but we have a module or a sorry an array of files we're gonna concatenate them and just add them to a PSN one file so we do the same thing with our private and public functions these don't the order of these don't matter I'm just like normal PowerShell so let's see what this what this does so it created a bin folder the version of the module I'm working with I got my manifest and I got my nice big kiss someone know in my pocket ball model this is like 8,000 lines so this is my this is my way of solving some of these problems with modules is just some of it's just brute force yeah the order of them that's kind of like the problem he was talking about is like that my solution or potential solution was maybe looking at ast and inspecting these files to figure out what depends on what what and a bit and create a dependency graph of the order I run you know dynamically that sounds great yeah yeah it works yeah a lot of the stuff is it works yeah okay yeah yeah hey des they just suck yeah I have a thing thanks for that I've looked at some of the PowerShell code for that using and I and I I know that part time thing I didn't know the technical reasons on why it's different and why classes aren't exposed that's another I haven't got a good explanation about why that's the case and why using modules needed in the first place yeah some custom loader you know or I mean but ideally this stuff is handed in PowerShell itself that's that's really the end at the end this is really just trying to highlight issues that I find with these so I already know the classes are not they're not a hundred percent they got added to fly and I don't think they've really changed in six I don't know what the road map is on classes and what is what they're gonna fix all right so I got a few more minutes here let me so that's my compiled model that's how I do is I just mainly create a big monolithic PSM one I ship it but the same problems with using module apply in that case you have to use using module if you want to get access to those raw classes directly not directly so these two are a little extra ID to see if I had time and I do classes so anyone know what an abstract or not know what in half struck classes and power so I mean I should say in c-sharp but the gist of it is is that you see if I got an example right here and I'm not a developer so this is my layman's term is a an abstract class is a is not a thing that you actually create you don't create an instance of an animal that doesn't make any sense you create an instance of a cat and a dog those are subtypes of an animal it makes no logical sense to create an animal that's why the afterword class is it's a lot of base functionality that you would then did you'd share in subsequent classes but it makes no logical sense to create that base class things would inherit from it that's much my layman's term for what an abstract classes regardless partial doesn't support them yeah yeah you can you can create a a janky version of it so let's create an animal class okay so we have an animal class so here is a way to and this is a runtime thing there's not a compiled time thing I say hey when if I try ever try to create an instance of an animal don't allow me it's you know I'm gonna throw an error if when I when the animal class gets instantiate and this constructor gets this constructor gets run I'm gonna find out what my current type is and I say well if it's animal don't do this this is mimicking a little bit of the behavior of an abstract class is that and in c-sharp you want to be able to this would be a compile time error if you try to create an instance of it this is a run time check though so this great it's created another class that inherits from animal and we can't obviously create a well let's try to create a animal no we can't my ear says no animals invalid you have to inherit can I create a cow yes I can can I make it move yes I can so that's that's a way to mimic abstract classes interfaces I don't know if there's a way to defect in PowerShell so you can mimic um sort of if you want to do this it's not strictly needed but that again abstract classes are are things that you know you don't actually create or add ever want to create an instance of it themselves and here's a here's a little bit more about the internals of classes I have this my class and I want to pass it a value and you know a normal power cell and command lists and functions you do parameter validation for string length and you know matching this regex or something like that you how do you do that on a class method you can't put parameter validation on this parameter that you're passing in so here's an itch so I'm not necessarily advocating for this but this is something you can play with so what this does is rely on some magic power so stuff and here's the link to where I found this so let's create a new instance no I got a little homegrown parameter validation here and why is that working PowerShell is attempting to cast the string that I passed in Brandon or BR to make a new instance of validated name and when the default valid the constructor a validated name passed gets created at that point it's using the normal parameter value set the value of that property so this is reliant on parcels you know casting from one type to another to do a little you know janky parameter validation directly on classes I'm not necessarily advocating the way to do this I would just wrap them in normal power cell functions and just do it the normal way but this is something I just saw that was interesting out there it doesn't always work though so this is a string right this is a value string I'm passing string I expect this thing to be a string I passed it an integer managers can get cast the strings when it needs to power so it's gonna want to do what it wants to do to help you out it thinks it's being nice and it's not you know okay so no so if I pass a string it'll just work it should just work the same like this yep it's the same yeah no joy you can't do it okay have nice things I don't I don't think so yeah we're wrapping up okay okay this is you know some of the links that I have some are projects that I'm working on they can see sake posh spot which I'll talk about later OVF watchman my all get rub yeah every pose it's not okay all fee I'll look at that Thanks [Applause]
Info
Channel: PowerShell.org
Views: 3,696
Rating: 5 out of 5
Keywords: powershell, windows powershell, techsession, powershell summit
Id: i1DpPU_xxBc
Channel Id: undefined
Length: 44min 40sec (2680 seconds)
Published: Wed May 02 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.