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

Developing with PowerShell Classes: Here be Dragons

00:00

Formal Metadata

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

Content Metadata

Subject Area
Genre
Abstract
Classes are a powerful capability in PowerShell and are meant to provide a more familiar developing experience to more traditional programmers. You will not experience calm skies and quiet seas though. This talk will show you where the dragons lurk and help you navigate the stormy seas. Classes were introduced in PowerShell 5 and mainly to aid in writing DSC resources but can be used with non-DSC modules as well. This talk will go over some of the hidden gotchas when developing with classes including: * Importing issues * Verbose / Debug oddities * Sharing classes between modules I've developed and released a large PowerShell project (PoshBot) that primarily consists of PowerShell classes. While I could have written the module using traditional functions and cmdlets, I wanted an excuse to try classes out on a new project. Using classes was not a smooth experience and I want to share some of my challenges.
CodeSlide ruleSoftware repositoryMultiplication signInformationLink (knot theory)DemosceneBlock (periodic table)TwitterBitComputer animationLecture/Conference
String (computer science)Range (statistics)Data modelMaxima and minimaBitCategory of beingCodeDefault (computer science)Constructor (object-oriented programming)
Inheritance (object-oriented programming)Flow separationEncapsulation (object-oriented programming)Information overloadSystem administratorTerm (mathematics)CodeCartesian coordinate systemOrder (biology)Instance (computer science)Set (mathematics)Software developerDifferent (Kate Ryan album)Demo (music)Flow separationScripting languageSlide ruleComputer animationLecture/Conference
MIDIHill differential equationConvex hullLink (knot theory)ThumbnailInterior (topology)Atomic nucleusMUDVacuumComputer clusterThomas KuhnDivision (mathematics)Maxima and minimaExecution unitoutputChemical equationLemma (mathematics)Inclusion mapEmpennageDenial-of-service attackRoundingProgrammable read-only memoryInvariant (mathematics)Computer-generated imageryInformationModule (mathematics)Point (geometry)File formatNormal (geometry)Object (grammar)Functional (mathematics)Instance (computer science)Flow separationRaw image formatComputer fileCore dumpSource codeCodeType theoryLine (geometry)Error messageModule (mathematics)Multiplication signComputational complexity theoryComputer animation
Menu (computing)Variable (mathematics)Information and communications technologyLemma (mathematics)Task (computing)Modulo (jargon)EmailLambda calculusInclusion mapExecution unitMultiplicationExecutive information systemChi-squared distributionFunction (mathematics)SummierbarkeitStructural loadModule (mathematics)Convex hullWechselseitige InformationPhysical lawUltraviolet photoelectron spectroscopyInformation managementComputer clusterVacuumComputer fileGamma functionLocal ringFloating pointRule of inferenceSurjective functionMusical ensembleNP-hardModule (mathematics)Order (biology)Virtual machineParsingCategory of beingException handlingMultiplication signSource codeComputer fileSet (mathematics)Software developerComplete metric spaceCore dumpInstance (computer science)ImplementationModule (mathematics)Line (geometry)C sharpScripting languageGraph (mathematics)Abstract syntax treePasswordInheritance (object-oriented programming)Computer animation
VacuumFunction (mathematics)ThumbnailCausalityMusical ensembleComputer wormChi-squared distributionConvex hullDenial-of-service attackNormed vector spaceFibonacci numberEmulationSummierbarkeitHand fanStructural loadModule (mathematics)Inclusion mapExecution unitCloud computingPhysical lawModule (mathematics)Revision controlMessage passingModule (mathematics)Data structureFreewareLatent heatCalculusFunction (mathematics)Functional (mathematics)Demo (music)Instance (computer science)Module (mathematics)Streaming mediaBuffer overflowError messageExpected valueCategory of beingStack (abstract data type)Table (information)CASE <Informatik>Hash functionSoftware bugRight angleDifferent (Kate Ryan album)Keyboard shortcutFood energyComputer animation
Module (mathematics)Compilation albumExecution unitMIDIKeilförmige AnordnungComputer clusterInclusion mapTask (computing)Convex hullGamma functionComputer fileMotion blurMaizeTotal S.A.Hand fanPhysical lawOvalSummierbarkeitConditional-access moduleMenu (computing)Cone penetration testDenial-of-service attackEmailAbstractionChainData typeDialectSimultaneous localization and mappingModule (mathematics)Computer fileMultiplication signOrder (biology)Run time (program lifecycle phase)Flow separationTerm (mathematics)Computer-assisted translationFunction (mathematics)Functional (mathematics)Type theoryAbstractionInstance (computer science)Constructor (object-oriented programming)Task (computing)Software frameworkCASE <Informatik>Binary fileRevision controlScripting language1 (number)Compilation albumException handlingSource codeBuildingSoftware maintenanceBitFormal languageGraph (mathematics)Line (geometry)Vector potentialOcean currentError messageRight angleModule (mathematics)CodeInheritance (object-oriented programming)Computer animation
Game theoryPower (physics)InfinityEmailMaxima and minimaConvex hullExecution unitIntrusion detection systemCategory of beingTwin primeSicComputer wormMathematicsComputer iconDuality (mathematics)Uniform resource nameEquals signRothe-VerfahrenWitt algebraDemo (music)Module (mathematics)Module (mathematics)Computer fileSource codeOrder (biology)Revision controlSoftware frameworkState of matterPasswordMilitary operationError messageMathematicsParameter (computer programming)Category of beingValidity (statistics)String (computer science)Electronic mailing listInstance (computer science)IntegerBitNormal (geometry)Regulärer Ausdruck <Textverarbeitung>Constructor (object-oriented programming)Link (knot theory)QuicksortProjective planeLengthFunctional (mathematics)Type theoryRight angleComputer animation
Coma BerenicesJSONXML
Transcript: English(auto-generated)
So afternoon, everyone. My name is Brandon Olin, devblackops on Twitter. This session is about developing with PowerShell classes
and Here Be Dragons. And what this really means is, what are some of the gotchas that you're more than likely going to 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 if you start using them, what not to do.
Or if you do like pain and suffering, go ahead. These links go to speaker deck and to the GitHub repo 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 are PowerShell classes? I'm going to 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 info blocks 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, OK, after you 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 these kind of tie, 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 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 of basic properties about that car, manufacturer, model, and year, and a method that operates on that class called Drive. And it obviously does what it says it does.
And at the very bottom is how you would instantiate that class with the new method, or one of the ways you can do this. On the right-hand side is a little bit more advanced stuff where you can do with classes. And this is where you actually start getting more of the benefit of using them,
code reuse is I want to create a new class called a Tesla. Obviously it's going to inherit a lot of the properties from a car class. It's also going to define a couple of new ones, max speed, range, and so forth. And then we're going to set those when we, on the default constructor on this class,
we're going to set some properties on it. This is really a basic example of what you would do with a 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're starting to morph into the realm of development. And you start needing to think about some of these more develop-y type terms. I'm not a developer. I know a little C Sharp. I know some JavaScript. I hate it.
I didn't go to college. I'm a dumb Marine, so yeah. I've just learned to stuff my trial and error, and sure, Forrester will. But the main reasons you would use a class is separation of concerns. You want this instance of a class to do one thing.
Another class has a different set of concerns. It does something entirely differently. You don't want this code to bleed into each other. And this is really about just code reuse and keeping 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 need to know about how to use a class, right? OK. I'm going to run through, hopefully I have time to run through these 12 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 going to 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 MyClass. Very basic module. Has a manifest. Nothing special there. Nothing special really in the PSM1. It has a class called foo.
We want to use that class in our PowerShell 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 going to work? I can't type.
No, of course it doesn't work. Unable to find type foo. Why is that? Does anyone actually know the true reason why that doesn't work?
I actually don't know the true technical reason. If Bruce Piatt was in here, he'd probably tell me why. I just know it doesn't export the class. If you actually dig into the PowerShell code for import module
and using module, you'll probably find out why that is. The gist of it is the raw class and type is not exposed when you import the module. So how do we work around that? Stealing my thunder.
Using class, which was introduced in PowerShell 5, or using module, I should say, is how you would use a module with the class in it. Let's see what this does. And there's all kinds of gotchas with using module,
and I'll go over some of them. But this worked. This is how you would use a module. It'll import the module and 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.
And this is how you were using an infobox module, is you can hide all your classes internally to the module and expose them with just normal partial functions or cmdlets. Let's see what this does. So actually, let's look at this car module.
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 classes in separate files. I think most people do that probably now. Is that true? I like to be tied.
I don't like a 10,000 line PSM1. Let's see if this works. So I have a class folder. I have a simple class called car that's in that. My PSM1 dot sources that class file when it imports. And then I have a normal partial function that will create an instance of that car, set some properties,
and then return it. And so this is my new car function is my way of interacting with this class.
So you can see that worked. I imported the module. I created a new class. I should say an instance of that class. Do a get member. I can see. It's car. I can do everything I want. This is a normal PowerShell object at this point.
You can see that. I can then pipe that and format list, format table, whatever you want to do with that, like any other object. So that gets around one problem with classes not being exposed from a module is you basically expose them with a function, which
means you also have to create a function in the new something to create an instance of your class and give it back to you. These scenarios kind of go in order of complexity.
So here's a gnarly one. So let's say 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.
Someone created this really nice class. I want to be able to use it in 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 going to import Tesla, and it doesn't work.
And why is that? Anyone have a guess? That's skipping ahead. This is how you would normally define a dependency in a module, right, in a manifest? Do you require modules?
I have that, I require the module, but I didn't work. It should have imported car before it loaded Tesla. What's that? It has no idea.
Just saying it's the same problem as import module. Because internally, the PowerShell required modules is probably just running import module with some variation of it. So you run into the same issue. And this theme of all these things, a lot of these things stem from that core problem right there. So the dragon in this is that, yeah, required modules
does not expose the classes just like import module does. Same problem as scenario one. And you'll also find with developing with classes, at least 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 the same. So let's add. So we'll fix the Tesla module.
So we had a hard. All right, so we had a hard dependency 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 we'll create a soft dependency.
And you really shouldn't do this. So now, inside, when I import that module, I'm going to assume the car is already on the machine. And I have to assume that here. And there's other issues with doing this. Now, things like PS Gallery and stuff, if you try to publish these to the PowerShell Gallery, you're not telling the Gallery that you have a dependency on this other module.
That's completely hidden from those. It requires, I don't know. I don't know if that'll work. Let's 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 it using module. I have it as the first executable thing in my script. And that's also another requirement with using module.
Let's go back to the car. I dot sourced it. So classes aren't exposed, even with using module, if they're dot sourced from the PSM1. They have to be in the PSM1. And that sucks, because I don't like 10,000 line PSM1 files.
We gotta do what we gotta do. So let's take, let's just pull this out of there, and let's stick it in here. And let's try this again. Save, save, save.
It works. So now I can do new car, new Tesla, and there you go. But that sucks. You know, it's problematic. 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 gonna get that dependency. And again, it's the same core problem, is that classes and using module, they need to be in the PSM1, 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 a class in the PSM1. Actually, that's what I did right there. Here we have a hard dependency and required mod, oh, no. Sorry. Just put that back. Car, the car module is now correct. Let's go back to the classes in the PSM1. Let's take this using module out,
and do this, how we think it should work. Anyone know why this, when you paste, it's really slow? Does anyone see that?
Anyone have that too? Yeah, it doesn't work. So this is what we would think we would need to do, is have the required modules.
Again, the core problem is that required modules is not running using module under the covers, it's using import module, and we already know that doesn't work. So, no joy. Required modules is not using module. Soft dependency on car module,
so we already did that one, I believe. Yes, we did. Yeah, this works, it's yuck though. Like I said, things like PowerShell Galley, we won't know about this dependency. If you try to import it, you have to assume that that person 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. I should say, anyone not clear? So, let's go, let's restart this just in case.
So, we have classes. Tesla and car, and I wanna import this thing. Let's just dot source this and see if it works. Is it gonna work? Of course it's not. Normally, you know, functions, PowerShell functions, you can write them in any order.
You know, the PowerShell 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 the things depend on each other, and you need to order them and 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 work. Yeah, just keep on going until you've run out of exceptions. And that actually does work, but that's, yeah. Yeah, or I told them, I was like, you could probably use like the abstract syntax tree
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.
So, don't do that. This is not really a dragon, this is really just an FYI with classes. You wanna hide properties from a class. Maybe they're internal 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. So, we have a class, 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 hunter 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
that 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 not do is give you a tab completion on these, so if I do F dot,
and I hit tab, I should tab 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, this is not a locked property.
So, don't use this to store secrets that you're thinking that you're gonna hide from people. If people, and this is the same in C Sharp, 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 they're implementation details of the class,
or like private APIs, and you run the risk of breaking things when you try to use internal things, because it's on them to change them. 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 gist of hidden properties,
not to hide secrets from you, just to 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 they're not private, and even private in C Sharp is 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 is more of an FY
about working with classes. I got this demo class from a fellow on Stack Overflow. So, this just kind of gives you a nice rundown of how verbose and debug work inside classes. So, 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 simple. And we have an advanced function with command and binding
that gives us our verbose 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 just give you a lot of stuff for free.
So, that works just like we would expect it. We create a new instance, pass it a property. Let's try the advanced verbose works like we would expect it to.
You can see my verbose messages in my constructor and in my method. Debug should work the same way, right? And it appears to.
It ran my debug message right there. So, that's cool. But, there's always a but. Well, actually this works. So, we'll just manually set our verbose 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 correct. Let's turn it on and run that again. We get our verbose message like we'd expect. Does debug work? They worked in the function. So, we'll set it to inquire. This will also work with the goal.
I should say not work with continue. Where's my debug message? The debug is turned on. Verbose seemed to work, not debug. Does anyone know why or have seen this? Because I don't know the answer. I think this is a bug.
Well, so does verbose. They're both in separate streams. Well, I mean, if we do continue, it won't do that, right?
I don't see it. So, I think this is a bug. I'm just curious if anyone else has seen this. I'll probably erase this. But to me, that should work just like verbose. So, that is a potential gotcha. If you wanna manually work these classes and you wanna turn on debug,
you gotta wrap it in a function and that sucks for debugging purposes. So, requires. How many people use a requires module?
Okay, some people. I personally don't use it. I think there's some problems with it. This is just yet another one of them. And I'll show you why. Don't do that. So, requires is 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 modules is the only way to do this. That sucks. So, requires, not gonna happen. Let's use that. Let's do that. That worked.
I should dot source this. And I got my instance. So, using module, don't use it. If you wanna use, work directly with classes, it's not gonna work. Same problem as one in scenario four 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 it's throwing errors. Your script, you're not gonna see the actual reason why that module didn't import. It's hiding stuff from you. It can lead to some debugging pain
if you try to use requires. So, requires doesn't import classes. So, run me first again. Refresh.
So, I have a 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 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 two added calories as a property. Close that, okay. So, I should be able to see them here.
So, 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? I imported version two, the latest,
like you would expect if you didn't specify a version and you have multiple versions on the machine. It's gonna import the latest. What if I wanna import an older one? What's gonna happen? Do you think that's gonna work? Of course not.
Yeah, there's a theme here, right? So, I got that, I got that. So, anyone know what module specifications are? Where you can basically have a hash table of the name and the version and you can use this with import module
and just give it that hash table to import that specific one. You think that would work? It does, kind of. It imported the module correctly. Why is this here? I said version two. What version did it, you think it actually loaded?
Oh, 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 two? Why did two get loaded?
I don't know. I told it one. No, I told it one, I want one. This is the module specification. It's giving you a specific version to import.
It'll load the latest, always. So, that's not cool. Why the latest version? I think this is also a bug. I gotta do some more investigation, try to figure out some other edge cases to see why this is working this way.
But module specifications don't work. They don't appear to work anyway. Not the way you would think. So, let's look at a more complex module. Fittingly named complex module.
So, and this is when I write modules, this is how my common structure and probably most of it, a lot of people here is public and private and maybe classes, if you have one, you got your manifest and PSM1 and your PSM1 does dot sources stuff. Or maybe does a couple of initialization stuff.
I have a build script that just kicks off SAKI. Anyone not know what SAKI is? Okay, it's a build, it's a task framework, kind of like make, rake, bake. I think there's a bake. There's one of these for pretty much every language
and they always sound like ache except for SAKI because PS ache is odd sounding and SAKI sounds cooler. But it's a build automation framework where you can set up tasks and dependencies. So you have to, usually for compiling code, I use it for other things as well. As a side, I am, as of about six months ago,
I'm now the maintainer of SAKI. It's gone through a couple maintainers over the years. I'm the current Dread Pirate Roberts, for now anyway. And if you're interested in SAKI, you can hit me up after this. But I have a build script that this is gonna run SAKI
and I can look at my SAKI task. I'm not gonna go over too much of this, but basically I have a task to clean my output folder, just wipe everything. I have a task to compile the module. We're not really compiling stuff in PowerShell, but really what I'm doing here is just gathering up all these source files and then shoving them into a PSM1,
just concatenating them all. Because we know, we saw from other scenarios, classes need to be in the PSM1. I hate having a giant PSM1. I wanna keep everything in source separated. So when I build my module, I just load up everything and put it in the PSM1 at build time.
The other caveat to this, or 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 PSM1 also matters. And this is pretty simple with three classes, but like my popspot module, which I'll 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 01, 02, 03,
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 wanna insert a 15, and what if I have 01 and 02, and then I need to put one 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 forcing it. I just define 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 PSM1 file.
So we do the same thing with our private and public functions, these don't, the order of these don't matter, just like normal PowerShell. So let's see what this does.
So I created a bin folder, the version of the module I'm working with. I got my manifest, and I got my nice big PSM1. No, in my PowerShell model, this is like 8,000 lines.
So 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, my solution or potential solution was maybe looking at AST and inspecting these files to figure out what depends on what, what, and create a dependency graph of the order, at run, you know, dynamically.
That sounds great. Yeah, yeah, it works, yeah. A lot of this stuff is, it works, you know. Yeah, yeah, it does suck.
Yeah, I have a, thanks for that. I've looked at some of the PowerShell code for the using, and I know that parse 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 really the end, at the end. This is really just trying to highlight issues that I find with these. So, and I already know the classes are not,
they're not 100%. Well, they got added to five, and I don't think they've really changed in six. I don't know what the roadmap 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 module. That's how I do it, is I just mainly create a big monolithic PSM1, and I ship it.
But the same problems with using module apply in that case. You have to use using module if you wanna get access to those raw classes directly. So, these two are a little extra. Let's see if I had time, and I do. Classes, so, anyone know what an abstract,
or not know what an abstract class is in PowerShell? Or in, I should say, in C Sharp? So, the gist of it is, is that, let me see if I got an example right here. And I'm not a developer, so this is my layman's term, is an abstract class 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. Right, that's what an abstract class is. It's a lot of base functionality
that you would share in subsequent classes, but it makes no logical sense to create that base class. Things would inherit from it. So, that's my layman's term for what an abstract class is. Regardless, PowerShell doesn't support them. Um, yeah, yeah, you can create a janky version of it.
So, let's create an animal class. So, we have an animal class. So, here is a way to, and this is a runtime thing, this is not a compile time thing. I say, hey, if I ever try to create an instance
of an animal, don't allow me. I'm gonna throw an error. If, when the animal class gets instantiated and 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, in C Sharp, you wanna be able to,
this would be a compile time error if you tried to create an instance of it. This is a runtime check, though. So, let's create another class that inherits from animal, and we can obviously create a, well, let's try to create a animal. No, we can't.
My error says, no, animal's invalid. You have to inherit. Can I create a cow? Yes, I can. Can I make it moo? Yes, I can. So, that's a way to mimic abstract classes. Interfaces, I don't know if there's a way
to do that in PowerShell. So, you can mimic them, sort of, if you wanna do this. It's not strictly needed, but again, abstract classes are things that you don't actually create or would ever wanna create an instance of it themselves.
And here's a little bit more about the internals of classes. I have this my class, and I wanna pass it a value, and a normal PowerShell and command lists and functions, you do parameter validation for string length and matching this regex or something like that.
How do you do that on a class method? You can't put parameter validation on this parameter that you're passing in. 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 PowerShell stuff and here's the link to where I found this. So, let's create a new instance.
So, I got a little homegrown parameter validation here. 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 constructor of validated name gets created, at that point, it's using the normal parameter validation to set the value of that property. So, this is relying on PowerShell's casting from one type to another to do a little
janky parameter validation directly on classes. I'm not necessarily advocating the way to do this. I would just wrap them in normal PowerShell functions and just do it the normal way, but this is something that I just saw that was interesting out there, yeah.
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. Well, integers can get cast to strings when it needs to. PowerShell's gonna wanna do what it wants to do
to help you out. It thinks it's being nice and it's not, you know. Okay, so. Did you define that, change it? No, so if I pass this string, it'll just work. It should just work the same.
Oh, like this? Let's see. Yep, it's the same thing. All right. So. I was thinking it was doing like the magic, like floats or whatever it was trying to do, like when you have like a.
Yeah. No joy. We can't do it. We can't have nice things. There was the question that got asked. If you create a soft dependency and a hard dependency in your PSM1, will it work? I don't think so.
Yeah. Yeah, we're wrapping up like right now. Okay. This is, you know, some of the links that I have, some of my projects that I'm working on, you can see Saki, PopSpot, which I'll talk about later, OVF, Watchmen, might all get that repo as well.
It's not? Okay, I'll look at that. Thanks.