PowerShell and Active Directory Essentials

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello this is adam bertram and this is the course powershell and active directory essentials if you are new to powershell and trying to figure out a good way to create reports based on various active directory criteria or you just want to learn some powershell you come to the right place lucky for you we're going to take you on a tour of powershell all while applying your skills to active directory as i mentioned my name is adam bertram and i love automation and powershell in particular i do a lot of stuff as you can see and have more than enough street cred to take you on our a to z journey on powershell and actor director as you can see here so the biggest question i receive when talking about powershell to different people is why why should i use parish health do x what if i already know python or perl or even batch what's the big deal about powershell anyway of course every question is going to depend on the context but in a nutshell here are the few basic reasons i give everyone right off the bat first it's everywhere if you've just heard of powershell and have to use it much at all you might know this you know powershell is not vbscript or batch powershell is more like python in a roundabout way powershell can manipulate files it can manipulate the registry of windows machines and a lot of other simple stuff like that but it can also call rest apis work directly with active directory hundreds of other non-microsoft products all while providing rich objects oh did i mention it's now available on linux and mac os as well it's also intuitive it was designed to be easy to learn in the familiar verb dash noun syntax what you see is what you get with powershell and typically what you expect the command to do is what it does no more guessing what this or that argument does it can also automate just about anything you can think of other than being a console it's a powerful automation language because of its ubiquitous presence and support for so many different platforms you can implement a crazy ifttt thing if you want you know if you're familiar with that service i've seen some scripts that pull data from an hr database populate actual directory send users to sap build home folders build exchange mailboxes and all kinds of other stuff since i've just convinced you to use powershell for all your daily needs okay well maybe not yet but i've still got some time but you're probably coming to this course because you're a security guy or gal you know admittedly i'm not that guy i'm the automation guy as in powershell automation is a general term and can be applied just about anywhere powershell is a universal tool that can enumerate security policies in active directory build exchange mailboxes control your sprinkler system and even control your cloud environment it doesn't really care where it gets applied powershell is great at gathering all kinds of data and building reports as you can see the effort required to pull all users and computers from active directory is as easy as just doing it for one if built right your work is infinitely extensible do the work once and apply it across the board regardless of the number of objects and finally it's also popular in the infosec community for the reasons we're not here today powershell is very popular in infosec because it's installed by default on all windows operating systems and has hooks into all layers of the os this means a lot of fun hacking opportunities for you security guys and gals but again in this course we're not going to focus on that we're just going to focus on using powershell as an automation language so is this course right for you before you spend your valuable time going through it well are you just getting started out with powershell have you used powershell for a little bit to create some super simple scripts but don't really understand how it all works if so you're in luck here in this course we're not only going to be working with active directory in powershell but as i'm going along i'm going to be breaking down powershell concepts and will ensure you understand everything before continuing on so you've got a good handle on powershell already well that's fine you might want to skip over the next module but stick around for the rest of the course i'm not going to pull punches when getting in deep with active directory with powershell if you finish this course you're going to come away with some very useful skills for one you're going to understand powershell now i'm not talking about just learning language constructs like operators functions modules and what have you you know that's useful but you're going to learn how to apply this knowledge to a real world scenario this is the most valuable knowledge of all you're going to come away with lots of other ways to apply the tactics you'll be learning here you'll come away with a shiny new powershell tool that can be wielded a number of different ways in your daily lives and finally you're going to learn a lot about actor directory concepts you're going to get exposed to all kinds of different best practices in ad we're not only going to just talk about them but i'm then going to show you how to use powershell to implement them as well this course is going to be laid out in modules we're going to start off with just general powershell stuff and hone in on active directory we'll start out with just getting used to some common powershell commands and then hop into applying your powershell skills to active directory once you've got a firm grip on powershell and how to handle it i'm then going to show you how to use powershell to interact with ad we'll then dive a little bit deeper into how to pull out various data from 80 objects like users computers gpos and so on once you've learned how to integrate various objects well then take a step further and get into maintaining active directory health this is using powershell to check for potential problems reporting them and even take a step further and fix them on the fly and finally we'll convert our rudimentary powershell console output and create some pretty reports you'll get introduced to some of powershell's output commands and how it can be used to convert data into user reports that even a non-technical manager can understand and then finally at the end we'll kind of wrap it all up with a nice bow and provide you a nice summary of what we've covered in this module we're going to get right to it and get starting coding with powershell this module will be a great jumpstart for those of you who are brand new to powershell we're going to focus on the basics here and attempt to give you a quick run through on everything you need to know to get your feet wet with powershell powershell is both a shell and a scripting language one of the first things you'll need to grasp is running commands you'll do this with the powershell console as you can see here the powershell console is an interactive console that enables you to run various commands in real time this means you don't have to execute a script separately the powershell console is just like the old cmd.xc all the commands that you're used to still work with the powershell console like cd dir type you know and all these other older dos commands most of those aren't real commands in powershell but aliases that microsoft has put in to make the transition to using powershell as easy as possible this also means that even those ancient batch files even still work although i'd be hard pressed to recommend keeping those around but really that should show you just how compatible the two are so let's start running some commands now on the console to see what we can do alright so it's time to really get into powershell now and let's dive in and go for our first demo here in this demo let's just run some commands get the feel for the console and um just kind of see what's going on with powershell so whenever you first started getting with the powershell the first thing we need to do is open the powershell console and to do that i'm running windows 8.1 here but the process is exactly the same with windows 10 or any of the other windows server versions so i'll just go in here and i'll just type power and you'll see that i have windows powershell so i'm just going to click on that and then you'll see that powershell gets open you'll notice that it looks exactly the same as the cmd.exe prompt that you're used to you know there's things like cls is still there we still have commands like ping so that there's a server called dc on my network we can ping we can run commands like ipconfig so exactly the same as cmd.exe we can even do stuff like dir or any of the old old style dos commands we can do any of that stuff still in fact in powershell we can also run the command prompt from within powershell so if we wanted to i can go to the command prompt here and now i am actually in the old school cmd.xe command prompt so again i'll run ipconfig same exact scenario as before but since i'm now in the command prompt i can get out of that by typing exit and you'll see that my prompt there turned back to ps instead of just the c colon what can we do with powershell well when you first get started you really don't know what's possible with this new language but powershell gives you some really good commands to do that and the first one is called git command and you can do that by typing git dash command and one thing that you'll soon realize with powershell is powershell has really good tab completion as well so instead of typing out git command manually like that i could just do type out get dash and maybe co and then i can start hitting the tab key and you can see that powershell knows all the commands available to me and it automatically will start rotating through all those so you'll find that you'll use the command quite a bit if you get lazy you can even do git dash and it'll start cycling through all of the commands that you have there it's a really really good time saver so let's type git command here and we'll see what that does and you'll notice that this has a lot of different commands it's flying through all of them now but these are all the commands that are currently available to me in my current session now there's a lot of those in here that are not going to be available to you off the top of the bat so like in the aws powershell stuff the google cloud powershell stuff these are modules which we'll discuss later that these commands are part of which you will not have those available to you immediately but one thing i wanted to show you is just the command structure notice that with git command here you have get which is a verb and command which is a noun and if you look down through each of these commands they all have the same general structure update dash noun unregister test so there's always going to be a verb and then a dash and then some kind of noun and you can easily see where all the verbs and nouns are available to you with git command so with git command git command is really really flexible and it allows you to see all the commands available to you and do some filtering and things like that with it so let's say that i want to find all of the commands that start with the get verb so with git command i can do a dash and then i'm adding a parameter onto a git command and because again i'm lazy i don't want to actually figure out what this parameter is i can just hit tab here and i can tab through all of the different parameters that are available to me with git command since i want to find all the commands that have the get verb i can just do dash verb and then a space and type in git hit enter and then all those will be filtered only on the get verb the same thing i can do with the noun get content is a good command for example so let's say i want to find all of the commands that have the noun of content and you can see i can do add content clear content get and set content the git command command is a very good discovery tool to use to really get in there and feel around and figure out what's available to you so another thing i wanted to compare is if you are used to the command prompt and haven't used powershell very much at all i want to kind of give you a general sense of what those two mean let's go to the command prompt by typing cmd here so let's just change into a directory called example we could just do cd see example let's say that i want to enumerate all the different files in there starting with foo so i can do that with the command prompt which is the old school batch way here i can do that with the old school four loop so if you're merely with batch files the four is just a way to loop through things and set iteration variables if you're not familiar you look at this like what in the world does this thing do you would have no idea what this thing does it's not very intuitive you're not going to really know what that thing does versus let's do the same thing with powershell let's exit out of the command prompt here now we're back into powershell now powershell has a command called get child item and get child item works similarly to the dir command on a lot of other different things so get child item gets listing of all the files and folders in a one or more directory so if i just run git child item on the root of c here you'll see that it just looks exactly like the dur command in dos used to so you have all of your different files and folders there now let's do the same thing we just did with the command prompt i'll use get child item here again and then i'll specify a path so there's a path variable that i specify for the folder and again i will use see example and also notice that i can tab complete folders as well that works with not only commands but i can also tag complete folders and files as well it knows that if you type c colon slash that you are querying the file system so let's go example here and i'll type a tab here and now bc example and then now git chat item has a parameter called filter and filter what does well what you would think it would it would filters the output that git child item is going to provide i can provide this filter here and just do a foo star so a foo and a wild card and i'll try this here and see what happens well it looks like it did find all of the food directories that's great but what if we had a file in the example folder here so i can do that by let's say that i'm going to create a file called foo dot texts and i'll do that powershell also has a command called add content so i'm going to add a file here called foo dot text and i'll just put some kind of value in it and that created the file i'll run this again and then let's say i only want directories that start with food not files as well in the previous example i wanted everything that started with name i technically did that just now with powershell but let's say that i want just the directories well you just do dash and then hit directory and it filters that all out by directory we can also do that with files as well so let's say that i wanted to always do files well i don't know what the parameter would be let's see what that looks like so i'll hit dash depth force name none of these look look file right just using the file parameter i did not know that parameter offhand i just tabbed through until i was able to find it then notice that it filtered on file now compare this command with this command which one makes more sense to you to me the get child item specifying a path and the filter in the file is going to make a lot more sense than the old school command prompt way of doing things you'll see that a lot in powershell so the next thing i wanted to show you was that powershell has very if not the same very similar commands that the command prompt did so for example ping in command prompt you had ping and then you specified the name of the hostname in powershell obviously we can still use ping but you'll see that all the output that ping has it's just one big string what if for example we wanted to pull out something like this big ipv6 thing here we would have to do a whole lot of string parsing and doing all kinds of crazy stuff to make that happen powershell has a test connection command and the test connection command can do the same thing i can use test connection and then dc and you'll see that it's formatted out with different headers here so instead of just one big piece of string you'll see that it has these different headers source destination ipv4 address and so on these are actually properties in object we're going to learn more about objects later but just suffice it to say if you have everything broken out in this way pulling out this ipv6 address from this output is going to be significantly easier than doing it with the dos way another really useful command is add content and add content as you saw earlier creates a file or adds existing content to a file so let's go ahead and i'm going to name one dot text so i'll just create a text file with the value parameter i'll put in there a few of my computer names so i'll put in localhost to represent the machine that i'm on now dc which is my domain controller here my lab network and lab sql so i'll go ahead and add this and then with the command prompt you could have seen the contents of this with the type command so i will do type and then see example.txt and you'll see that looks like i already had it in here so i added duplicates so again with command prompt i could have used del and i can use the same thing in powershell so i will go ahead and delete this and then using the up arrow a few times i can search through the history and then i'll do it again and then you'll see that i can use type to get the contents of that file but powershell has a much more powerful command called git content which went over earlier git content is exactly the same as type but it's much more powerful you see that on the surface it looks like it's exactly the same you don't think it's really doing anything different but what you'll find is that each of these the local hosts a dc and the lab sql each of those are individual little objects with properties now again if you're not familiar with objects and properties and all that it's not going to make a whole lot of sense to you right now but i'm just going to kind of give you the primer here to make you realize that these with everything being objects it's so so much easier to give you an example of that so let's say that i'm going to do type well okay i want to only see the first line for example so let's say i only want to pull out localhost well how would i do that in command pro well honestly i don't know how to do that in command prompt because it's not intuitive it probably has to do something like find string or i don't really know how to do that because i would have to parse out that first line however just one tiny example of what powershell can do is with git content that's an array each of those elements there is an array because of that i can assign this a variable so i'm going to sign this and say this is my computers and then now my computer's variable contains each of those now you may think well big deal you just assign the output of git content well let's just say i want to pull the first line all i have to do is put its index zero index one index to index okay let's try the same thing with type here let's see if that works say this is cmd computers cmd computers and again notice i can tab complete and also tab completes variables as well all right so let's do 0 here one two now you may think well that actually works well i'll show you why that works so type is an example of an alias in powershell i can look at aliases powershell has aliases for a lot of the common things that you would run in cmd because in powershell you're not actually in the command prompt although microsoft and the powershell team really wanted you to adopt powershell really wanted to make it easier to do it that's why how they came up with this concept of aliases so you'll see that there's quite a bit of aliases and what aliases are are command that you can type in here but you're actually executing another command for example here is group if you just type group you're actually running group dash object if you type ii you're actually running the invoke item command if we scroll down here and go down to type you'll see that when i actually execute type i'm actually executing get content if i run get content see example exe and whenever i run type c example it is the exact same thing that's because of aliases so aliases are really good way for you to explore and get things done without having to learn all the commands around that eventually it's a really good idea to learn all those different commands but right now you don't have to do any of that stuff that concludes our running commands demo i encourage you to get in there type around try the git command again and just explore some of the commands that are available to you see if you can learn a little bit about the different commands and what they do as you're just starting to get your feet wet you're going to need some help lucky for you powershell has an awesome and intuitive help system built right in no more googling around to try to figure out what that obscure command or that obscure argument means every powershell commandlet has helped built right in if you're familiar with the linux man account this is like man on steroids by typing git dash help followed by the command you'd like to learn about along with a few different parameters you're able to see a description of the command each parameter and their descriptions as well as some really helpful examples what really sets powershell apart is its concept of updatable help by using the update help command powershell can reach out to the internet and download the latest help content for you this feature is even possible using your own custom commands as well so let's jump into a demo to see what's possible with help so when you first start out with powershell you really don't know what commands to use how to use them and so forth so where's the first space you look at well the first place that i always look at is i used to do a dash question mark or a slash question mark or something like that to figure out like what the command is supposed to do and when i didn't know what command even to use in the first place maybe i used to do dir to try to find the different commands or that sort of thing really the discovery was not that easy with powershell the discovery is very easy as you saw with the running commands demo but also powershell is a really great help system involved here so let's go over a good example of how to use this so first of all let's say that i want to find all of these services on this machine i can do that with get service so you can see that git service brings back all of the windows services and their states on this machine well now maybe that i don't want to see all of them so let's say maybe i just want to see the status of this one here maybe the wmi performance adapter its name is wmy apsrv i don't really know what parameter to use here so i will type git service again and then i'll type a dash and what i could do is start tabbing through here and trying to figure out which one it is and in this case it's name which is pretty obvious what the right parameter is here but a lot of these commands you'll see the parameters they may not know exactly what the parameters do so what we can do is we can look at the help properties of each command and all the parameters and what they do so here's how we can do that first thing we do we can use the get help command here and get help has a parameter called name and i want to get help for get service and you can see that immediately it brings back a lot of great information so it has the syntax category here to where it provides you three different ways that the parameters can be used so on the first one there you see you can use name computer name dependent services etc the second one if you just want to specify a computer name you can do that each of those little sections there in the syntax they are called parameter sets different ways that you can use each of the parameters and then you have the description which is a really good example of just kind of a summary of what the script does and then you also even have related links so you see what commands are related to these and you have remarks here now the marks let's go into a little bit more detail here this is definitely not everything you can do with the help syntax so let's say that i want to use the help syntax again and i will use get service here and i can do another parameter and let's first just do parameters here so let's say that i want to get more information on what that name parameter does i can just type in name here and then you can see that it gives a really good summary of what just that parameter does it also tells you if it's required or not so if it's a mandatory requirement it's position we're not going to go over positional parameters very much but that's basically just you don't have to actually type in dash name you can just type in the name and it would work default value pipeline input and wildcard we're not going to talk about all all that it allows you to really dive in and get some more information about each different parameters however what if you kind of wanted to see everything you can do detailed and you can see when you do dash detail it brings back just about everything you want to know about that so it brings back the same syntax and description it brings back descriptions of all the different parameters and even examples examples is what's really cool about the powershell help because i learn best by examples examples allow you to really comprehend and understand how different parameters work depending on the commands there's anywhere from one to ten different examples of how to actually use the command a quick way to get to the examples this is the one i use all the time still i just use dash examples dash examples you saw that output in the detailed section but dash examples is just a really quick way to grab the examples and then finally you can also do full which is pretty much everything possible about that individual command you see there's a lot of different things in the detailed but the full actually breaks down each of the parameters of required positional default value and so forth so that's kind of the gist of the help system and you can use every command built with powershell will have help so you can do get help get content get help set ada account control that one was with the active directory module you can see that all really good commands do have the integrated help one thing that's really sets powershell apart in this help system is this concept of updatable help things may change people want to update hell but if you rely on traditional help systems they're all static there's really no way to get the content updated powershell has a content update will help so i can run update help here and what update help does is it goes out to wherever the urls that are set on each of the commands normally all the clans built from microsoft are pointing at a microsoft url it'll actually go out to the internet and download all of the new help that microsoft provides update help is a really great way to keep up to date on if things change so for example you'll see this lot on some of the active directory module the microsoft azure module and a lot of the other modules that they're constantly adding new features and the way things work and if you use update help this will automatically go out and grab all the latest and greatest descriptions for all of that information that you want and get it all on your system to where it's in your local help system here so that's one thing that's really sets powershell apart from a lot of the other scripting language or console help out there that's about the gist of the powershell help system this help system is not just static you can also write your own help for your various functions and things and integrate it into the help system pretty well but i'll leave that up to you we'll leave that for another day objects are what sets powershell apart from other scripting languages like batch vbscript bash and the like objects allow you to group like properties and events into a single entity and manage it as one in powershell everything is an object even data types like string integers arrays are all just objects objects are everywhere in powershell now these objects have properties and methods think of an object like your car your car has attributes that make it a car right you know it has colors it has doors a trunk tires etc these attributes would be called properties if your car was the object your car can also do things you know it can go forward it can go backward it can turn left it can turn right these would be methods on your car object in powershell these properties and methods will be passed along a pipeline with the object unlike bash where piping is available but it's just simple strings powershell allows you to pass these entire objects along this pipeline and do things on them it's sort of like the assembly line you're seeing there in the next couple demos we're going to explore objects and the pipeline one of the features of powershell that really differentiates it from other languages and other shells is the concept that everything is an object in powershell now as you saw from the slides an object is basically just a thing that you can consider that has various attributes which are just properties of that object and then various methods which are the things that you can do to that object so let's go through a few examples of what that looks like in powershell first thing i want to do is i'm going to create a variable here and i'm just going to create a simple string variable here and i'm going to do that by just using taking the output of right output here and we're going to say hello world well before we do that i'll just show you what this output looks like here so you see that it just outputs a hello world string so let's go ahead and assign that to a variable and call it dollar string now when you get that then the output is stored there now when i just type it out like that you'll see that it just brings back hello world on the service it doesn't look like there's anything else to it you would definitely be wrong if you thought that that was the only thing we can dive in a little bit deeper and i'll show you that this string is actually a rich object full of all kinds of different things to do that you can pipe that to a command called get member get member enumerates all of the various properties and methods of that particular object and then displays them all on the console here you can see here that it is a string and you notice that as a type in traditional programming languages a string is just a string it's just a set of characters and that's it there's nothing else to it in powershell a string is actually a string object which as you can see here there is a lot of different methods to the string one and there's only a couple properties in this case for this string type get member is very good at allowing you to get in and really do some investigation of what type it is and what are the various methods and properties that you can do here notice that in order to reference any of these methods and properties you have to use something called dot notation and you may be familiar with this already so for example this string object here has a length property so i could just use dot and then again with the tab completion i could just type a few other characters and then hit tab and it would complete i can hit string dot length and string dot length can tell me how many characters are in hello world so if you would count all the different characters there in hell world it would be 13 different characters that's how you reference properties on an object so let's say that you want to do something to this object you want to use one of the methods using the same dot notation of the methods but with the methods they always end with parentheses right now we just have hello world all right so let's say that i want to convert all these to uppercase i could just use the two upper method and choose a left parenthesis right parentheses which means that method has no arguments to it hit enter and you can see that all of the characters are uppercase now we can do the same thing with lower as well if we wanted we could do two lower and they would bring all of them to lowercase those methods perform some kind of action on this same thing with replace so let's say we want to replace hello with goodbye that did not work because it looks like that it's case sensitive that's one thing you need to remember a lot of things in powershell are not case sensitive but some things are you have to always remember that so the replace method is case sensitive now one other thing i wanted to point out was notice that on this method here notice we just have the method name two lower left parenthesis right parenthesis that's it there is no what you call arguments inside there so we can run this and there's no arguments so think of arguments as kind of like parameters in various functions however with the replace we need to provide the replace method that was some kind of input so in this case the replace method has what you want to be replaced and then what do you want that to be replaced as that's called passing various arguments to a method when we created the string variable here we just created an object that was already built in we created an object of type system.string now the system.string type is a built-in type in powershell but we can build our own as well let's say that i want to build an object from a car car object so a car has various properties to it so let's try to run this and see what happens here to do that you can build a powershell hash table and a powershell hash table is nothing but a lot of different key value pairs so in this instance we have a color the cart color is going to be red the transmission is going to be automatic and it's not going to be convertible as you can see that i have a boolean false value here so i'm going to create this hash table and call it hash table now when i pipe our hash table to get member you see that the type name is system.collections.hash table and it has different methods and properties that's because it's a different type what i can do is i can build an object of this now hash table technically is an object but we can actually build what's called a ps custom object to do this this is very common whenever you get more into powershell and really using the pipeline and things like that which we'll talk about later let's now convert this into a custom object we can do that by using ps custom object this is called a type accelerator here and you can see that it changes the output without even changing it so whenever i output the hash table you can see name value keyne key values however when i convert that to an object it brings back convertible color and transmission those are the properties of that object versus the properties of the hash table object our name and value and we can also using the ps custom object type accelerator there that's kind of a shortcut that you're generally recommended to use so now let's assign this to the variable car pipe that to get member and you see now that is a system.management.automation.ps custom object object now notice that up above i used dollar car piped it to get member and well not necessarily i piped it to gm well what is gm anyway well gm is a set of aliases so that is an introduction to exploring objects in powershell so remember the command that you really need to run the most is get member get member allows you to really dive in and explore more about objects and figure out the properties and methods and then also remember you use the dot notation to reference the various properties and then methods are always left parenthesis and right parenthesis one of the other unique features of powershell is the pipeline the piping itself has been around for a long time so in bash or even in dos you could do things like dir let's go to actually command prompt here so let's go to dir pipe that to type or pipe that to find string you can pipe commands to other ones but never before in a language in windows you can actually use the pipeline to pipe those rich objects that we talked about earlier to demonstrate the pipeline i'm going to show you a couple different ways how you can use it how we can get stuff done without it and with it and see what the differences are let's say that i want to restart a service so first of all i'm going to see if this service is on here or not i'm going to use the audio srv service nope looks like it doesn't work because i'm actually in the command prompt because the ps wasn't there so let's exit the command prompt there and you see we get ps back so let's run git service name audio srv so it's running now the windows audio service is running i can restart that by just doing restart dash service name audio srv and that would have restarted the service now that doesn't use the pipeline in any way that's kind of like the old-fashioned or traditional way that you would do it providing a parameter directly to a command so now let's do it the object way so here's the next step up to do this let's first grab this and put this into a variable the variable now contains the service object restart service has a name which you saw before a name parameter it also has a parameter called input object now input object is a common parameter name that you see on a lot of different commands that accept pipeline input however we're not going to use the pipeline in this we're just going to show you that we can actually pass that whole object and it does the same thing instead of accepting just the name it accepts that entire service object this is how you would do that the the pipeline way we can do that a few different ways we have the service object in here and if we look at this with get member here you can see that it is a system.serviceprocess.servicecontrollerobject this time instead of piping it to get member i can actually directly pipe that to restart service and it would do the exact same thing so i just took that entire object past it to restart service and since restart service allowed pipeline input to that command it worked we don't even have to assign that to a variable if you want this is the beauty of the powershell pipeline because we don't even have to do that on separate lines so we can just take the output of git service directly to restart service and it will do the same thing you can add as many different pipes as you want here so let's say that i'm going to do something else to that service restart service has a common parameter called passthrough so you notice that whenever we just ran this nothing happened instead we can use passthrough which as soon as restart service is restarted it will actually pass that same object that it got from git service out to the console now this allows us to pipe something else to it let's say that i pipe something else here set service let's change the startup type to manual now actually let's first see if it's set to manual or not so we'll look at this again looks like the default output doesn't show the startup type or anything else for that matter so let's dive in a little bit and we can pipe that to select object property so let's look at all the properties of it and we have status service type service handle display name so it looks like in this instance for services we can't actually see the startup type let's do this another way here so let's grab git service just for a stupid example that you will probably never use but hopefully get the concept here we can restart service do a pass-through which would then pass that same service through and then now let's stop service so it's going to get the service it's going to restart the service and immediately after we start it's going to stop so then we hit there and you notice that it didn't do anything at all stop service we can even do pass-through and stop service and then now you can see that the status is stopped so it got the start service object restarted it and then stopped it all in one line because i was piping all those down one at a time let's go through a more real world example here in this example i'm going to go through a list of computers in a text file and then just king each one so to do that i'm going to first see if my text file is here i use git content path i believe it's example.txt yep we still have those in there i can use testconnection here i'll make sure this command works computer name dc looks like my dc is up and working all right so i want to do that i want to ping each of those now you may think that this may work using the pipeline you may think well that's going to grab localhost dc and lab sql send all that out to the console well maybe i can just pipe directly to test connection that's a very common assumption but you can see that we get a lot of errors and it's because test connection does not provide that pipeline input like that so the command has to be built for pipeline input and if it's not you'll see that it will say the input object cannot be mounted in the parameters blah blah blah they do not take pipeline input to get around this we can use a for each object and then provide an object that test connection does accept as pipeline input so let me show you how this is going to break down here so we can use get help to get more information on test connection to see the pipeline input to see any kind of pipeline information we always need to use detailed here so if i use detailed and i'll scroll up nope all right we need to use full full which provides us information for all of the different parameters and their type of input when we scroll up here you can see that here's the parameters we have first i have the as job parameter the accept pipeline input false buffer size except pipeline input false okay now finally you see here the computer name parameter except pipeline input true so that parameter alone can accept pipeline input however you see that it says buy property name there's two types of pipeline input in powershell there's by property name and then there's by object because we were piping an entire object to test connection that didn't work because test connection doesn't understand accepting an entire object into the command it will however understand just that single computer name parameter here it will understand the computer name parameter because it's set to accept pipeline input by property name so what does that mean well let's do one by property name to do that we need to build an object that has a computer name property so when we go see check out the output of git content here you can see it's a string there is no computer name property on here we need to make one of these names over here we need to make these computer names so we'll understand it better to do that we can use a for each object so we can use for each object and then let's just do ps item and it's exactly the same output we're just grabbing all the contents of git content piping it to for each object and then iterating over each of those individual ones if we pipe this to test connection again it will do the exact same thing because essentially we're doing the exact same option before we need to actually build a another object from this ps item or the pipeline variable to do that we can use the ps custom object like we went over in the earlier demo so let's do ps custom object and then we want to build our own here so then we'll do this build the hash table again we can always cast a hash table to an object and then i'm going to do a make a computer name property and now for each object we'll output an object with only one property computer name now i'm going to pipe that to test connection now you can see that it works because test connection finally understands the input that it's receiving let's go ahead and look and see what this looks like now you see that instead of just showing localhost dc and lab sql it has a computer name with the dashes and then all of them under that so that's saying that the computer name is a property and if we pipe all this to get member you can see now that it's not a string anymore it's a system management automation ps custom object with most importantly a computer name property so now that we have an object with a computer named property test connection can understand that then we can pipe directly to test connection once you've gotten the hang of individual commands it's now time to start building some scripts scripts are simply groups of commands running together as one scripts allow you to easily take the output of one command and use it as the input of another the majority of our work will be creating scripts and eventually modules which we'll discuss a little bit later by building scripts you can easily reuse code by doing something called dot sourcing and simply executing other scripts directly from another script you can call scripts from other scripts which means no more rewriting code over and over again scripts will be used for anything other than minor ad hoc tasks unless you like working on the command line directly the majority of your time will be spent on building scripts although a script is just a text file and you could technically use something like notepad this will soon get old as there is a much better editor called the powershell ise or integrated scripting environment that comes with windows and is a great choice for anyone beginning powershell so let's now get into another demo well we'll be using the isc and build our first script all right so we graduated from running commands and it's getting too tedious to copy and paste commands all the time and run them in the console so your next evolution in your powershell learning journey here is to use scripts let's get into building our first script there's a lot of different ways to do that because after all a script is just a text file but microsoft provides a really good script editor known as the powershell ise so that's the first thing we're going to go over here to get to that we just go to our start menu here type in ise and there it is windows powershell isc so we run this and you'll immediately see that there is no place to actually type code it actually brings up a console screen in actuality the isc has a built-in console here so you can see that i have a built-in console and it's exactly the same console as you have if you just type manually type in powershell.exe so it's a really great way to do debugging and just to do quick copy and paste and things like that to get things done with the ic we need somewhere to build our script so the first thing we need to do is go up here to view and then go to show script pane and the script pane is where we can actually type out our scripts and various commands that we need to run there's a lot of other things too the powershell ise like debugging support a lot of different viewing options you can zoom in zoom out there's a lot of different options here but i'm not really going to go over a lot of the options you can pretty much figure out a lot of this stuff by just clicking around and do things today we're going to focus on just writing a script and then executing the script to do that i'm going to kind of come up with a fictional scenario to where we have built a text file with computer names and i want to loop through that text file and first ping the machines to make sure they're online and if they are online then i want to query something in wmi and get their operating system so let's go ahead and do that now so the first thing we need to do is make sure that we have our text file on our file system somewhere i can do that by going down into the console i believe it's in the root of c let's check it out here so we can do the ir c and it is called example dot text all right well let's just make sure powershell is a really good command called test path we can just dash path here c example dot text it's true so it is one other thing you should have noticed here as i was doing this in the powershell ise it has a really nice intellisense feature here to where it will immediately show you all the different parameters and things that are available to you so it's a really handy feature there so now that we know that our text file is there in here in the console let's just make sure that the computer names in there like we think they are so we'll just run get content and looks like we have three so we have localhost dc and lab sql so that's good so we have all this in here the first thing we need to do is to enumerate all those computer names we did that with git content we need to do other things as well like ping make sure they're available and then query them for the operating system we can't really do that in the console very easily so we need to build a script to that so what i'm going to do is i will just copy and paste basically just get this exact snippet here and paste it up here into my script pane window and because i'm anal about my capitalization i will just capitalize get content here and then i will use the path parameter so it's more obvious instead of using the positional parameters like we were earlier all right so we have get content path one really good thing about the powershell ise is you don't actually have to write the whole script ahead of time and then execute it all at once you can kind of do this piecemeal to do that you can click on any line in here so i have line one i only have one line in my script i can click on that and then click on this button here run selection or i can press the f8 when i do that you'll see that it just runs it down here in the console so it's a really good way to run these one at a time so i can do the ar all i have to do is click on it somewhere and i run dir if i want to run more i just highlight click selection you see that it runs them all so it's a really good feature of the ise that you use a lot since we need to enumerate through all of these we need to find a way to kind of iterate through each of and do something to each of the elements and to do that we're going to use a for each loop there's a few different ways to do it for each loop in powershell but i'm going to use the for each object command so to do that i'm going to do a pipe here and i'm going to type for each object i'm going to add left curly brace and then i'll add a right curly brace what this does is this means for each line that git content provides so each line inside of the example.txt file it will do something for each of those lines so if i run this now you'll see that i don't get any output at all that's because i've actually redirected the output here to my pipe so i'm not actually piping it out to the host console here it's actually going straight into this for each object command to get the same output i did before i need somebody to send that to the console i can do that with the pipeline variable i can use the dollar underscore this is just a variable that represents the current item or current iteration in this file so if i run it now you'll see that i get the same output that's because each time the dollar underscore is ran it will output to the console another automatic variable here that i can use is i can also use ps item if it's a little easier for you so i can run ps item and i'll run this again and you can see that i get the exact same output it's the exact same it's called a pipeline variable so you can use either one you want i'm used to doing the dollar underscore but you can use ps item if you want as well now that we have a system set up to where i can do something to each one of those items in that text file i now want to ping them i can ping them with test connection so i will type in test connection here and then i will specify dash quiet and dash count one by default test connection will act like the ping.xc command where it will try four different times and give you a nice output of the ip address the latency and all that since i just want to test to make sure a machine is online or not you can use quiet and it'll just output true or false and then the count of one that just means just send one icmp request to it and be done with it so now let's run this and now see what happens now you can see that instead of the computer names we have true true and true that's because for every one of these computer names we ran test connection against it and it returned a true a true and a true so you can see that with the for each object we can do something to each of those notice that the line link is getting a little long we have some other code to do and we don't want to continue this all in the same line one of the other great things about scripts not as easy to do in the console is to do multiple lines so i can bring this down a line you can actually do line breaks and these curly braces here and then add another curly brace down here powershell knows to kind of extend the line and knows that the same command and it knows what you're doing so we can actually highlight this all again and it does the exact same thing be sure to always try to keep your line length manageable because you don't want to have to scroll left and right it's just ugly to do all right so now that we're pinging each machine now we need to build some kind of conditional logic so we want to do something only if the machine is online to do that we can use an if then statement so i will enclose our command here in an if statement and now i have an opportunity to do something only if test connection was true first of all let's actually take this back to a simpler level here and i'm going to say if test connection equals dollar true then let's just say the machine is online all right so let's run this and notice we've got three times the machine is online that's because it was up three times the if then logic here this piece right here the test connection piece that actually just returned true or false it returned a boolean true and i'm using the dash eq operator here to compare this result this whole result here against this boolean value here which is dollar true this is the law form of testing conditions what you'll most likely find out in the real world is you take all this away and then you can run this again and it's the exact same output because powershell if then statement it will always return either boolean true or valid true or value let's just write something out so we could do right output whatever and this will actually do the same thing so it doesn't really matter what it is as long as this statement here outputs something so let's back this out now that we have set up a condition so we can do something only if the machine is online so instead of machine is online we want to actually take some kind of action against that so i want to grab the operating system name for each of these well how do i do that well we use wmy or we use sim using the wmy command let's like git wmy object is considered legacy so what we want to do is try to use the newer command list called git sim so we can go get sim instance and if we look at git sim instance we can go down here and we can do help get sim instance which will run through the help in a future module where you'll see that the get sim instance gets the sim instances of a class from a sim server so in this case the sim server is going to be windows now that we know the command to use now we need to specify a computer name to connect to well what if you don't know the computer name well you just type tab and then in the isc you have all the options i have computer name here here on line three at this time when this script executes the computer name will actually be represented as that pipeline variable so it's going to be dollar underscore actually now we need to specify a class and to do that we do dash again and looks like i have class name so i'll hit tab and then i know from experience here that the class name is going to be win32 operating system so i will make that a string and now let's see what happens so this should go through and only if the machine is online it will query the win32 operating system sim class and you see that it did that it did bring back all the various properties that were returned from that class for some demonstration let's actually stop one of these computers to make sure that our logic is working as it should powershell has a really nice stop computer command here let's stop my sql server so we go computer name lab sql and i want to wait until it's off nope actually let's force it to make sure there's any users logged in they will go ahead and do that so i will go ahead and shut it down and i would just use the old school ping command here and the dash t because old habits die hard i suppose you're here let's go ahead and clear this screen of all this stuff we will ping it see if it's online and it looks like it is offline all right great now let's run this again then now you'll see it's taking a little bit and we only got two instances we only got localhost and dc we did that because we had that if statement there only if it was online so we had that option to do that we're reading the text file we're making sure each of those machines are online and we're reading the operating system i now want to see what operating system it is notice that actually we're getting some information like the system directory registered user in c or another but we're not actually getting the operating system name so to do that with the get sim instance command the git sim instance command has a property value here so i can do dash property and i know that it's caption well what if i didn't know it was caption ahead of time what i usually do here is i will take this piece out and then manually go in here and explore to do that get some instance outputs an object with all those properties i can pipe this to select dash object and then a star and then you'll immediately notice that we get back a lot of other properties than just a few that were shown the few that were shown were just based on the format that git sim instance was configured to show it's not all of the properties by default that it showed as we go down through here i can explore which of these properties i want to find and it looks like there i have a caption property and it's microsoft windows 8.1 enterprise in this instance so i know that i want to get the caption property only how do we do that well i can do that by again copying using the select object command again and this time instead of doing a star i can just select object and do caption and then notice that it just has caption doesn't have any of those other things with select object you can really limit the amount of properties that you see so now that i've done this in the console and i know what syntax to use i would then go ahead and put this up in my script so i would do select object and then do caption all right now that i have it in my script i will highlight everything run this again and then you'll see here that i have caption and then i have 8.1 enterprise and server 2012 r2 standard great so i've gotten all of the operating systems of all the computers in my text file typically i don't just want a big list of operating systems i want to know what computer name each of those operating systems correlates to well we can do that pretty easily so because we have the computer name available to us here with the pipeline variable we can incorporate that into our output to the console the first thing we can do here is assign this to a variable so i will assign this to a variable and call it operating system so now we have that stored in operating system and now i can output this out and you'll see that it should be the exact same thing as what we had before because we're not just immediately sending the output of git sim instance to our console but we are saving it to a variable for later use and then outputting the variable which goes to the console so now that we have that stored in a variable now i want to add the computer name so first thing i can do well if i just want a really rough output i can just put the computer name in here and run this again and now that you can see that it will have localhost caption well it has it in there then you have to kind of think about well what does this relate to what does this not relate to it's really hard we need to make it into a more understandable way so to do that we concatenate these two in a string with double quotes so to do that i will just put in operating system and the computer name in double quotes here so i can do a double quote and then i can do dollar underscore and i'll just do a dash and then close my double quote here and let's see what this does all right so notice that we have localhost dash and then we have the operating system and dc dash so we have the computer name dash and the operating system but instead of computer name dash and then this actual operating system name we have computer name dash ampersand curly brace caption equals operating system name but why is that well that's because the operating system itself is not just a single string whenever we save this in here we're not actually saving it as a string whenever we do select object here caption that's actually still outputting an object but it has a caption property to it so you can see that by default powershell will output an object with a property and a string here as the at sign curly brace property name equals whatever the value is i want this to say localhost dash microsoft windows 8.1 enterprise and dc dash microsoft windows server 2012 r2 standard i don't want all that caption stuff in there so let's do that we can do that a few different ways so let me show you the first way so let's take this out and then instead of just outputting operating system i can do a dot here and then notice that powershell the ise is smart enough to know what properties are available to you so i can just pick caption copy this out again and then notice now that we don't have the caption underscore and then the operating system so up here see we had the caption and then all the lines that's indicate that that's a property under here now we don't have that at all so we've removed all that completely now we can enclose this in double quotes again and put our routine back in here and then now let's see what happens all right well it didn't work again what's going on here well the reason is because whenever you reference a property which is captioned here to an object which is the operating system inside of double quotes you actually have to enclose this with parens and a dollar sign so i'll do dollar sign left paren then right paren and now i'll try this again now notice that's exactly what we want we want computer name dash operating system name actually we got exactly what we wanted here so let me just show you one more quick way now select object also has instead of by doing just caption we can do a parameter called expand property an expand property actually take just grabs the value of caption doesn't actually care about caption at all now let's go ahead and try this again with the expand property parameter notice that it has nothing for the operating system name that's because there is no such thing as caption anymore because we expanded it out we just grabbed the value with select object over here to do this now we don't need the dollar parens anymore nor do we need the caption property we can just do what we expect computer name dash operating system and we get what we want this is a really good way to go because then we don't have to worry about that caption property we've got our script created we've tested it by highlighting it and running it with run selection now let's go ahead and save it so we can reuse it over and over again so i'll go ahead and save this and i will save it as get computers now that i have it saved i can go down here in the console and then now i can just execute this script as we normally would we don't have to use the ise at all for this so let's just use the powershell console that we were using before so let's first make sure that it's here we have getcomputers.ps1 there so now i'm going to execute it i can do that by just typing git dash and the first three letters or so of the script name hitting tab and then notice that powershell will automatically put the dot slash in there you need that if you're going to execute something in the local directory so let's go ahead and run that and then now notice we got exactly that same output and we didn't actually have to write it all those commands are available to us now inside of this single script this concludes our building a script piece of the course here so let's now continue on with the course and see what else we can learn with powershell for our last part of this demo let's briefly talk about modules just like scripts group commands together modules take this a step further and formalize things a little bit although modules are again just text files and the scripts they're kind of a special script not with a ps1 file extension but with a psm1 file extension or in some cases a compiled dll modules group commands together not necessarily random code modules are typically built around a single concept for example we'll be using the actor directory module quite a bit in this course this module has commands to just manage active directory there's also a dns server module iis module and so on modules can't be directly executed and ran modules don't contain executable code themselves they contain commands that can be executed this is why if you attempt to run a module nothing will happen at all you will import a module into your current session and then run the commands the module contains and finally modules are great to share code you'll see with our ad module that microsoft has shared this code with us in a single module this allows microsoft to easily share that code with us likewise when designing your own modules you can share the code with your co-workers and the community as well modules are more advanced than scripts so don't worry too much if you don't know how to build them to manage ad you won't have to know how to build a module from day one now that we've got the basics of powershell down let's take this up another notch here for our final demo and talk about modules as you progress in your powershell knowledge you'll eventually find yourself creating a lot of these modules but in this course we're going to be actively using a module that's already created called the active directory module so i wanted to make sure that you understood concept of the module how it works so we're going to be using a lot of the commands in the remainder of the course with the active directory module first of all a module is in a simplest case just a grouping of commands together to find things in powershell you just do get dash window whatever you want so i'm going to use get dash module and you can see here that i have a few modules already loaded into my session so that's kind of the concept of modules it's called importing it and exporting modules when you want to load them they are imported whenever you just run git module you see all of the modules that are currently imported into my session and you can see there with the exported commands on the right those are all the commands that exist inside of each of those modules now this is definitely not all the modules that i have currently available to me to see all the modules on my local system here i can use the list available parameter and when i run that you'll see a whole lot of different modules because i have a whole lot of different things installed here so i have a lot of microsoft ones you see you have microsoft powershell archive diagnostics host and some other third-party ones so i have the sql ps one here i have the azure one the aws powershell and google cloud all of these modules are essentially just more plain text files but instead of ps1s they're psm1 files powershell has a environment variable that looks for specific places where each of these modules are located and that is in the ps module path my ps module path contains a lot of different folders so what this means is every time you want to make a module available to your power cell session you can put it in any of these folders that you want here and it will automatically pick it up recognize it parse through it and understand it so you can then import it and then use some of the commands inside of that module so let's say that we're going to be working with the active directory module here so let's take a look at that so i can run git module name and then i just want to use active directory notice that i could just tab complete on the module names too tab complete is a great feature of powershell right now i have the module loaded into my session because i didn't have to do list available so let's check and see so it is loaded alright so now let's remove this from my session completely i can do that by remove dash module name and then the module name now remove module doesn't actually remove it from the file system it just removes it loaded from your current session when i run this again you'll see that active directory doesn't show up now as of powershell version 3 powershell auto imports these modules so whenever you type a command in it will automatically bring the module in however there may be times where you want to manually import these in for whatever reason you can do that with import desk module so i can import s module name active directory and then get module again then now you can see that the active directory module has been loaded let's remove this again and then one of the other things is you don't necessarily have to have a module inside of one of those module paths for powershell to understand if you place a module inside of any of these folders here powershell will automatically pick it up it's the best practice to put modules in here but i wanted to show you another way to do that so let's say that for some reason you don't want to put a psm1 file in each of these folders with import module you can point to the psm1 file directly so to do that let's grab some information from the active directory module and i want to see where that's actually located at on the file system so i can use list available since it's not imported and i can pipe that to select star to give me all the properties and i can grab down here and see the information here looks like the path is here in the system path notice that instead of a psm1 that's a psd one modules can optionally have module manifest and a module manifest is basically a listing of all the information about that so it can sometimes be the name description all the commands that exist in it and that sort of thing so but we're not going to really worry about manifest for now but so it's suffice it to say if a module has a manifest you can point directly to that manifest or directly to the psm1 file either way so let's say that for some reason this module is not in the ps module path i can do import dash module and then say the specific path of it and then get module again then now you can see it's imported so import module you can just run import module with the name or you can just run it with the specific path now nine times out of ten you're always going to be running it with the name and in actuality as you're just getting started you're probably only going to worry about import module because all this stuff autoloads for you but i want to kind of give you some background we have a list of the exported commands here so you see we have add ad central access policy member and another one with some dot dot dots there some ellipses since the exported commands property here can't display all this in the console maybe i want to see all the commands that exist in our active directory module we can do that with git command so git command has a module parameter here and i'm going to specify active directory after i do that you'll see i can get a really good listing of all the different commands that exist inside of that active directory module and again using help is a good discovery mechanism whenever i first started with a new module i'll explore it so i'll see all the commands that exist maybe i want to unlock an ad account i look through and say unlock ad account here then bring that over to get help put unlock ad account and then get some more information you can dive down a little bit further do the various parameters so we can do detailed and then get various parameters get module and get command they're really good discovery mechanism to really explore modules a little bit better that concludes the basics of modules there's a lot more two modules out there but like i said in this course we're not going to be building our own custom modules and everything basically we're just going to be taking an existing module that microsoft has built and use that i wanted to give you a summary of kind of what modules are and how they work so you kind of understand the foundational things to learn more about powershell i've got a few good resources here i also author courses for the online training company pluralsight you'll find a lot of great powershell courses in that library also powershell.org is another great community resource with free ebooks a forum and a lot more but most importantly just open up powershell and break stuff granted do not do this in production but get yourself an isolated environment and just play around with the commands take a process that's been in the pain in the neck and just see if you can automate it with powershell start small applying a real world problem to your powerful learning will solidify your understanding of the language in this module we're going to get started applying our newfound powershell skills to active directory i'm also going to introduce you to the little project we'll be working on throughout this course i'm really excited to get started here so i hope you are too when just starting out managing ad with powershell the first hurdle you're going to have to jump over is the difference between the gui and the command line in this case powershell both powershell and the gui are working with the same ad database but present information and give you tooling that's very different a few advantages here first the gui is great at discoverability they are naturally interactive since you must click through menus on buttons scroll around and so forth they are also intuitive because you have cues on the screen to click on like a tab name a label a visible scroll bar etc however powershell has some great advantages as well for example a powershell script performs the exact same action every single time you run it it doesn't change at all it doesn't fat finger anything it's also the same effort to do one thing versus many code allows you to just loop over lots of things to do the exact same thing every single time and also powershell code is reusable you can save it anywhere and run it again at any point to do this in the gui is extremely hard to do and is pretty ugly if you've seen those screen scraping tools before and a few disadvantages of the gui here first of all gooeys are not scalable there's no way you're going to say creates i don't know 100 users in the gui and be sane afterwards humans are messy too we make mistakes fat thinkers stuff all the time get distracted and so on and powershell does none of that now i'm not going to say that there are not any disadvantages to powershell obviously you have to learn the language and such but once you get over that initial learning hurdle you'll find that working with powershell is very rewarding before we get too far into building our own scripts with powershell i first wanted to kind of give you a mindset transition from using the gui to using powershell to demonstrate this i'm going to do one task one time with the gui and then one time with powershell i kind of show you the differences and kind of the different ways to interact with whatever task you're involved with to do that i'm going to create a lot of users in active directory from a users.csv file so there's going to be a lot of different employees in a csv file and we're going to create users from this a few different ways here is the csv file that i'll be working with here and you can see i just have one two three four different employees here with first name middle initial last name department and title as each of the columns in here i'm not going to actually create each of these by hand with the gui but i wanted it because that'll take way too long just like in the real world you would get tired of doing this over and over again let's first bring up actor director users and computers here right so if i was doing this without powershell what i would have to do is i would have to open up the folder that i have the csv in i would have to navigate to the folder here so i'm going to do this in real time so i'll grab the folder and then maybe this would be excel or something like this i'll just open it up with notepad plus plus i have four of my employees all right so i'm going to go ahead and try to create the first one alt tab over here and then before i get too far into this though there's a few different rules we have here our company has some kind of standard so we have a standard to wear one ou for each department and we also need to add the user to the all users group so every user goes into that group they all have a common password we all need to make sure every user that i create has to have the password is changed that logon attribute set and then finally the username there's no other username with first initial last name we'll go ahead and use that if not if that's taken then we're going to use first initial middle initial and last name and if that's still taken for now we're just going to say you can't do it maybe we'll go back to hr or i don't know somewhere like that let's go ahead and create the first user so the first user is me adam d bertram i'm in the accounting department and i'm a manager so i will open up here and then because i'm in the accounting department i first have to figure out which ou do i need to be in i'm going to be in accounting all right so i can right click that go to new go to user and type in my first name and last name okay and then go back to the csv file make sure that it's right oh i forgot my initial username first initial last name is default i want to start with so i'll hit next up it looks like somebody else already has that version yes or last name then i will try to go with first initial middle initial last name which is a d bertram try that okay great that worked so i'll type in my standard password twice one two three make sure my user must change password next log on hit next hit finish and then i've created my account now i need to go look back and see make sure i did everything right oh i still need to add it to the all users group to do that i will double click here here it is member of add all users done and i make sure i did everything right yes all right so i've created one user notice how long this took to take place now times that by four and you'll get a good sense of showing how long it takes actually to do all these one by one and plus you have to add into the additional time to account for things like fat fingering and forgetting something and going back and changing it's just a really messy way to get things done like this i'm gonna go ahead and delete this one i just created and now let's do it with powershell so i will go ahead and close this and i will open up my powershell script that i have created ahead of time what we're doing here is more advanced than what we went over before but the purpose of this is not really explain to you what this is doing but give you a good idea of just a general sense of the way that you would go about this in powershell we'll cover a lot of this up in the coming course but a lot of this is a little more advanced i don't expect you to know what all this does at this point so keep that in mind this script works by first i'm reading all the employees in that csv so i'll assign them to an employee's variable that way we can loop through them then i need to find the common user password remember that i used the password i've had to put it in there twice for that one user if i was having to do this with the gui i would have to do that twice for every single user or eight times here i'm just going to input it once technically i could just assign this a variable right here and say whatever the password is here but it's generally not a good idea to put password and plain text here using the git credential command i can grab out that password and leave it encrypted and then here's where the for each loop we're really going to focus a lot on this for each loops the rest of the course but for now just if i just say we're going to do something to each employee in that csv file so the first thing we do there's different rules that are set up in here what you have to think about is notice as i was going through in the gui i was having to go through each rule set for me to pick a user i first tried to create one it failed then i tried to create another one so i did one iteration then i did another iteration right after that by doing this in powershell i can script and automate that stuff in code it automatically check the next one ahead of time and then it will make all those checks in a blinding less than a second to make all this stuff happen so you don't have to actually do all that stuff by hand so this part right here is just trying to figure out the username so it's going to check and see if the preferred username is available and if not it's just going to go ahead and use the second one and then here if that's not available it's just going to error out and say username is already taken unable to create the user so then after it knows the username then it goes down through here and we'll create the user the majority of this code here is just using the new ad user command and i'm using a concept called splatting in powershell i'm doing that because you can see there is a lot of different parameters to this command that i'm using so there's quite a bit and if i keep all this in one line it could potentially go all the way out here it's really not good practice to make your scripts go way over generally recommended to keep it between zero and 150 characters that's the total length of your script length splatting is a really good way to pass all these different parameters that i have here all in one shot to this new ad user command so this is where it will go ahead and create that ad user based on the rules one of the rules was create the ad user in the appropriate ou here using the path parameter we can do that easily we could just say path they make it a variable employee.department so we got department from that csv file so that's where we are defining the path there and then here's the account password we are using that common password we are defining all these common things up here so the ou path is going to be in the csv and then the common password is going to be in the common user password variable so we define all that once and then regardless of 1 10 20 50 or a thousand accounts it's always going to be the same we could just refer to that just like we always would and then once we get the account created then we're just going to add it to that all users group here and that's what the add ad group member does so we're going to add it to the all users ad group members so you can see here that we have each of these different rules kind of separated out the group edition the user creation and then we also have the rule set to figure out the username and since these are built in regions i can just go ahead and collapse these and you can see that i can easily read what's going on here again don't worry about what this script is actually doing at the moment we're going to address this in more detail later on but for now just realize that regardless if we can run this 110 20 different times it's always going to be the same writing great scripts is about translating what you use in the gui to code so let's go ahead and run this now and see what happens so i will go ahead down here in the console here since we're in the powershell ise we have this integrated console let's go ahead and bring the demo path in now that's a really long demo path i have this script in so let's go ahead and run it here we run this by doing a ampersand demo path slash create acme user dot ps1 normally when you're executing a script you don't have to use the and symbol there the only reason i'm using that is because i'm using a variable here demo path to specify the exact path i'm using and i'm doing that by enclosing it in double quotes so that's the only reason i have to use the ampersand here so i'm go ahead and run this and let's see what happens first thing it's going to prompt me for the initial password for each account by default a git credential ps credential and powershell wants a username and password it's going to prompt for a username and password but in this sense we're just using this input to get a password so i'm just going to type in the password here and then just type in anything for the username because we are not going to be using the username in this i'm going to go ahead and hit enter and you can see here that it already output a few different warnings a bertram is taken and d trump is taken it did that because we had some warnings here right warning username whatever the username is taken it did that for each of the other ones so it's really smart you can write powershell to give you really great output and different verbose warnings and things so notice that the verbose statement here this didn't show up well the reason was because we didn't have our verbose preferences on to see that let me actually show you how to run this through with verbose i'm going to go ahead and delete all this stuff out that we just created here so there was one in accounting there was one in generatorial services here and there was one in hr yep okay all right then i have to delete j murphy here so let's run this again and this time i will run it with verbose preferences on so you can see more information about what's going on do that i will just assign verbose preferences to continue then i'm going to go ahead and run this again and now you see the verbose output we got more information about what's going on it gives you a really good way to verify what's going on so just going from the first example there it's checking the username a bertram is that available then it says warning nope it's not available then it automatically goes back to the first initial middle initial last name checking that one great and then now it's creating and then it's done adding the user to the all users group done and then just does that for every single one of them you just define the actions that you want to take on each of those users and it does the exact same thing for each user as with any good course we need a project to work on throughout in this course we'll be building a tool called a.d health check the purpose of this tool is three-fold by building a tool in powershell this will greatly help solidify these concepts in your head it's a great learning tool to use a project like this you'll also come away with a tool that you can use today this will be a tool that can keep active directory healthy in a number of different ways and give you much better visibility into the inner workings of ad this tool is going to be built like a real powershell project we'll go through three rough phases of first figuring out what we need to do incrementally adding on any new features we need until coming away with a finished tool that can be used when we're done this ad health check tool is going to cover five different sections it will first be able to query user accounts and discover interesting information about them like expiring passwords locked out accounts and so on we'll also get into computer accounts as well to discover machines that haven't been used in a while or figure out the computer location and a few other things we'll next get into managing groups our tool will be able to query all groups members of the groups group permissions and stuff like that these sections will cover in the next module next we'll take a look at overall ad health this will entail monitoring ad replication checking on the database to ensure it's healthy building a simple front end to the dc diag tool and a few other things this will be in the module afterwards and finally we'll build some capability into the tool to produce great looking and intuitive reports which put together different sources of data to create a better way to visualize what's going on in your aed environment the prereqs for this course are going to be pretty simple you're going to need at least one domain controller running windows server 2012 r2 or greater you also need a single domain joined windows 8.1 machine or windows 10 and ensure you have powershell v4 on it or later and finally since we're not going to be changing anything in this course you'll just need read writes to a lot of different objects i'll be running as domain administrator in my demo lab just to ensure i don't have any security problems as we progress but you need to know this ahead of time so make sure you have an account that can read all the various objects in active directory there are a few ways you can interact with ad with powershell the easiest is to use the active directory powershell module which is part of rsat or the remote server administration tools packaged by microsoft rsat is a package that consists of different client software like active directory users and computers the hyper-v console cluster management and a lot of other tools is already there as well for us the only thing that matters is the active directory powershell module which is included in there we'll need to get our set downloaded and installed before we can do much of anything to allow powershell to work with active directory we're going to use the active directory module that module is part of a software package known as the remote server administration toolkit or rsat for microsoft this is just an msu package you can download from microsoft and technically we could just go to the web browser download it install it button you know what fun is that this is a powershell course so let's go ahead and do this all from powershell the first thing we need to do is download rsat from microsoft and to do that we can use the invoke web request command here now the invoke web request command goes out and queries any kind of web api that you want and in this instance we are going to be using the out file parameters this command is going to go out to the uri that we provided here directly to the msu and then it's going to save the msu to our local machine as c windows 8.1 and then the name of the msu so i'll go ahead and run this now and i'll show you what happens here so you notice that it's going out and it has a progress bar writing request stream it's giving us an output of how much it's downloaded so far so just think of it as like four man's download progress bar and this progress bar you see here is a built-in feature of powershell so you can use that progress bar for any number of different scripts or modules or whatever you use that take a long while you can always bring up that progress bar with the command known as write progress so now it should be downloaded so let's make sure we'll run test path here test path does return true great all right so we got it downloaded now just like our cmd.xy we can just run xes directly from powershell here so in this case i'm going to use wsa the install switch the name of the msu and then i'm going to do a no restart so i'll go ahead and run this looks like with the isc and with the powershell console you can see that it still can bring up the error messages and the message boxes that you're used to so i think that this is saying that i missed the quiet switch so let's see here as this is installing in the background i'll go ahead and come back here in a minute and we can finish the rest of the demo welcome back our set is now installed so now let's just verify to make sure it's showing up to do that i'll just go into the programs and features control panel apple here with appwiz.cpl so i'll go ahead and run that it's in turn windows features on or off here so it's in the windows features category and when i scroll down you see yep i have remote server administration tools if i drill down in here you see that it contains a lot more than just the active directory stuff you know it has dns dhcp wsus stuff has all kinds of different client features how you can manage various microsoft services that's about it for installing rsat so in the next slide and demo we're going to get into the active directory module itself and get it set up and show you how to use it as i mentioned in the earlier slide the ad module is part of rsat it's the tool that's installed on a client to allow powershell to interact with ad it can be installed in the client which we'll be doing here but whenever a server becomes a domain controller it's also can be installed there as well but it's generally not recommended to perform actions directly on the dc itself anyway the active directory powershell module is the link between our powershell scripts and ad it's pretty involved and has a lot more commands than what we'll be using you'll see in this course that contains over 150 commands that really make what used to be complicated tasks much easier so we've now got the rset software package installed now it's time to really get into the active directory module itself so in this demo we'll go ahead and make sure it's installed properly make sure all the commands are available then we're going to go over some general ways that the active directory module operates so once the rss has installed you go in here into windows and features and then i will go here to windows features and instead of just checking to see if our stat is installed i'll dive down here and go into role administration tools adds and adlds tools and then you see right there the active directory module for windows powershell before this was not enabled and you had to go in here and manually enable it looks like now that they went ahead and just enabling this by default so that's where you would check to make sure the module is installed once you confirm that it's showing up in program the features then more importantly we need to figure out if it shows up in our powershell session or not to do that i will just go ahead and use git module again with list available to make sure it shows up and is available to us looks like it's there it is in c windows system 32 windows powershell v1.0 and module so that's good let's check out the commands that are in it make sure there's all the commands are showing up properly looks like all of the commands here there's quite a bit of commands as you can see so all the commands did show up and now when i did that git command it should have imported it for me automatically so let's just make sure here in order to enumerate all those commands it actually had to do the import so if you recall from the previous modules if i just use get module with the module name then it just checks all the modules that are currently loaded in our session looks like we are good to go here when the module is loaded what i usually try to do first is just make sure i have the right permissions to do what i'm going to do and in this course we're going to generally focus on three different commands we're going to go into some other ones but these kind of three general ones i just want to make sure that i can read a user account read a computer account and read a group in active directory so i'm going to use the get ad user command that's inside of the active directory module and that command has a parameter called filter using the filter i can filter out sam account name equals administrator so what that means is i'm only going to be returning usernames that match administrator so when i run that you see that i did get something back at this point what it is doesn't matter as long as it didn't get an error if i would have gotten an error saying like permission denied or access denied i know there was going to be a bigger problem so i will do the same thing with ad computer that has the same filter and you'll notice the filter is a common theme here a lot of the ad commandlets have the filter parameter and they all operate the same they all operate from the active directory filter so i will go ahead and check and see if i can get a domain controller yep i have permission there and i will finally do the same see if i can get information about the domain admins group and i can do the same there so that confirms that i can at least have permission to read the users computers and ad groups so i know that's going to go here another thing i wanted to mention before we got too far into using the module is kind of the nuances of how this active directory module works here is the typical properties that you'll see whenever you run get ad user computer group a lot of the different get commands in the active directory module you know there's nine or ten different properties that you'll see by default if you remember from the one of the last modules we can typically do select object star which would get all of the objects that are currently there i'll run this again you'll see that we got a few other ones but if you're getting an ad user an ed user has a lot of different attributes to it there's a lot more than just what's shown here you may think well what's going on well a lot of the active directory modules commands have a property parameter directly on the command so you see here with egg the user i can specify a property parameter and then do a star which will then get all of the properties of that object so if i do that you see there's a whole lot more here that's one thing that really tripped me up whenever i first started working the active directory module i would pipe it to select object star and think that's all the properties there but the active directory module behaves a little bit differently than we're used to it's grown some skepticism over time but it's generally just about the best way you can interact with ad just remember if you don't see the properties that you're looking for use the property parameter and then do a star or whatever property you are looking for and one other thing that you may not notice is if you've been working with actor directory for a while you know that each object has specific attributes to it so there is specific active directory attributes then there's powershell properties the active directory modules commands tend to give you a different view of the active directory attribute so let me show you an example of that here is i'm using what i call the old-school way of pulling information from ad with adsi adsi was what we used to use with vbscript it definitely still works with powershell here but you can see that it's much less user friendly than using the acro directory module 4 but on the flip side it does give you all of the attributes for a particular object i will go ahead and just grab all of the attributes for the same account name of administrator and when i do that you'll see that these are specifically active directory attributes so notice that they all are lower case when you do this in powershell it kind of messes with the case a little bit and generally this is output coming straight out of active directory now let's compare that to getting the same information with get ad user here so we'll go ahead and get this same information with ad user output that and then you'll see that it has a lot more properties but at the same time there's a lot in here that weren't necessarily active directory attributes what it does is it tries to make a friendlier output notice that these are specific date times these are bad password time here you know there's a lot of different parameters in here that aren't necessarily active director attribute just remember that powershell adds on additional ones and sometimes modifies the format of the actual active directory attributes a really good example is last logon the real attributes has the last logon parameter here and i believe i can get to it by doing real trips dot last log on the last log on that is actually a date that the time that active directory user account was last used this isn't very friendly you can't figure this out there's some ways to do this in powershell to convert this to a date time but one of the great thing about the actual directory module it does it for you so whenever you do this with the active directory module it has last logon which is that big integer but it also has last logon date and then it has the actual date it does that conversion for you the biggest thing you need to remember is the active directory module does have a lot of great features and makes reading the output a lot easier but do not just assume that the attributes for whatever object in active directory is going to be exactly the same as what get 80 user computer or group will provide to you hello and welcome to the next module in our course interrogating active directory objects in this module we're really going to get down into coding we're going to dive right into powershell and how to use it to perform a number of different active directory tasks there are two different ways to interact with active directory with powershell the first is interactively this is doing things like checking a particular user account maybe enumerating all of your domain controllers quickly or really any other ad hoc task you might choose to do one way to do these ad hoc tasks is to use the active directory provider the ad provider is a way to interact with ad much like you do with a file system we'll go into this topic in the next demo if scripting however you want to use the ad commands like get 80 user new ad computer and so on it's possible to use the ad provider to write scripts but you'll probably find it's much easier working with individual commands instead so let's jump into a demo now on powershell providers how they work and what the ad provider looks like all right so let's go ahead and focus on the first way to query active directory and that's through the active directory provider and as i briefly explained in these slides the active directory provider is similar to a browsing active directory via the file system so let's go over quickly what that's going to look like a powershell is this concept of a provider and a provider is retrieved by using get ps providers so if i run this now on my system you can see here that i have a few different providers here and each of these providers is essentially just kind of a grouping of like things like for example the registry is a hierarchical representation of keys and values similar with file systems you know you can think of a file system folder as just like a registry key because the registry key has values inside of it a folder has files inside of it so it's similar to what a file system is to be able to see those you can use get ps provider here and you can use git ps provider and specify the ps provider parameter here and just to get one of them so let's just say i want to see what file system is you can see here that the ps provider has one or more different drives inside of it the file system down here has drive c and d so that's just your typical c and d drives however the registry up here has the hkey lm and hkey cu drives already attached to it just think of the ps provider and ps drives very similar to the file system to dive a little bit deeper and see what drives are part of the ps provider we can use git ps drive and git ps drive enumerates each of those drives that are part of the powershell providers this gives you a view of each of the drives and each of the providers associated with each of those drives you can see that we have all of the drives here notice that we have the ad drive provider active directory then we have the root of root dse that's because we already have the module imported here so let's just go ahead and remove this i'm going to show you what this looks like when it's not here i'm going to go ahead and remove the powershell module from the session run this again and then you can see there that the ps drive is part of the module importing process so you can see that the aed drive is gone now let's go down a little bit deeper and see each of the items inside of the drive a file system listing with get child item is a very familiar process i would assume just grabbing the files from the file system drive now let's import the active directory module and when i do this you may see very quickly the progress bar that shows you that it's actually creating the active directory drive so let's see if you can see that sometimes whenever it's slower it'll show up real quick but sometimes you don't even see it at all so we didn't even see it at all so you just have to take my word for it here whenever we did that that actually loaded up the powershell provider which in turn loaded up the powershell drive so now we can run this and looks like oh i had the wrong name here so let's just run it without it so we'll use the parameter by position here to find this all right so that worked whenever we run git ps provided active directory you'll see that it has the ad drives inside of it now that the powershell drive is loaded we can just go through it just like a file system just using get child item and the path of ad so now you can see instead of files and folders it brings back domains and application partitions in active directory we can provide specific paths just like we can a file or folder in the file system we can also do that in ad now i just provided the path of the domain name you can see now that it brings down organizational units containers and things like that so instead of files and folders it's just active directory objects one other thing we need to discuss was the filtering whenever you use powershell drives and powershell providers each has a different filter to it if you've used git chat item before to enumerate files and folders you may have seen a filter parameter here if i run this this will actually filter out any files or folders based on my pattern there of star bertram now notice that there nothing came back but then again it didn't also send an error now it didn't give me an error because the file system provider itself understood the syntax of star bertram here so it understood that's the appropriate syntax however whenever you use the filter with the same star bertram here with the ad drive you'll notice that it's going to give you a different output so now notice it says the search filter cannot be recognized that's because each filter that used here is powershell provider specifics so the active directory filter doesn't understand what star bertram is it needs to be a different format i'm not going to go into each of the little nuances between them for now i just wanted to let you know that whenever i use the filter to filter files and folders i just naturally assume oh i have i still have filter on the get child item command here i could just use the same filter to do the same thing for active directory objects or even for the registry no that's not the case each of these has a different filtering language different filtering query syntax that you'll have to learn and kind of get used to one of the most common tasks you'll perform in powershell is building functions we'll do a lot of these in the course functions are sort of like building blocks they are a way to group commands together and all the logic together to form a common tasks functions allow you to start small and then as you begin to accumulate more and more functions you'll find that coding time will decrease because you're able to reuse code a lot functions have three phases an input processing and an output powershell functions are very similar to a script a script can have parameters which can be provided at runtime which is input the script runs which is the process and it can optionally output something a function does the same thing although it's within a power cell session and it's not actually a file let's get into another demo where we'll build a function so let's now get into how to build a powershell function before we do that let's first cover scripts and we're going to be talking about how to build scripts and eventually convert these scripts into functions so let's get started with that the first thing we do is we just start out with a script you've probably built at least one or two scripts in your day but let's just go over an overview of that and as we go through here we'll see that we're going to convert this script to a function i built a script here just called script.ps1 and you can see that this script just says hi i am in the script so it just sends some output to the console here so not anything big at all and essentially a script is just a text file with a ps1 extension so we can open this up in notepad if he wanted to and it will show the exact same thing now because it has that ps1 extension and it's because it is powershell code inside of it the power cell engine understands it and can execute it if you are not in powershell powershell can invoke scripts from the command line so from cmd.exe for example so you don't have to actually open up a powershot console to invoke a powershell script so you can see it here where i will just invoke powershell.exe and pass it a file and then it says hi i'm in the script now since i'm in a powershell console here this actually spun up another powershell process and then ran this script inside of there so at the time it was running i actually had two powershell processes running since i already have the powershell process running here i don't necessarily need to bring up another one to do that i can just invoke it straight from the console here which is the same thing because we have a variable here called demopath inside of here i have to enclose it in double quotes and then i use the ampersand symbol there to make it executable so if i would just put this alone you'll see that it wouldn't understand what it is it just interprets it as a string at that point so it wouldn't actually make it executable let's convert this same functionality to a function first of all why would you even want to make a function functions are great at essentially replacing scripts for the most part so think of a function as sort of like a little building block inside of a script functions can either replace scripts or you can put different functions inside of a script now there's a lot of different advantages to building a function versus building a script for example you may lose a bunch of scripts you may have scripts all over the place and you don't know what they do in the first place however with a function if you can group all that code that you have inside of scripts and do one or more different functions you can just put those in your profile and then be able to have those at your fingertips i can do some of these built-in ones so i can do git content and you know that's going to work or i can do test connection or something all of these are going to work i don't have to worry about the testconnection.ps1 file where that ad so i can execute these functions are always loaded inside of your console so let's just build a very basic function now to show you how to do that to build a function we start out with the function keyword followed by the function name so in this instance i'm building a function called do dash thing one thing you need to realize whenever you're building functions that powershell has a unique way of naming things technically you can name a function anything you want but there's a specific set of approved verbs that you could use powershell has the verb dash noun so it has the do thing so a verb and then a dash noun however i'm kind of breaking the rules here because this do is not actually an approved verb at least i don't think it is powershell has the get verb command and you can see that whenever it returns these are all the quote unquote official approved verbs add clear hide join lock all these all on the left here these are all the verbs that you're supposed to use for your function names you won't notice anything if you're just building scripts and functions by themselves but as soon as you start to build modules you'll see it'll occasionally throw some warnings so you're not using an approved verb or whatever it's really a good way to utilize best practices and so that everybody can understand if you ever share your code what your code does in the first place whatever you create this you have the function keyword here and you have the name of the function followed by curly braces and inside the correla bases you have whatever code you want to do so in this case i just have write output i did the thing every functions have to be loaded into memory so they have to be loaded into your session so to do that in the powershell ise i would just highlight everything and go up here and hit run selection it won't do anything because it's not actually executing that's just loading the capability of the function to be used once it's loaded i can then call it as many times as i want so i do think do thing do thing i did the thing it's actually executing the code inside of here another thing about functions is you kind of think of functions as bundles of code that have inputs and outputs on this function we just created it has an output it really didn't have any inputs you know we ran it and it just output i did the thing it didn't have any inputs however that's not real common most the time you're going to have parameters for things so let's first grab the output of this do thing here into a variable and then once it's in the variable i can run some logic against it so i can run did it equal i did the thing and that equals true whenever you capture a function's output like that you can do all kinds of things in the function you could just capture it into a variable and then do some comparison do some manipulation of the variable and whatever you want to do so let's take this to a different level here and let's add a parameter parameters are essentially just different ways to provide the ability to send input to functions so in our do thing here i'm building a single parameter called attribute and whenever i create this param block here with the parameter attribute then that attribute is available inside of the code itself i can reference in here you can see with this function here i'm running right output i did the thing with dollar attribute that's going to be the name of the attribute whenever i pass it in so let's bring this into memory and whenever i bring this into memory notice that it's the same thing here it just essentially overwrites what i previously had i can now run this and instead of just specifying do thing i can specify a parameter dash attribute and then give it an argument in this case it's going to be whatever so i'm going to run this capture to variable get the variable and now see it says i did the thing with whatever so it's going to replace whatever is in the attribute right here so that's a way to provide a parameter to a function now here's a good example of functions working together inside of a single script so i've already created a script here so let's go ahead and take a look at this so in this script i have two functions and then i have some code inside of the script itself that aren't inside a function this is very common whenever you're working with scripts you'll have the functions declared at the top and then once the functions are declared then you can call and use the functions however you need to down here lower inside of the script but you first have to get the functions available so for this example i just have a small function here called find text file it just essentially looks for a set of text files inside of the c demos folder i also have a set text file which changes the value inside of a file based on the path so really simple stuff and in reality you probably don't need a function to do this because you can do this directly with set content and get child item but just for demonstration purposes we'll just go ahead with this way so the first thing i want to do is i will capture a text file into the output here so i run find text file name whatever this is going to call the function up here and then it's going to search for whatever so it's going to be just like that there all right so we'll remove that let's just load in both of these like i'm going to be calling it all at once so we'll load in both of those into memory and then we'll run text file oh cannot find the path c demos because it does not exist let's just create this folder real quick see demos and i was searching for whatever all right so let's just add a file here now we should have two files inside of theirs i'm going to run this again now that we have the two files loaded up inside of the text file variable i can already tell know from experience that this is not going to work the situation that we have hit that's because we have two files in here and i don't have my set text file function prepared for two files so right now we just have a single path a single value and set content can only do a single file at once actually you know what let's go through and see if this actually works this may be a good educational experience here so we have two files inside of text file and then text file now contains the properties for each of these now let's just see what the text file dot full name is so notice now we have the full name is c demos whatever dot text for both of these so we have two of them in here and i'm going to run set text file and it's going to pass in both of these paths here and it's going to change the value to i changed this file so let's just see if it works i stand corrected because sometimes set content or whatever function or command that you're using you can actually pass in one or more different path in this case we passed in two paths inside of here so let's see what each of those has in them now so it looks like git content can actually do two of them as well that's one thing you need to realize that sometimes lots of different commands have parameters that can do one or more different elements at the same time so for example on this one i could have done get content see demos whatever text and whatever to text so just doing one thing or separated with a comma we could have done c demos whatever our text comma c e demos whatever two dot text it understands that you're passing two files instead of just one and you need to do that to figure out if the command can accept one or more you can use help for that so i'll use get help and i'll use get content for this example here and then i'll use the detailed switch here to get all the details now scroll up and go to the top here there's a lot of stuff in get content so let's find the path parameter actually let's just make this easier we'll do get help get content we can specify the parameter itself i believe it's path whenever you want to know if a commandlet or a function can accept one or more arguments for that particular parameter you'll see that whenever you use help and provide the parameter here of path the top there has dash path that has string followed by two braces now notice the two braces that's what you're looking for there if it doesn't have the left brace and right brace that means that it just accepts one so let me give you an example so let's check out a parameter of the raw notice that raw is a different type raw switch but see switch doesn't have the left brace and the right brace that means you can only put one item inside of there so if you're ever curious if you can provide one or more arguments inside that parameter that's how you would do that so that was our primer into building powershell functions as we go through the course we're going to build lots of different functions we'll go through some further advanced steps so we'll learn more about how to add on to the functionality of a powershell function time to get into some ad objects we're first going to cover computer accounts as our first foray into computer accounts we're going to learn how to read them from active directory using the get ad computer command as promised a powershell learning concept will be attached to these and future demos as well for this demo we're going to focus on building and executing a script learning about dot sourcing and ci can quickly turn a script into a function so let's now get started into applying our powershell skills to active directory so i'm assuming that you already have the active directory module loaded because of that you will have the get ad computer command that will be using in this demo so you can see that i've already created a script and i've called it get varonis computer now i called it git verona's computer because this is going to be part our a project so our group of scripts we're going to be creating now right now get veronica's computer dot ps1 it's not a good script because you can see that i have some demo code here that i'm going to be explaining some concepts for however as we progress through the course i'm going to add some different functionality to this script so that we can use it in combination with some other things so that you can actually use get viron's computer in the real world and query various active directory computers in any way you want in your own environment to get started with figuring out how to query active directory computers and we're going to use the get ad computer command and the get 80 computer command is a very common command that you would use inside of the active directory module so let's just run it and see what happens the first thing you notice is whenever you run it without any parameters it's going to prompt you for a filter it's prompting you because the filter parameter is mandatory so you cannot run get ad computer without providing something for filter we can either do a star in here and then hit enter and it'll go ahead and run through but it's always a good idea to not put any kind of interaction inside of your script you want some autonomy in the script you don't want to have to provide input to a script all the time when you're trying to run this and maybe a scheduled task or some kind of unintended instance to do this we should provide the filter and then specify the star all in one shot here and when we do that it's not going to prompt us anymore as you can see it's just pulling down all of the different active directory computer accounts that i have in my current domain one thing that really got me when i first started was as i was looking through here i would see for example on this bottom computer 1000 and you have all the properties from distinguished name all the way down to user principle name if you look at another one here you can see that each one has those individual properties here just to demonstrate that let's just grab the first one to do that i can use select object dash first one every computer that comes back with git ad computer comes back with an object with a certain set of properties here so let's say we use the first one and we're just gonna skip one so that's the next one so member serve one and then we have dc notice they have common property names when i first started i know active directory i know there's a lot more attributes to each computer than just these few different properties here where do they go so my first inclination was to do something like this i would do dash first one and i was aware of the property parameter here and i would use property star and i would think okay well that's going to give me all of the properties but notice that it added some things in here that don't make any sense property names added properties remove properties property count those aren't active directory attributes now how do i does get 80 computer not even provide these properties well this is a nuance of the active directory module the active directory module has a parameter called properties that allow you to specify these there's a lot of talk in the community where the active directory team at microsoft didn't really design the module quite right not adhering to the typical community standards but we're not going to go into that in a moment anyway to get all the properties with get 80 computer you actually have to use a star here on a different properties parameter just specifically related to get ad computer so when i run this now you'll see a lot of different properties in here so just so we don't have to scroll through each of these i'm just going to grab one of them so i'll specify properties star now notice that most of your active directory attributes come back and you'll see that you can get a lot of the information from a lot of these if you're just kind of looking at this you're eyeballing this you may think well this is all of the active directory attributes for a particular computer well that's still really not the case there's a lot of things like the custom attributes the exchange things and there's a lot of other less used attributes that don't show up in here but for now this is the huge majority of the aed attributes that you'll need for an individual user account this is pretty much all there is to get a d computer now you can go through the help and there's a lot of options inside of the help we're going to go over filtering a little bit later but just to get you familiar with get ad computer and what it does really that's just about it if you're running this on a domain join machine and you have the ability to query active directory computer accounts you'll see that it's really easy if you're trying to enumerate active directory computer accounts in vbscript it's a whole lot harder that's why i chose to use the active directory module even though it has some nuances like the properties parameter there it's so much easier to save so much time to be able to query things out of actor directory next up is 80 user accounts 80 user accounts are retrieved using the get 80 user command you'll see that this command is similar to the get ad computer command so we're not going to spend a ton of time on the command itself instead we'll focus on the powershell learning concept in the upcoming demo we're going to learn how to query ad for user accounts from a first name and a last name instead of just typing them into the console we're going to use a csv file to read these names from and then pass those to active directory to do that we're going to learn about loops in powershell and how they work as well now that we went over ad computers let's just go ahead and see if we can query ad users you'll see that querying 80 users is pretty much the exact same process of querying ad computer because after all a user and a computer are just objects with attributes inside of active directory so the same process applies we just replace git ad computer with get ad user and the commands have the same exact behavior filter is necessary here so we just specify filter and you'll see that we have all of the active directory users that come down same thing with ad computer where it doesn't specify all of the properties at once we can use the properties parameter with the star or if we want to we can bring down individual properties by specifying individual ones so let's just say we want to do password expired and you see that we have password expired there's false however if we dig it out no properties at all you see no password expired here and if we want to do all of them we can just do star and this is exactly the same process with get ad computer so i'm not going to go over that anymore because this course is going to be not just how to work with active directory in powershell i'm trying to teach you powershell at the same time and this is a really good area to do this in with getting when you're working with a set of objects or a set of data in this case we are working with a set of ad users a common reason to use git 80 user is that you have a set of users that already exist somewhere in a csv file in this instance i have a csv file full of users so let's just go ahead and see what's in this csv file to read a csv file with powershell you use the import csv command and then specify the path of the csv file itself so i will go ahead and run this assign that to a variable and now i have csv users now you can see in this csv file i have first name and last name and they each contain different employee name whatever have you so i have this in a csv file now this could be a csv file this could be a sql database this could be an oracle database this could be just about an excel file this could be any kind of data source that you want powershell has ways to grab whatever data that you need from a specific data source and compare it with another one that's what i really like about powershell to do this i'm going to use the csv file to filter out the active directory users that i want to see before i just specified the filter parameter and then set a star so i wanted to see everything well in this instance let's just say i just want to see the users inside of this csv well notice that it's just first name last name there's no unique account name so we need to do some matching to make that happen to do that i'm going to first grab all of the ad users with git ad user and then specify the star parameter here so i have everything saved in all 80 users this brings us to loops in powershell the first kind of loop i'll show you here is called afford each loop now i'm using what's called a for each statement here and a for each statement is declared by specifying the for each keyword here and then in parentheses you do used to have a variable in and then your data set so in this case the u variable is going to represent the iteration variable so it's going to reference in this case each user that's represented with all 80 users if i just put this to the console you see that it does everything really quick so it just dumps out everything all together this natively iterates through each of them in here but it doesn't allow you to actually do anything to the users as they're iterating through so if i run this for each loop i'll see that it does the same thing you're going to get each of the users displayed out here in the console i'm essentially just reading every user inside of this all ad users variable and then just outputting it to the console well that's great but that's not very useful because we can do the same thing by just outputting all the 80 users which would do the exact same thing the benefit of using the 4-h loop here is that you can do things to each of these users as you're iterating through now i'm going to do the same thing here and just do it for csv users so remember that where our csv users we had each of the users with first name and last name so we have multiple different objects so each of these first name last name is a different object we're going to iterate through each of those objects and then do something to each of those in this case we're not really going to do anything we're just going to use those as input for our search query for active directory users so in this case you see that i'm going to iterate through each of the csv users each iteration variable is going to be called csv user so let's just take this back a notch here and then let's just do what csv user dot first name whenever we display this you see that with the dot notation we can reference that object property and just specify the first name here we get the first name the same thing with the last name if we do last name run all this again you see that it gets the last name it's just iterating through each of those different objects inside of there what i'm doing here i am using the csv user first name and last name as input to where object to pass to my where object filter to filter out users inside of there to demonstrate this let's first grab the count of all the users to do that i can just do this and just do count so that i have 22 users inside of my all 80 users command now whenever i run this that's all the users but i don't want all of the users i just want just the users inside of my csv file to do that i'm iterating through each of the users inside of the csv file and using each of those iteration variables so i'm using the iteration variable csv user then just doing first name and specifying last name here this will represent the first name and last name of each of those usernames i'm doing this putting this in the where filter because all ad users each of the objects inside of there have individual objects as well so let's just do one of these here select object first one so notice that i'm going to be using given name and surname surname here in this instance it's nothing and given name in this instance is nothing as well so i'm going to be referencing each of these in my where object filters essentially as the for each loop goes through every single one of these csv users it's going to fill in this where object filter script here and it's going to compare does the first name and last name equal some given name and surname inside of active directory users let's run this and see what happens so it did find some users so let's see how many let's find i'm just curious here here's a quick tip for you i'm just going to make a little counter variable here called i i know that if this statement right here if this returns anything at all right now it's going to the console but i just want to see if it actually returned anything to do that i can just enclose this with an if statement inside of my 40s block here so this just says if you returned anything at all that means in this case if given name is equal to csv user.firstname and surname is equal to c is the user.lastname if you return to anything at all then do plus plus which is a shortcut to increment the value of i in this instance now that's going to increment that when it finds a match for each of these so just a real quick way to see give me a count so i will copy all this all here and then now i'll see what i is see that i is 14 well that means that for 14 of those 22 users there was a match inside of all ad users you'll see these for loops are very common in scripts they're really good way to iterate through a common set of data sources and you can do all kinds of different things and we're going to be going into more depth and use things a lot further on in the course next up is groups groups just like users and computers are objects in ad as such the active directory module has the same general naming scheme for the command to retrieve groups called get80 group since groups are a little different than computers and users since they have sub components called members inside we also have a get ad group member command that will help us retrieve those as well as for the learning concepts in the upcoming demo we're going to dive into objects and properties we're going to go over a great example to build your own custom objects to get the output you're looking for i've also intentionally broken this one down in incremental sections as i was building the demo it progressed into multiple stages and kind of grew from there you'll see that this is a common occurrence when building powershell code the upcoming demo is a great overall representation of iteratively building onto code next up is ad groups just like with ad computers and ad users we will use get ad group very similar have to use the filter hit star and bring down all the groups exactly the same as the other commands this time we're going to be getting into one other command here called get ad group member groups are a little different than users and computer objects because a group has sub objects inside of it called group members that's why we have get ad group member here so let's just go over a quick demonstration of what get ad group member looks like let's say we want to grab all of the members of the domain admins group so we'll say domain admins equals get 80 group member identity is domain admins i mean admins here's all the group members inside of there so we have three it looks like let's just limit that down to name we have administrator the sccm and then an it admins group inside of domain admins so that's essentially what get ad group member is i'm going to be using this demo for groups to show you a real world way that i write scripts in code and things like that it's an iterative process so you look at one thing you see the output like no that's not really exactly what i wanted i'll tweak it this way and then no that's not really what i wanted i'll tweak it that way so this is what i'm going to be doing here so in this instance i want to build some kind of output that allows me to see all my groups with all of my members you can sorta do this with the members property of each group whenever you specify filters and then look at the members property of each of the groups you can see that it has a member's property and then it has each of the members inside of there so let's limit this down a little bit and show you what this looks like so let's look at the first group here so that one doesn't have any members in it let's just do skip five of them backup for operators look for one with some memories in it all right let's cheat a little bit just to where name equals domain admins technically we have the name of the group and the members inside of it but notice that in the members we have groups inside of members computers and users so let's just expand this out if we do expand property that's just going to bring out everything you'll see that we have it admins is a group sccm is a computer and administrator is a user now what if i just want to see all of the users inside i don't want to see anything about groups i don't want to see any computer accounts so how would we do that so right now it's not possible we need to redesign it a little bit let's just go a step further here's a good way of using the for each loop to do that so let's first grab all our groups again and then inside of the for each loop here we're going to run git 80 group member and query out only the user in here so wherever the object class is used so let's just run git 80 group member again on domain admins and then we do select name and then object class notice that it tells you if it's a user a computer or a group whatever the class of the object is now i can limit that here by doing user so let's just do one instance this is another good example before you do the loop you want to make sure you get your code right to just do one so let's just say i want to grab all the users out of here so let's say this is object class equals user and then notice that it just pulled administrator out so that's a way that i can pull out just users for the domain admins group but i want to do all of them to do all of them i can assign them all into our groups farewell here and then use a for each loop to iterate through every single one of those in this instance i'm running the for each loop i'm going to run git ad group member for every one of the groups where the object class is user so only grab the users out of each of the groups and only show me the members property now notice that this sort of works the reason i say sorta is because this is going to last forever because the display doesn't look right to display this out to the console i'm using the group.name here whenever i just specify just group.name it's going to output that name property to the console and then it's going to output to the console the result of line 18 here now notice that it's not very intuitive so for example we have the administrator group and then we have members below it we have users guests print operators backup or operators this doesn't work because it's actually showing groups as well as users so i need to actually change this property here for members and that needs to be named now let's see what that looks like now that looks a little bit better real world on the fly troubleshooting here now this will work but the display is terrible and i'm not going to really understand this now i'm not going to know that this is the group name and then i have name and then the dashes administrator i can't see what the group name is and what the members of the group name is we need to build custom object here to make this better looking so we can understand it better so to do that i'm going to create a custom object i'm still going to use a for each loop and i'm going to iterate through each of the groups again however this time you see here in line 23 i'm building a powershell hash table so i'm calling it output and as i iterate through each group i'm going to add items to this hash table and then at the end i'm going to convert it to an object and then i'm going to output that here on 23 i'm building a hash table for each of the groups then on 24 i'm defining a group name key and i'm making that one the group.name so this is the name of the group then on 25 there i'm getting that same output and then just grabbing all of the group members inside of there and then on 26 i'm creating a members key and assigning that all of those group members that i just grabbed and then on 27 that's where we have ps custom object this is a really good way to create custom objects from hash tables so you define ps custom object here and then you put a hash table right after that and then it does a translation or a conversion in the background so let's just see what this looks like now so yeah we have members and they have group names so like the winrm remote wmi users group name doesn't have any members the administrators group has the administrator member users not everything guest just has one print operators but notice that it still isn't that good to see yeah it's nice i can sort of see what's going on but i want to take it a different level i don't want to see the groups with no members in it just seeing all the space along the left there it's not very intuitive so to do that i will put some if then logic here on line 40 if there's anything that return in group members then only create the members property and then output object else if since i don't have an else in here it's not going to do anything whatsoever so i'm going to run this again now you'll see that there is no big space on the left hand side for members you'll see that we have group name administrators members of administrator guest schema admins administrators you'll see that there's no space it's a lot more intuitive that way however this really doesn't even still look the best we can even take this step a little bit farther by formatting this output example there for the domain users group you'll see administrator dot dot dot that is cutting that off because the console can't display that now there's some different ways to do that but let's just use the format table here you'll see a lot of different commands called format list format table these are ways to make the display to the output a lot better so the format table is another quick way to change the output see what it looks like i was saying format table than doing the auto size which adjusts to the size of your console and when i ran that you'll notice that it didn't still even look the best because it had a space here between your outputs of each of your objects so it really didn't even look the best the reason it did that was because it was piping this output here this ps object 2 format table for every single group because i was in the for each loop it was doing that for every single one i want to do a format of everything at once you may think well i'll just take this out and then i'll put this down here right below my curly brace that ends my for each loop now you notice that an empty pipe element is not allowed so you cannot pipe everything that comes out of this 40s loop to format table auto size to do that we can use another type of for each loop here this is the for each method now this was introduced in powershell version 4 so you cannot do this with any other version but the for each method is on collections inside of powershell so since i know there is more than one group inside of this groups variable i can specify four each so this is doing the exact same action as that for each loop previously it's just going through each of those objects inside of groups so each of those groups and doing something to them so in this case i'm doing the exact same code so everything here is exactly the same as what it was before but now notice that i'm allowed to format table auto size at the very end of it so now when i run this it's going to wait until it accumulates all of the groups and then finally when it's done it's going to output that all at once and then send that all to format table and then it's going to output it into a very nice format so notice that we don't get any output now while i'm talking before it was sending things out the pipeline to the console constantly now since we're using format table it's actually cueing all these objects up and then it's going to spit them out all at once and run with format table now notice that it's much better looking we have the group name we have the members for each you know we have on the domain users group see that expanded out so we have administrator the kerberos katie holmes s help desk so let's expand it out a little bit more to be able to fit these two columns on the console we were able to see a very nice output there that was a good example of iterating through and just eyeballing various objects and properties in the display format that you need this is going to be a very common occurrence whenever you're building scripts in powershell you're going to first figure out how to do one thing let's say figure out how to grab a group once you do that how do you figure out how to grab all the group members once you do that you see that it's just a building process the power shells are very good at a building process so using building blocks to build over and over and make things better and better we have already done some collection filtering in the previous demos but i really wanted to build a section here just for this purpose that's how important this concept is and not only when clearing ad but any kind of large data set if you're aware of some best practices around collection filtering your scripts will perform much better in the upcoming demo we're going to cover two ways to filter collections one way is with the where object command which we've used earlier and also we're going to cover the where method which was introduced in powershell v4 i'll go in depth on these two general methods of collection filtering and explain some nuances that you might run across so in our previous demos we essentially returned everything that commands like get 80 computer get 80 user get 80 group get 80 group member all of those commands we just returned everything that we could possibly get in there we didn't actually filter out anything the majority of the time you're not going to want to get everything in active directory especially if you're in a big enterprise where you have tens of thousands or hundreds of thousands of object natural directory you're going to need a way to filter this out now there's a few different ways to do that so in this first demo on filtering we're going to just talking about the basics of filtering using the where object command using the where method so let's get started with that so the first thing i need to do is i need to build an array so in this instance it's just going to be some kind of source of collection of objects so i'm just going to make an array with 11 different elements in it i'm doing that with the range operator here we can use the dot dot which is a quick way to get elements inside of an range see it's 0 through 10 here so we have 11 different elements inside of this array let's just say that i want to only get certain elements inside of that array i want to filter them out one way to do that i can use the where object command the where object command is a very common command that you can use to limit the output of a number of different commands it's not assigned to just this array it's not assigned to get content to get ad user to get a computer essentially where object can be thought of as a generic filter it will filter out on any kind of output that you can possibly imagine so for this instance i'm going to limit the output of anything that's greater than 2. so to do that i can just use specify array pipe it to where object and then do my pipeline variable my dollar underscore which is greater than which is the gt operator greater than 2. whenever i do this i see that it just gets me 3 through 10. i'll admit that i was using a quick syntax so i'm not using the full syntax here i'm using a positional parameter you probably won't do this the whole lot in the real world but this is actually the filter script parameter to the where object command so this filter script parameter here this essentially just means if anything inside of here based on every item coming out of this collection is true or is some kind of output as long as it doesn't output either a boolean false value or null it will go ahead and output anything i could even do true and this will output everything i'm not checking it against one of the elements inside of the array i'm just going to say just true for everything obviously everything comes up this is a condition that gets evaluated against every single one of the elements that are there because i have an array of 0 through 10 i can use that because that is my pipeline variable that's going to represent every iteration inside of there so when i just do this because dollar underscore is something notice that now it's just 1 through 10. previously i had a 0 in here it didn't output the 0 because 0 is another form of boolean false under the covers this does a conversion so if this does not output anything other than a zero a boolean false value or a null value it will return so if i just do false here it will return nothing if i do null it will return nothing and if i do zero it will return nothing as well but let's just say i do i don't know 56 something random it'll return everything because it returned something other than those three different values however if you want to run conditions based on items inside of that array you can do your dollar underscore greater than two or equal to six whatever code inside of here evaluates to some kind of output other than the zero false or null then it will evaluate to true and it will send that individual element outside to the console so another way to do that is to use the where method as i mentioned previously went over this a little bit in the last demo that was using the for each method in this instance it's the where method and as of powershell version 4 we have this where method here and the where method is exactly the same as the where object command the only difference here is that the where method does not use the pipeline so notice here on line six here that i'm specifying array then doing my pipe variable and piping all of that to where object this actually goes through the pipeline however with the wear method here you notice that i have no pipe symbol i'm just using dot where just defining a where method now this is generally faster than using where object you won't see it too much on little data sets like zero through 10 but you will notice on like tens of thousands of items in a data set where if you're not using the pipeline the pipeline degrades performance and it really adds some time to the filter this will be significantly faster if i'm using powershell version 4 or later i will always use the where method because it's pretty much exactly the same as wear object but it's faster now you can also use the in operator as well here so if i run this it gets me 3 through 10 and i can use the n operator here because this is essentially saying if anything any of these 0 through 10 which is the dollar underscore there is in this array 3 4 5 6 7 8 9 10 then evaluate to true now i'm using in here for an example but you can use that across any number of things you don't even have to use a where method or the object command to do this you can actually do things like this as well so if you're filtering you'll notice there's a lot of different ways to filter you know i can do this not even in a filter script 3 is in there that's true 6 is in there that's true 66 is false filtering out elements in a data set a lot of the times you'll use where object but other times you may use something like this you may have an instance to where you're having some if then logic if 6 in whatever here then do something so it's all about bringing all these things together and figuring out the best way to filter things out you see that we can use in as well going back to the same principle that we showed you up here as long as the code inside of the curly braces here outputs anything other than zero boolean false or null it will output everything so when i run this it didn't tell me hello it just returned all the items inside of that array consequently if we do this maybe a for each for each doesn't actually filter out anything it just gives you everything out of the array but since this is a for each this is going to actually send to the pipeline run for each same thing iterates through every item in that array but it just says hello so where is good for filtering for each is good for generally reading all of the elements inside of the array so that is the first basic filtering demo coming up we're going to go into more advanced scenarios on filtering there's a concept in powershell known as filter left this is a term that was going to represent a best practice the best practice to filter collections as far to the left in the command as possible this means not using where object or the where method at all if possible why well it's because those two methods take the output of the previous command and filter why not give those commands the absolute minimum number of objects to work with in the first place typically filtering left uses a provider specific filter these are filters that are applied by providers themselves like the file system active directory and so on as such they are much faster and are more efficient than simply throwing everything into the pipeline you'll find that this concept yields the greatest benefits in large environments or when working with large data sets it can mean the difference between waiting for a script for a few minutes or even an hour or more if the dataset is big enough in the next demo we're going to focus on this filter represented as the filter parameter with the ad commandlets i'll also go over a few other tips to really fine-tune your ad queries as well so now let's time to cover some more advanced filtering techniques i briefly touched on this in a previous demo where i explained the difference between the various provider specific filters so i'm just going to give you a brief refresher on this and then we're going to be talking about the active directory filter specifically and then after that we'll go into some of the different parameters you can use to really limit the scope of the things that you can find with the actor directory filter every filter parameter for get child item for example is different based on the provider when you're using git child item with the file system provider as i am here you'll notice that it doesn't return any files because there is no doc files in the windows directory however if you use this then it's going to say the search filter cannot be recognized because the filter syntax that the file system provider uses versus the filter syntax that the active directory filter uses is completely different this is a topic that still to this day i've been writing powershell and messing with the active directory module for a very long time now you'll find that the active directory filter itself is not very intuitive it's more of a thing you have to learn if you're unfamiliar with how to use the syntax for the actor directory filter there's actually a help topic on it to get to that you can use git help and then the about active directory filter here so when i run this you'll find that it's a pretty complicated subject you think well it's just a filter it's easy to learn it just to some syntax but if there's an entire help topic on something you know it's not very simple so if you just use get help about active directory filter you'll see that it has examples for everything you can possibly think of here it tells you everything the specific just to the active directory filter so going down through the examples here notice that the active directory filter and essentially is a wrapper around an ldap filter so if you're not familiar with ldap ldap is the essential directory that active directory is built on top of it's just another way to query out various attributes for example on this first one here you'll see that the filter is object class like star and that's equivalent to the ldap filter of object class equal star that seems logical and see that cm name like bob okay that seems logical too however you'll find that there are some instances where i don't know if it's in the examples here but you'll see some instances to where things aren't intuitive i'm not going to go into a lot of details on this but i just want you to know that whenever you're doing filtering with active directory your first choice will be to use the active directory filter because you're filtering left of the pipeline that means that if you use the native filter your performance is going to be much better than if you're using something like where object or the where method because that's actually filtering everything after the fact this is going to be a learning experience for you we're not going to go into this in detail you could take up an entire another module or something to talk about how to manipulate these active directory filters so fights to say there's a good starting point for you the help topic so if you ever have any problems reach out to the help topic or reach out to the community we'll be glad to help you the next way i want to show is limiting the search for your ad command list based on the ade command list parameters to do that let's first see how many users we have in active directory we have 22 of them so there's a few different ways to do this let's say that you only want to get all of the users in a specific container or a specific ou now you could query that out by doing where the dn equals whatever in this instance i'm using the search base of just finding things in here so let's say that i just want to find the users in the user's container and the root of mylab.local here i could do something like this so let's say i want to do filter let's first see the dn of each of these so select distinguished name there's all the distinguished name now the our container that they're in is part of that distinguished name because of that we can filter on that so let's say that filter distinguished name like do the star star see that did not work because it may not be distinguished name inside of the filter it may be dn see things like this it's not very intuitive because even as a powershell scripter of many years there's still many things like this that don't really make intuitive sense to me you would think distinguished name like and then that would work there's some reason inside of the syntax for the active directory filter that that does not work however you'll find times when you'll do something like this you'll say well forget it then i'm not even going to use it i don't care about shaving off a few seconds from the query i'll just do something like this i can do get everything where object dot distinct wish name like see there that actually worked the syntax for wear object is a lot more intuitive than the syntax for the actor directory filter and i mean that's not essentially the powershell team's fault that's the fault of the filter is actually dynamically building all these complex ldap filters in the background to do that and granted it will be a little bit slower than using the filter parameter but the majority of the time if you're not worried about shaving a few seconds even a thousand or more different users it really doesn't matter that's one way to get all the users in that specific ou you could do this but it's not the recommended way because the ad commands already have a parameter to do this without having to pipe everything to where object to do this you can use the search base parameter the search base parameter just essentially says start searching for this particular active directory object in this ou or this base object so now when i do this again it should work and then when i do select distinguish name again then notice that they're all in that users container again granted we didn't use the filter but using the search base or this search scope which we're going to go over here in a minute that's essentially the same thing because if you use either these and the filter or a combination of both all those elements get combined into an ldap query at the end of the day whenever the command runs against the active directory database all that stuff all these parameters in this filter will all get combined into an ldap filter which will then return the objects that you want to see so that is the search base we can also do another limit by search scope let's say that we want to find all the users instead of the user's container however if we go over here and let's say we want to find all the user inside of the automation list oh you there is a user here just some random user inside of automation list and there's a child ou in here let's just create another sample user inside of this child ou so there's one in automation list and there's one in the child now you here so now let's just say that i want to find all the users inside of automation list to do that i'm going to change this to automation lists and this should find all of the users inside of that automations ou notice that it returned two because it returned the one inside of distribution lists that sub ou and it also returned the one inside of automation lists now let's say that i just want to see the users in the automation list value not on any of the child i use we can change the output of this by using the search scope so let's first grab this and bring this down here and then now let's play around with the search scope immediately it recognizes the available options i have let's do subtree here and see what this does all right it still returns something notice that it still returned everything we need because subtree will return all of the users inside of the current ou and all of the child i use however let's say that you want to just get the user inside of automation lists notice that now it just returned the users inside of the automation list so we didn't actually go and down inside a distribution list so search scope is another good way so you can use the search base and search scope and also the filter on any different combinations that you want so between all of these and if you possibly can't get the filter that you need then you can also filter active directory object in a number of different ways an active directory powershell course would not be complete without specifically talking about the search ad account command this is a command that's essentially a shortcut to common queries it's a command that saves a ton of time to quickly query various items around users and computers although it's really not feature rich you'll find that for small things like finding users with expiring passwords maybe getting disabled accounts and the like are much easier using this command rather than filtering out all these properties yourself in the next demo i'll go over some common uses of the search 80 account command no course on powershell and active directory would be complete without a demonstration of this search ad account command now i'm focusing an entire demo on the search 80 account command because it is that important the search ad account command is going to save a ton of time and really makes things so much easier to do ad hoc queries to pull different things users and computers and things out of actor directory so let's just briefly go over that so first off let's just see what we can do with search ad account by using help here and i'll use the detail to see all the different parameters here you'll see real world typical queries that an active directory administrator may want to do so for example on the top there we have account disabled finds all the accounts that are disabled account expired finds all the accounts that are expired account expiring all the ones that will expire within a certain amount of time inactivity locked out password expired so notice that this gives you shortcuts on queries that you could use with the where object or the active directory filters let me just give you an example here so let's say that you want to find all of the users in ad that are disabled with our previous knowledge before you talking about search 80 account we could do that by using get ad user let's say it first try to do the active directory filter because it's usually better it's faster to this way so you kind of fool around with it so let's say enabled equals false so maybe that'll get it we got all of the users that are not enabled which thus they are disabled so let's just make sure if we go new name and then the enabled so we found all of them that are disabled this is a legitimate way to do it so that's one way let me show you another way here let's say we don't want to use the active directory filter and then we'll just use a where object we can also do something like this where enabled equals false select the name and the enabled property and we get the same thing two different ways of doing the exact same thing now let's use the search ad account the search ad account has a specific parameter just for this purpose account disabled because the search ad account by default gets both computers and users we just have to specify users only and let's limit that to the name property and the enabled property same thing which method do you think is more intuitive probably the search ad account because it's immediate i want to find all disabled accounts and only users you can infer that from the other ones but it's really not as obvious you can use the same approach for any of the parameters in here so if you just tab through you can say account expired looks like i don't have any you can just play with this all you want here account inactive locked out is there anybody locked out so there's all kinds of different things that you can do here with this password never expires it looks like we got a few there so it's a really easy way to do it here's another one that's requires more than just one parameter let's say we want to find all the accounts that are inactive tapping through we have account and active and we want to find just users brought back a whole lot of things because the account inactive parameter requires either a date time parameter or a time span parameter to limit that to i found that the easiest way to do this is use the time span so let's take this a step further and see if we can find out the users that either have never logged on at all or their account hasn't been active in a certain period of time so to do that we have search ad account we can use account inactive then we only want to use get users here so let's say we want to do users and then we can do the time span of 90. you'll notice that time span can be a little complicated sometimes that really doesn't make sense well is that 90 days but yes this is 90 days to get more information about time spans you can actually build time spans with new time span i'm doing this on the fly here so let's see how this works so right now there's all the users and their last log on date so notice a lot of them have never logged in and there's only one that has logged in that just has a date to it let's just count how many these are and we'll do a comparison here 23. so now let's try to build a time span to do the same thing instead of specifying the 90.0 and all that with the string let's just do a time speed here so we'll do a start of 90 days ago so let's see if we can do something for 190 days ago 90. so notice that's 90 days ahead of time we can also do negative 90 which is 90 days ago all right so now this may be a little easier for you to understand we do new time span days negative 90 24. so that's the same thing as using the 90 string to me i try to find ways that are easier to understand since this method has days in it and negative 90 that's makes more intuitive sense to me and you can do the same thing for a lot of these other parameters as well so we can do account expiring that limits the amount of users by the expiring you can do account inactive there's a lot of different parameters in here that you can do i'm not going to go over each one honestly they're all pretty intuitive but if you're curious and if you ever need to quickly run queries on active directory for various things i highly encourage you just to run help search account detailed and then run through all of the different parameters that they have there's a lot of the parameters some of the parameters are common to the get ad user get 80 group so you notice we have search based search scope you can still limit your searches to whatever you need to but also now you have all these great switch parameters where you can just specify password never expires or password expires or locked out you can specify all those things by just saying intuitive i want to find all of these users that meet this criteria it's a lot easier to understand than trying to figure out how to manipulate one of those active directory filters or even a wear object filter script all right so the time has come for the final demo in this module in this final demo we're going to put everything you've learned together and build our ad health check script we'll reuse the work we've done in many of the previous demos to build a nice tool that will allow us to gain better visibility into a few different metrics in ad what's most important though is that we'll lay the groundwork for you to add additional functionality to this script by doing this you can take whatever you've learned here and customize it for your own environment as promised earlier in the module and also in the course we're going to take all of that learning that we went through in the previous slides and demos and put that all together to build a little tool here that will allow us to get a good summary of various counts of objects and components inside of active directory that you can just run one script and get an example summary of what your active directory environment looks like to do that i've built a script called invoke ad health check here as promised before we are using the same scripts that we built previously called get verona's computer varonis user and varonis group however i've modified those a little bit so that now instead of being standalone scripts we can actually easily consume those as part of this larger tool for the most part these are exactly the same functionality as they were in script but you can see that instead of a script they're actually functions now so i have one function with the same function name as the script name so for get varonis user here i have a single function inside called get varonis user and to provide some kind of ability to change some properties because that's going to be necessary in our ad health check tool i've also built a single parameter called properties here it's setting the star or asterisk as default this function is a symbol wrapper function around get 80 user which essentially when called it just calls get 80 user and passes whatever properties here directly to the properties parameter of get ad user and the same thing for get ad computer exactly the same in the real world you probably wouldn't write a simple function like this at which hall's get 80 computer with the same parameters the reason why we are going to be using these same scripts now is because there may be times where whenever you are getting a computer account or a user account from active directory that you may want to do something to that output at a certain time for get ad user for example so maybe you want to return home folder paths or maybe exchange mailbox information you would do that by manipulating this script and not the main scripts you would be manipulating git verona's user here and then anything coming out of git verona's user would be your home folder exchange mailbox or what have you get verona's group that's the one that's a little different since it was more complicated than the others we're doing the same general concept though we are just calling git verona's group with the properties here and we will define properties here this needs to be members because we need to pass members to that then it creates that custom object force so this is a good example of why you would want a function as a wrapper to the various command lists because we can do custom code like this and do custom output each of these scripts now contains a single function now since i want to use those functions i can't use those functions off the back because they're in different scripts so first we need to bring those into session or load those into memory and to do that we can use the dot sourcing which we discussed a little bit earlier in this instance i'm just saving some time here defining all of these scripts that we have an array and then using a for each loop to loop through all of them and then notice the dot there we have a dot and then the scripts path slash whatever the script name is and the script path is just the demo path that i'm working with here so as we dot source all those scripts each function inside of the scripts will become available next on line 15 there we are defining our output hash table so similar to what we did with groups we're defining an output hashtag which we will then output a custom object at the end there and then on 17-19 we are actually calling each of those functions and grabbing everything that we need in this instance we are grabbing all the objects that come from git veronica's user bernoullis computer and veronese group computers and groups we're just using the default because we are not passing a parameter here it will just simply use the default which is star for each of these but for users since we need to manipulate the properties a little bit for some things we're going to be doing later on we need to define our own properties to get so in this instance we could say getting all the properties and then since the msds user password expiry time computed property isn't default even when you specify the star we're going to need that as well so we can pass different properties here to this function so once the script goes down through all these then this is an option to where i wanted to get expiring passwords this instance here goes through each of the active directory users and finds all of the user accounts that will be expiring in less than 30 days this is an instance to where the result that we need is not inherently built in into the active directory module this is a good example of a time whenever you have to actually do a lot of coding and figuring out things ahead of time this is an instance so where we actually have to dive in and really start googling around and figuring out how to do this in this instance i'm just getting expiring passwords and to do that i'm using the where object in ad users where the password never expires and password is not expired these are the easy ones however to actually get when the password will expire is a little bit harder because that attribute isn't natively in active directory we have to kind of compute that on the fly to do that i'm using this date time type here and using the from file time static method so with that from file time method does is that's getting the date which is the password expiry time computed which means that is the date when the password will actually expire since you know that we don't want when that date is we want to know how many days is that so to do that we subtract the current date from the date that was going to actually expire and if that's less than 30 here it's going to return true and i'm gathering all of these things up here and this is all one command and getting the count of it so we're getting all of the users that have expiring passwords less than 30 days and assigning them to the expiring passwords property here and then going down the rest of this here it's a little simpler one thing i wanted to know here i'm saying that i'm not using search 80 account because we just went over the demo of search ad account and a lot of this information here the expired passwords lockdown accounts for example that's really simple to use with search ad account however i'm not doing that here because we are doing a lot more things other than just those one-off search ad account is really good for finding those one-off things however if you're building a tool like this because up here we are already getting all the users that we need all the computers that we need all the groups those are making a call to active directory so it's going out and actively querying the domain controller that's why we don't use search ad account because search ad account if you use that over and over again that's just going out and making a call to the domain controller over and over and it's not really efficient if we've already made that call and we already have all the objects we just need to do a little bit of filtering ahead of time so that's why i'm not using search ad account here here is where i'm just defining all of the output properties that we need so i want to see how many computer accounts are in ad how many users how many groups here's an example of how many users are in the domain admins group so maybe we're concerned about group membership expired passwords locked at accounts password not set you're limited to only your imagination here it just depends on the property that you need to see and how you need to see them once you have this framework created adding another field here is as simple as just figuring out the property for the user or the computer or the group that you need and figuring out how to write code that will show you that count it's pretty simple that regard and then line 42 we are converting that hash table to a custom object and then outputting it to the console pretty simple i wanted to mention that this is a common technique that you can use to build each object on the fly as you're going down and then just outputting it at the end if you're accumulating a bunch of things all together at once like i'm doing here it's a really good way you just get the output assign it to the property and at the end you output the object and it just outputs everything that you'd like to see there with that being said now let's just go ahead and run this and this is going to take a little bit because it's going out and grabbing all of that stuff at one time i'll be back with you here in a few seconds whenever this is finished all right looks like it's finished and we didn't get any errors which is great so now that you see we just have a summary of the various pieces of active directory the output is very simple but you can see there was 42 lines here wasn't too bad this is really what powershell and active directory are all about especially when just querying and reporting on things it's just about taking the time going slow building out each individual component that you want and then eventually at the end putting it all together into some kind of tool like this this module really got us into active directory got us diving into some of the various ways to query different objects in ad and provided a simple output here hello and welcome to the next module in our course hands-free active directory health in this module we're going to get some ad specific configuration settings and how to read them with powershell throughout this process we'll also introduce a few powershell specific concepts like parsing string data and we'll also cover a brief introduction to powershell remoting as well this module will again mostly be all demos we'll first dive into parsing xc output because not everything has a powershell commandlet available it's sometimes necessary to use traditional xe tools and parse the output in a way to create a structured object from it this is an important skill to learn and we'll cover some examples using ipconfig and the dc diag tool we'll then build more functionality to our 80 health check tool by introducing replication monitoring we'll query each dc and gather various pieces of useful replication information from them and next since cached passwords on read-only domain controllers is a security risk i'll show you how powershell makes this process easier through just a single command this will also go into our 80 health check tool so finally we'll query the database of each dc and enumerate things like the database size and if whitespace logging isn't able to demonstrate how powershell remoting works for our first demo let's cover parsing xc output when an xe returns something it's to the standard out stream now there are different streams in the traditional command prompt and powershell is capable of capturing all of these types of strings it's much like the pipe command is required to capture standard output by using the greater than symbol here and piping it to a text file the difference is that powershell does this natively without the need for the greater than symbol there and although it's easier to always use a powershell command if possible it's sometimes necessary to use these legacy tools as well parsing output allows you to create functions and code to be used as a stopgap or bridge between the two technologies so for this demo we're going to work on parsing command line output but before we do that let's first see what we're up against here whenever we're parsing command line output that just simply means taking the output of an existing perhaps legacy function or legacy executable and then converting all of that rough output that's big string that it outputs into a structured object so to give an example here i can use ipconfig is a really good example now when ipconfig sends its output here you'll see that it sends out a bunch of text to the console now this is fine if you're just casually looking down through here and trying to figure out what you want to know but this doesn't really lend itself well to automation because you can't use this output very easily in another kind of input so let's kind of break this up and parse it out into a more structured object so the first thing i mentioned here is define what you'd like to parse out whenever you're designing these tools around this command line parsing typically not going to want everything in here now maybe you will that would just be part of your definition but in this case i just want to see the adapter name the ipv4 address and the subnet mask and i just want to see the adapter name for ethernet so what i did here is i just kind of made this simple little hash table it doesn't have to be a hash table you just need to define what an example output would be i want an output to show adapter ipv4 address and subnet mask just like this now looking down through here at the top there you see ethernet adapter ethernet so i want to capture that ethernet string that last one there and then looking down through for ipv4 address you see there is an ipv4 address a bunch of dots a colon space and then the text that we need same thing with subnet mask i have subnet masks the dots the colon space and then exactly what we need the trick is to figure out how to remove everything else from that entire output and just get the pieces that we're looking for one way to do that is to use select string select string is a really good tool that allows you to match patterns in strings and then output various matches thing it does all kinds of gray stuff it's kind of like grip on steroids i guess you could say if you use gret before it's a really good tool to parse out strings to demonstrate select string here i have already created a string called just test string test string just contains a few different lines so test colon test colon test colon and then some output i'm going to play around with select string and then figure out if i can get each of these in a structured object the first thing i want to do is because this ipconfig contains a lot of lines so it's not just one line we'll first need to split out the output one for each line so we need to create an array in powershell to do that on line 22 there i am creating the array and i'm using the split operator and then specifying the back tick in now the back tick in represents a new line separator what this is going to do is this is going to take each of these lines inside of the string and then create an array from it to demonstrate that i will go ahead and run it and now i can just reference one line at a time test whatever fail that's the first line test something fail that's the second line so it separates those all so that's the first step in separating each of these and to be able to kind of parse these out a little bit later so once they're all separated i can then use select string and then use the pattern parameter to parse out what i want i'm going to go ahead and run this here and you see that it searched through that whole array which three of those elements in there and i just found the one with the pattern test colon foo and you see that it included the whole line there so test foo succeeded so that's a really simple way at the simplest form select string uses the pattern parameter to allow you to parse out various strings inside of there however that's not going to work in our situation we need to use regular expressions or regex select string and regex you'll use this a lot if you do a lot of command line parsing this works out well because regular expressions has a concept called capturing groups and the capturing groups is what's defined here a capturing group essentially just says match this whole pattern right here and then once that's matched capture this piece of the match and store that off somewhere else once it's stored off somewhere else i can then reference just this little piece here and if you notice here with the test foo succeeded the whole string i'm actually just wanting to get the word succeeded in this case so when i do this this little piece here should just be the word succeeded now i'm also using the all matches parameter here because by default select string only finds the first match and then quits now in this case since i only have one instance i wouldn't have to use this but if you would have multiple strings inside of there that match this pattern you would need to use all matches to find all of them i'll first go ahead and run this and then see what this output looks like and you can see if you're just looking at the output it's not going to show you much at all it's just going to show you each of those lines but i wanted to show you there was something in there at least one thing that select string does whenever it sends its output it has a property called matches this is only populated if you use the regular expression capturing groups so the left parentheses and the right parentheses here this matches is populated for each of these let's go ahead and run this and run through each of these here so you'll see that all matches inside of there has a matches property and the matches property has a few different properties in it called group success captures and so on this is good information this tells you a lot of information about where it was captured and that sort of thing i want to get the groups so inside of the matches there is a groups property and if i run this you can see that this gets more granular here and allows us to dive in to the groups itself so i have success captures index length and value capture the groups property always contains at least two different objects inside of groups itself this one here is one object and then this is a second object now if you're just doing one match the second object will always contain the actual value that was matched so you see that we have value succeeded now if i just search for that i get the object that i want because groups is an array i can just specify the one index there and then bringing it down another level groups one dot value now i've gotten just the word succeeded that's what i want so i went down from that whole line and parsed it down one at a time and got the word succeeded so that's what i want to do so now let's apply this same concept to ipconfig i'll first grab ipconfig's output here and you can see that it's exactly the same as what it was before i then want to parse out that ethernet adapter name the line that says ethernet adapter ethernet i want to pull out that ethernet string and i can do that with select string to do that i can pass the output of ipconfig to select string as i'm doing on line 42 here and then i specify the pattern ethernet adapter and then i'm using those capturing groups again there just to capture that ethernet string and then i'm passing all that to four each and then i'm doing the exact same concept it was to narrow down just that ethernet string so when i run this you see that i just get ethernet the same concept goes for ipv4 address now you can see that in the pattern the regular expression is a little different there's whole courses on regular expressions so i'm not going to go into how to actually do the match but you see that capturing group again i'm following that same concept when i run this you see that i did get 192.1680.122 so it parsed out that information same concept with subnet mask as well i'm able to parse that out it's all about building the right regular expression pattern now once i'm able to pull out each of those strings one at a time if this is part of a bigger automation script it's going to make it efficient since each of these attributes looks very similar because you see that i'm running select string passing that to four each doing the pipeline variable matches groups one value i'm doing that three times over and over and over again good code it's all about keeping dry so don't repeat yourself that means use a loop here i'm going to define a properties hash table and i'll go ahead and bring that in and i'm just defining a key of adapter ipv4 address and subnet mask and then associating each of those values with the regular expression that it matches now i want to create a custom object for this so that all this is about going from a rough string like we did with iv config output and building an object from it to do that i am creating a hash table and i'm going to put all these keys inside of this hash table in order to loop through so to read each of the keys and values inside of a hash table i will use the get enumerator method so that allows me to loop through that just like an array so at this point what this string here is doing is this is saying loop through each of the keys inside of this properties hash table and then define each of these keys as a key inside of this future object hash table on 59 there the dollar underscore dot key that's going to be adapter ipv4 address and subnet mask this is essentially going to be the same keys as the properties hash table however you can see here that now i only have to specify this one single time so i only have to specify how to grab the value of that key one still time instead of repeating that over and over and over again in the end this future object is going to be adapter ipp4 address and subnet mask and instead of these regular expression strings here it's actually going to be the values of each of these that i want so now i will go ahead and run this and check out what it is and now you can see that it's a nice structured output i have the adapter subnet mask an ipv4 address all in a nice common format that's a really nice object however you see that it just has name and value for the header that's because it's still a hash table let's just convert it to an object which using the ps custom object type accelerator here piece of cake i'll just run this and now you can see that we have ipv4 address subnet mask and adapter as headers at this point we have parsed out exactly what we want from ipconfig and made it into a nice custom object for this next demo we're going to use the dc diag tool the dc dag tool is probably the original ad health check troubleshooting tool it's a tool that puts together a lot of different tests and performs them against your ad environment the functionality is great but unfortunately it hasn't been updated with a new powershell command that's what we're here for we'll break down dc diag's output and convert the unstructured output that it returns into nice object with each of the tests that are performed broken out so it's much more easily readable and during this process i'll introduce you to a simple concept i use to first to find what i want my script to execute and then figure out how to get there so let's now build a feature into our ad health check tool so the first one we're going to be doing is we're going to be grabbing the results from a dc diag scan on our domain and since dc diag doesn't natively produce powershell objects we have to parcel out all those strings up for you and hopefully with that introduction in the last demonstration that we did we were able to quickly make this happen so the first thing we're going to do just like the ipconfig example we did in the last demo i'm first going to just run the command and just grab everything and put into a variable to run dc diag it's just as simple as running dc diag slash s for the server and my dc is going to be domain controller i will go ahead and run this and since this takes a few minutes to run i will go ahead and just let this run in the background and i will be back in just a second whenever this is done all right we're back and it looks like it's finally got done so let's check out the output here make sure it's not a bunch of red error text or anything yep looks like it ran all of the tests and it worked next thing we need to do is we need to define the output so what do we want the output to look like whenever it's done and i've done that again here i want to see a row for each test and for each test i want to have properties called test name test result and entity now entity may not be that obvious of what that is at this time but you'll see what that is here in a minute it'll make a little bit more sense to you again just look with the ip config example first thing we need to do is try out select string whenever you're parsing command line now but it's all about filtering down one level at a time in this example whenever i just eyeball the results of dc diag output i see here that i see dc pass test advertising dc pass test frs events dc failed test it looks like my entity which will be my dc in this instance in my domain controller past test and then the test name now since i want to see the test name the test result and the entity it looks like each of these is on the same line i have dc so whatever entity it is passed or failed i want to know that the word test and then the name of the actual test so the first thing i need to do i need to filter out all these other stuff that i don't want to see so to do that i will first try out select string using the pattern of test colon you can see here that i see starting test well this gets me all of the test name it's a really good start it's not all about consuming and getting everything all done at one time so this gets me all the test name however i want to also see test result and that entity property to do that i first need to grab out just the test names from these i don't need to see starting test colon and then that space i will run the for each so i'll grab the value of all those matches again like we did with ipconfig and now you can see that i removed down all that unnecessary text was in there then next i will grab the test results with the test results you can see here that it does pull back the entity so the dc passed test and then whatever the test name is so this regular expression here does that you see i'm using the capturing groups again because i want to capture what the test name so this capturing group is going to be connectivity advertising frs event and so on so again once i have paired that down a little bit i now need to grab the value here so i will go ahead and run this and again this does exactly the same thing i did before i'm just removing out all of the unnecessary things that i don't want to see and now i'm just getting the value of passed or failed for each of the tests great next step done next since i need to create an object after all this is said done with the test name the result and whatever the entity is i need to match these up somehow so i can't just get the test names just the test results i need to match these up and to build these into an object when i go back here you can see that i am using these lines here and luckily in this instance each individual line has all of the elements that i'm looking for for my object so my object has dc passed or failed the word test which we're going to remove that here in a minute and then the name of the test itself so they're all in one line you can see that i did already get that information out with this line up here so line 24. so i was able to parse just those lines out so there's a lot of stuff in here that i need to parse out eventually but this is a good start now i can have a piece of code here that essentially creates our patch table again and then converts that into an object now since i'm using the capturing groups that populates the matches property that select string outputs here and then because of that i can use the groups property in this instance before in our other demonstration with ipconfig we just had one match now we have two matches that's why i have to use the index of one and then the index of two for the groups when i'm doing this this is the value for each of these and i'm defining the test name key and the test result key and then associating them with the appropriate value and then i am converting it to a ps custom object you can see here that now i've got a really good start i have an object for each test with the properties of test name and test result that's great so i have two of the properties that i'm looking for in the object next thing i want to see is the entity most of the time it's going to be dc but as i was looking through there i saw that there was sometimes it was going to be the application partition and things like that i didn't necessarily want to call it dc so i'm going to look down through here again and this instance i am parsing out the entity now you can see here i have dc but i also have forest dns zones schema configuration and mylab the domain as well so this is the entity and i use the exact same approach as i did before with the capturing group just grabbing that entity out of there and then once i do that it's just a simple matter of adding the entity property to the ps custom object as i am doing here and notice that i have three values now three groups in here to match so i will go ahead and run this and then now you see that we have one object for each property name with a test result an entity and a testing property so once i have this information in here now let's go ahead and take what we've demonstrated here and clean up this script and incorporate it into our 80 health check tool so i'll go ahead and open up the ad health check tool here and this is the same one that we were working with previously so let's go ahead and add this to here looks like in the 80 health check tool we have a few properties already i want to add the results of dcdiag here as an additional property so i will go ahead and just put in a placeholder here and call it output.dc diagrams and i'll just be a blank string for now because we're going to put in a placeholder once i have that now i need to figure out a way to execute something inside of here to get the output of what we were talking about here first thing i want to do is since we are modularizing out this with various scripts i'm going to add in our scripts here so i will add in our dcdiag.ps1 script so i'm going to eventually be dot sourcing this in so we can go ahead and be able to run this so once it's dot sourced in i need to convert all this code i did into a usable function a lot of this was just for demonstration purposes so let's go ahead and remove out a lot of this stuff we first need to get the dc diag output we definitely need that and remove all this stuff that we did in the interim here and just get the final output so that's going to essentially just do exactly what we did just remove at all that explanation that i did earlier so it's going to grab the output of dc diag take that output patch to select string and then create that future object here so let me just run this again to make sure this still works so now we have just the code just to get the output that we want now since this is going to be incorporated into our invoke ad health check tool we need to build this into a function to do that i'm just going to create a simple function here i'll call it invoke dc diag and then i will place all of our code inside of this function create our pram block here now this is allows me to compartmentalize this piece of code and now we can just call it from wherever we want and now i can just run invoke dc diag it will run dc diag and parse out all the information that we need so once we confirm that in the dc diag script it looks like we are dot sourcing so the invoke 80 health check script will dot source then dc diag so it will make it available and i'm going to scroll down here to make sure not missing anything and nope so now all this information that you see down here in the console i want to compartmentalize all of this into dc diagresult to do that i can just run invoke dc diag right here and put it in parentheses this is going to execute invoke dc diag and when it's done it will assign it to the dc diag property since i'm doing this on the fly i didn't want to prepare for a lot of this ahead of time because this is a really good learning experience for you as you'll see that i may make mistakes here and there as i'm doing this let's see we have it in the same folder so now i will go ahead and run this script and looks like it did not work out right we got some output there but we got some errors as well invoke dc diag is not recognized as the name of a commandlet okay let's see why that was so we have invoke dc diag the function here inside of the dcdiag.ps1 so make sure that both the scripts are in the same path and i believe they are let me just make sure here so they are in the same password in the five hands reactor directory health in the demos folder it is the scripts pass this variable here was wrong so i'm going to need to update this path variable here that's updated now i can go ahead and try to run this again so it's prompting it for the mandatory parameter of filter for get 80 computer let's just figure out why it was doing that all right let's check out the get verona's computer we didn't actually convert these into functions like was originally intended see we have get veronica's computer.ps1 but we still have a bunch of this executable code we need to convert all of these into functions now we have a little what's called a wrapper function around get a d computer that we can then just call get varonis computer and i believe let me make sure that the same is done for the other ones as well so what we're doing is we're doing the exact same process as we did before we are removing out all of the demonstration code that we were working with and this is a common thing you'll do you're going to be working with a lot with these scripts and when you work with the scripts you'll find that you'll need to refactor them in some way you'll find that you'll have to convert these scripts into functions in order to help modulize your code and to plug in features like i am here in the ad health check tool so again here let's just grab out the necessary code and we're going to call this one get varonis group and then the same thing with getperonus user this was a pretty easy one here so we have csv users csv users and all 80 users so we need csv users and the all 80 users variable create the function again notice that we have a variable here called demo path we're still going to need that okay so we'll clear the screen there with cls and looks like now we have getron as user with a function get everyone's group with the function and then get verona's computer with a function now let's try to run this again now notice it's taking a little while it didn't immediately error out hopefully this is going to work but you remember before looks like invoke dc dag is probably working in the background because it's taking a while i'll be back in a few minutes while this is done and we'll see what the output is all right looks like it worked so great you see here that we have dc diagresult we have that new property and then we have all of that information that we saw previously that had the test name the test result and the entity that is all a single property inside of our 80 health check tool because i didn't output this to a variable let me go ahead and do that now and we'll just run this real quick again so i can't actually run it here directly from the ise because i need to output it to a variable here i'm going to go ahead and run this manually here inside of the console so let's change the directory to here make sure we've got it here with ls we're going to assign this to example output equals invoke 80 health check dot ps1 that's going to execute invoke ad healthcheck dot ps1 and then send all the output you just saw to the example output variable and then we can parse it and then play around for a little bit be back in just a second all right looks like we finally got done here and now i should have that example output to be able to play with so now i can just do example output dc diagram and now you can see that familiar output that it's all stored in here this was the first task we did to add some functionality to a new tool so this is a really common occurrence where we had existing functionality so existing code spread out through various scripts and we incorporated that all into one script per one function once we did that now we have the foundation laid to where we can just start adding in functionality as we will and you'll see that in the upcoming demos we're going to be doing just that the next feature we'll be adding to our health check tool is replication monitoring dc to dc replication is one of the most important metrics to keep an eye on in your aed environment by using the active directory modules command powershell makes quick work of this to do this we're first going to figure out how to enumerate all of the dc's in the current domain and then once we do that we'll then target each of these dc's to gather a few key pieces of replication data for the next feature of our ad health check tool let's build a replication monitoring feature to do that just like we did with the other features first need to define some kind of rough layout of how you'd like the output to look in this case whenever i run my ad health check tool i want an output that's going to look something like this here so i have a hash table and inside of that hash table i have a replication status key which also is a hash table with each of my domain controllers listed there and then inside of each of my domain controllers those are also hash tables with the domain controller as the key name and then the value which is also a hash table with the keys of replication attempt and replication status and you can see that i've kind of laid a rough layout of sort of what that's going to look like so i'll have the date and time for the last replication attempt and then either success or failure if the replication status exceeded and depends there and then i will uh also have this one for every domain controller in my entire environment so it's a really good idea to lay out a rough outline of what you'd like your output to start with before you start a new feature on a tool like this the first thing we need to do to get the replication information for our domain controllers is first to enumerate all those in my domain to do that the active directory module has a really good command called get ad controller and it has a mandatory filter parameter here in this case i just want all my domain controllers so i'm just going to specify a filter of asterisk and when i run this i would just create a dc's variable which contains all of my dc's in here so there's lots of properties in here so i'm just going to do a count to make sure i have two dc's in my environment so once i have all of the domain controllers enumerated i will then need to grab the information about replication on each of those fortunately the active directory module creates a really good command here called get ad replication partner metadata and this is a command that gathers a lot of great information about your replication of your domain controllers not just success or failure but for now we are just going to include just those two properties so those are the only properties we are concerned with at this time so when i run this i can run it with a target and then specify those dc's that i found earlier and now for each of the domain controllers it brought down a lot of good information you see here we have last replication attempt last replication result the time it was last successful so there's a lot of good information for each and every one of the domain controllers and how they are interacting with each other so once we're able to pull that rough information now it's time to mold that into a structure that we need so the first thing i want to do is i want to create my outline of the object that will eventually be to do that i'm going to create my output hash table and just make my replication status key inside of there because that's what i defined at first what how i wanted it to look so i've created the hash table and now i can go in and add elements to this hash table and then eventually convert that into a custom object when we get done so once we do that i can go ahead and then enumerate through that repel data variable since each dc is an object in the reply data i can confirm that here two objects for each dc i can then just loop through this with our for each variable here and then define each of the servers let's just go ahead and do this manually real quick so i can do four each and then each of those objects has a server property so it has the fully qualified domain name for the server property if i can loop through each of these this will create a hash table key for each of these so now i will go ahead and look at this so now you can see that we have a hash table with a key of replication status that has a value of both of those other hash tables so let's dive in a little bit more and then we will look at output dot replication status dive in a little bit more now you can see that we have dc.mylab memberserv1.mylab and then a blank value for now so that's just kind of going taking a step further and building out the structure a little bit more now once we have the structure built we can then just add in the values that we want so in this instance here i'm just adding in instead of just creating the hash tables for each of the domain controllers and then taking that a step further and adding the last replication attempt and replication status keys to each of those domain controllers hash tables so when i run this now it should run successfully so now let's check it out so we got output dot replication status now you can see we have each of the dc's and we have values inside of those so let's dive down further just to check out one of these so i have replicationstatus.dc.mylab.local and now you see that we have the last replication attempt and replication status associated with that dc and then one thing i wanted to point out notice that i had to put single quotes around that dc.mylab.localproperty that's because the property has dots in it and with powershell you must have quotes around any property that has dots in it because otherwise powershell will think that those dots indicate further properties all right so we're almost there however notice that i want replication status to be a string of success or failure right now it's just going to be 0 or some other kind of integer if it failed this is a really quick conversion here we can just quickly do this with an if statement right inside of the replication status value itself here i'm just saying if replication status equals 0 i'm going to say it's true else it's false however we can also do this to success and failure if we want so at this point we have all the structure we need just a simple matter of adding this in so instead of true let's just say this is success else failure let's run this again and check it out now now you can see that it says replication status is success now i can do this for remember serve one make sure that looks okay and i have a last replication attempt and replication status of success this was all that was included in the replication monitoring feature now let's clean this up again and let's incorporate this into our bigger ad health check tool so to do this i need the replica variable and the output variable we still need dc's to feed to the rebel data which will make ripple data we don't need that one let's just be sure here to run this again again with the ic i can just run the entire script with f5 here so now it's just a script now since we're going to be dot sourcing it we don't want to directly execute it when you run the ad health check tool i'm just going to go ahead and create a function out of it i'm just going to call it invoke replication monitor and then take our code that we've built and add that into the function one thing we did miss here notice that we are building the output hash table but we've never actually converted that back into a custom object so in this for each loop we're actually building it then now all we have to do is finally add that step that converts the hash table to a object so let's just test this out see if it works we can do that i'm just going to go ahead and run selection here that will get the function available in my session now i can just run invoke replication monitor looks like that worked so let's open up the ad health check tool since we're using a new script here we need to add it into our scripts so it's replication dash monitoring that will not source it in so we have the function available and then we're going to add another property called replication status invoke replication monitor now one thing that i did notice that we will need to change is the nested replication status hash table here so in this instance you can see here that we are building a hash table called output so we have a hash table and then we have another hash table embedded into that this will work if this feature is just running on its own but if you run it with ad health check 80 health checks going to have its own replication status property so if i would let this run this would look like the object replication status dot replication status so notice we would have a nested replication status so we do not need this embedded replication status hash table because we are incorporating it into the 80 health check tool and because it's not in here we don't need this anymore either so we can just remove this so now it would just be the output of each domain controller test this i will bring this into my session again run this again and now you can see that each of the domain controllers is its own property so that looks much better now so everything looks good so let's see if you can run this without any errors no errors so far because of that invoke dc diagram this is going to take a little bit we'll be back in just a second and we'll see what the new replication monitoring feature looks like under the replication status property all right looks like it came back and with no errors so great so now notice that we have replication status property here and we have each of the dc my dc mylab.local equals our hash table which will include our replication status and mymemberserv1.mylab.log which is my other domain controller so you'll see that the replication monitoring feature is now incorporated inside of our ad health check tool for our next demo we're going to add a feature to find cached passwords on any read-only domain controller in your environment read-only and domain controllers are sometimes used in physically insecure environments like branch offices or really anywhere where credentials do not need to be updated one feature of rodc's is password caching this prevents the rodc from talking to another domain controller thus allowing it to authenticate credentials while being offline by default rodc's must refer the authentication request to another writable domain controller this is a security issue if that rodc were stolen or the passwords could be vulnerable to password cracking this feature of our health check tool will check for these all right next up in our features for our ad health check tool i've decided to add in a feature to finding cache passwords on my read only domain controllers you may wonder like where is he picking out all these different features of the tool well to be honest with you i kind of picked these on a whim the reason i've even mentioned this in the first place is the features that i'm adding here are not required by any means i'm just building each of these features as an example so maybe a useful feature that you may use with your ad health check tool but at the same time i want you to know that the process is exactly the same for adding each of these it's just simply defining what kind of output that you need and then going step by step getting the structure right the main structure of the object or whatever you want to do building that down whittling it down slower and slower and tinier and tinier until eventually you come out with the output that you want and then once you have the main script like we're doing here then i'm just converting into a function and you can see that converting into a function is just essentially wrapping all that code into a function and then putting it into the ad health check tool don't get hung up on the examples that i'm using here since i'm going to be finding cache passwords on read only domain controllers the first thing i need to do is find all of the read only domain controllers and to do that it's very simple with git ad controller again i'm going to filter for all of them so i'll get all of them and then i can filter out this even more by saying where object using my is read only property here if you remember in that previous module it's always better to use the filter parameter but in this instance it's much much easier just to simply output all the domain controllers and filter it after on the pipeline by saying where dollar underscore which is the pipeline variable dot is read only i will go ahead and do this here and notice that i have none well i have none because i have done in my lab environment however if i would have these in my lab environment the output is going to be exactly the same as if you ran git ad domain controller so if i run git admin controller again you see that it outputs the typical properties that occur here it would just have an is ring only you see here i have the is read only property here in this case they're both false so you have all those another huge time saver that the active directory module has it has this command called get ad domain controller password replication policy usage now if you dive into the active directory module at all you'll see that it has hundreds of commands and things to do all kinds of other things that we don't have near enough time to cover so in this case this get ad domain controller password replication policy usage which is too long of a command you can pass all of those domain controller that you found directly to that and then it has this revealed account parameter here now the revealed account parameter say i want all the accounts that have a password that has been cached on each of the domain controllers the reason that i know this is i'm not an active directory expert by any means i've got a few decades more of experience with active directory but i don't use it on a day-to-day basis so what it did was whenever i was doing the research to figure this out i first went to help and before you go and create your own function or command first i would go through the actor director module and figure out which one it is and this one caught my attention because right in the description it says gets the user computer accounts that are authenticated by a read-only domain controller or that have passwords that are stored on the read-only domain controller so it says the list of accounts that are stored in rodc are known as the revealed list if you look at the details of the command you'll see have a revealed account parameter and this grabs those so since i'm not going to actually pull any of those out because i don't have any read-only domain controllers i can just go ahead and run this it's not going to do much right now because i don't have anything however i wanted to include this in here because it is a very useful feature of the ad health check tool because it's a primary security concern this one is going to be shorter here because notice i just have a few accounts here but i still want to incorporate this into the ad health check tool i will go ahead and follow that same logic that we have been in the previous demos and i will say this one's called invoke rodc password discovery and i will put all this code inside of the function and then save it so it looks like this will just output all the revealed rodc accounts for this feature again just like before since we're adding a new feature i will go ahead and add the script in here to dot source it to get that function available to us and then i will add another property cached on rodc's and that function name so now we have a new property on here now when i would run this again just notice i will now have a new property called cache passwords on rodc's once this is done running then i have another property that i can dive in and really get more granular and figure out which passwords may exist what usernames may exist at that point it's just a matter of diving in to each of these properties here and then taking a look so if that was cache passwords rodc's then i could just dive in and it really gives you a starting point to do more discovery work next up in our demo parade is powershell remoting this demo will not be ad specific but is a required primer for the demo following it powershell remoting is a feature you'll find yourself using over and over again in a nutshell this feature allows you to run local commands on remote systems just as if you were sitting at the console if you're familiar with ps exec it's kind of like that it allows you to create a temporary session to a number of different machines and pretty much run whatever you'd like with a few exceptions of course let's get into a demo where i'll cover a brief introduction before we can get too far in the next demo we're going to be using a lot of powershell remoting and i thought powershell remoting is such an important topic we needed to cover a specific demonstration on just the basics and getting started with powershell remoting so let's go ahead and do that in this demo setting up powershell remoting for the first time between a client and a server it first needs to be enabled as a windows server 2012 r2 powershell moding has already been enabled by default however even in r2 and later in some of the client systems it needs to be configured properly for it to actually work a quick way to enable powershell moding is to just run enable ps remoting force i'm running this on my client now and this will need to be ran on both clients and servers as well because powershell moding is a client and a server system so you see there that says winrm is already set up to receive the request on his computer and it's already set for remote management that process ensures that powershell moding is enabled so that means it ensures that a service is started and that some firewall exceptions are in there as well so it's a quick way to get everything configured at a base level once you've ran this command on both the server and the client then it's off to test this out and establish a session i'm going to be doing this in a domain environment so if you do not have a domain environment if you have one computer that's in a work group or both of them in a work group the configuration is going to be much more involved but just know that in this demonstration and with our 80 health check i'm going to be assuming that all the machines are domain joined so powershell moding has this concept of a session there's a few different commands involved with powershell remoting that uses this session the first thing we need to do is we're just going to build a session here and do that i just simply use the new ps session command now when i do that you see that i have a session variable here so if i look this up i have a session variable the state is open and it's available so great so now we have an open session with that remote computer i can look at all of my powershell open sessions by using the get ps session command so notice that i have a one session here as i create more and more sessions i can create multiple sessions for one computer or many different computers if i run git ps session on the client machine here you see all those open sessions that i have if for example i wanted to remove all those sessions i can just pipe git ps session directly to remove ps session and now you can see that the session is gone however because i want to reuse this i'm going to hit create that again and now i have an open session now that i have an open session i can reuse this session over and over again for a lot of different things everything really is held on that remote system so let me give you an example the command that you'll probably be using a lot is the invoke command command and this command is essentially just a command that allows you to invoke all kinds of different code on the remote system so in this case i'm just telling invoke command use this session that i just created which is on that remote computer and run this code in this script block so i'm going to run the hostname code inside of the script block and if i just run hostname here on my client machine it's just client1 this is to prove that when i run hostname it will be running on that remote computer so when i run invoke command here with hostname you see that it comes back as dc that shows you that it is running on the dc itself now one other thing that you may run into is you really need to realize that everything is stored remotely in that remote session let me give an example here let's say i want to set a variable we're going to call it variable equals hello so i've now set the variable on the remote session now if i try to enumerate this variable on my local machine here you see that it has nothing in it well that's because the variable is actually set in that remote session so let's go ahead and run this invoke command and see what that variable is here now you can see that i run variable inside of that session it then comes back the session maintains its state even when you're not in it so it's always running kind of in the background it's running remotely on that machine so you can just come in and in and out whenever you want now this is just a really simple example of using invoke command there's a lot of other things that you can do with invoke command and you can use that all with get help another connection method i wanted to explain was using temporary sessions we just built a full session whenever i use new session which comes back with a session variable like this that's essentially called a full session that brings up everything that's necessary for you to get a complete interactive experience sessions are good for reusing commands like we just did in case you need to do it multiple times over and over again there's also a really common way that you can run commands with just a real quick temporary session that's brought up and tore down at the same time and to do that you can use invoke command here and instead of using the session parameter i'm just going to use computer name i'll specify the computer name with the script block and now you can see that it brought back dc then however if i look at get ps session here you see that i just have that same session so let's just go ahead and remove this and just be sure that it's not opening another session here so no sessions run it that essentially brings up the session runs the code and then tears it all down in one step you'll use invoke command with a computer name parameter a lot if you just have one code block to execute on the machine if you just need to run a quick host name or gather some kind of information for the remote machine in that nature so you use that a lot now one other good thing about the computer name command here is you can use multiple computers as well so for example let's say i want to run that code on my dc computer and my memberserv1 computer so let's see what this does it connected to the dc but notice how it's pausing here that's because there's some kind of connection problem with member surf one and i thought this may happen because my member serve one is going through a few maintenance things right now but it looks like it finally did come back so it looks like dc and member serve one both did run host name that's a really good way that you can run it on one or multiple or a hundred machines at once now again this was just a very simple example of using powershell moding and invoke command there is so much more to this but there are entire courses focused on just powershell moding if you like any more information running across any problems i highly suggest first looking at the help for invoke command and that will provide you a list of all the different parameters and all of the different examples and a lot of other things that you can do with invoke con but for now this should give you a primer on how we will be using powershell moding in the next demo for our final demo in the module we're going to add another feature to the ad health check tool this feature will be able to discover the database on each dc in the environment and pull some interesting information from it we'll use powershell remoting extensively here to do this since we're going to have to pull some registry information to do that we will find each dc's database once we find the database we'll then read the size of the database and determine if whitespace logging is enabled or not white space logging is a feature that allows you to see the unused space in the database when defragmented you'll usually find a lot of this space is freed up all right so it's time for the final feature of our ad health check tool and this is a feature where we're going to go out to each of the domain controllers find out where the active directory database is located and then pull back a few properties from these that we would like to see in our final report so again just like we're starting out with the other features we first need to define a rough layout of what we like the output to look like and in this case i am defining a hash table again because this is eventually going to be incorporated into the ad health check tool itself with each domain controller name being a key and inside of that we're going to have the database file path the size and if white space logging is enabled or not so to get started i first need to enumerate all the domain controllers again we've done this before so i'll go ahead and do this before i actually show you how for this to run automatically we're going to go over a few concepts that we haven't discussed yet i'm going to cover this interactively first to do that i'm going to open up a powershell remote interactive session that will allow me to run these commands directly on one of the domain controllers itself so now that i'm in the domain controller's remote session i can then start running code everything that we're looking for is located in the registry it's defined in a registry value to get the information from a registry value we use the get item property command and the get item property command can be used for anything with a provider so if you remember from one of the previous modules we talked about providers and a provider can be anything like the file system the registry the even the certificate store or even the active directory provider so the git item property command works for any of those different providers so in this case we want to find the value of the dsa database file registry value it is located in this key here so the first thing we need to do to get this database value is first we'll run git item property and get the entire key so you notice when i just run git item property i will get all of the values inside of that key we're just focused on the dsa database file value so i'm going to go ahead and assign that to the variable that way we can use it later in our object and then we'll check out and see what that is now notice that it is a file path now since it is a file path we can use get item property again to get information from that actual file so if i run git item property again and instead of specifying a registry key i can specify a file path and now notice that git item property understands that and then brings back the file that i requested now notice there is a length property there and the length property is 293 five one two well the length property is the size of the file it's represented in bytes however that's not very obvious so i want to see that in megabytes now powershell provides a really cool shortcut to convert bytes to megabytes bytes to gigabytes terabytes to kilobytes however you want to do there by indicator here just called mb so mb is for megabytes gb for gigabytes kb for kilobytes and so on so i can divide my byte value by one megabyte and will eventually come out with to be megabytes so when i run this now i can see that the size is now represented in megabytes it's a little over 28 megabytes it's much easier to see for the final property we're going to gather we're going to gather if white space logging is enabled or not and again that white space logging is a registry value so i will go ahead and grab all of the information from the diagnostic key this time and then the value that we're looking for is located in the six garbage collection registry value again i will just run this and then white space logging enabled should represent the value that we're looking for so it looks like it's zero right now so it's off i know by experience that zero means if it's off one means if it's true however that's not very friendly i need a better output i need it to represent true or false instead of one or zero to do that we can just simply use this if condition to say if it is one then change the value of white space logging enabled to true else if it's zero then change it to false so i can go ahead and do that it's just a real quick example to transform the output and then finally once we've gathered all of those variables we can now put it all together into an object again we are using the ps custom object type accelerator here and then specifying an array so this just is going to create a simple powershell object now notice that for the key here in this hash table the key is left paren hostname right print we've used the hostname in the past the name command simply enumerates whatever the host name of the machine that is currently being executed on and since this is going to be executed over a remote session host name is going to represent every single one of the domain controllers that we run this against so whenever i run this in the remote session itself you'll see that it has dc there that's how i can tell that this is running on the dc domain controller that is the whole process for a single domain controller so now let's back out of the remote session and get back to our local session here and let's remove out the manual steps here that we had to do we've already created all this so we can just remove all this comments out here to demonstrate one dc notice that i was just pulling out one line at a time and executing it however this code was enclosed in a script block so i have a script block variable here and it goes all the way down to here so i have all of the code that we just went over all enclosed in a script block so a script block is just a package of code i guess you could say that can be executed on command because all that code is encapsulated up into a script block we can now run invoke command and just say invoke command go out hey run this piece of code on this dc run this piece of code on this dc that's what we're going to do here so let's first make sure that we have all the domain controllers so we have our dc's variable defined and then inside the dc's variable we have the name property and it has dc at member server one which is both of my domain controllers once i have the target machines so the domain controllers i can then just specify the group of domain controllers for my computer name parameter because my computer name parameter can accept more than one computer name the script block which is the script box we just defined and then i'm also specifying hide computer name here because by default invoke command will output the actual uh computer name that it executes on it so in this instance i don't want that output so i'm just going to use the height computer name parameter there so i'll go ahead and run this and it should run pretty quickly so that just invoked command went out established a remote session to each of the domain controllers and ran that code and got everything back so let's see what it looks like at first this doesn't look anything like you're thinking of we have member server one i see a reference there but i don't see dc anywhere and i see this run space id the first thing we need to do is we need to get rid of this run space id because i don't want to see that that's an extra property that's included whenever you run invoke command to do that i can run select object with the exclude property run space id now in order to use exclude property i have to actually also specify all the properties so it's a little counter counter-intuitive because i'm essentially saying i want all the properties except the run space id this isn't mandatory if you do this this won't have any output at all so just remember that if you're ever trying to exclude properties and then i'm going to overwrite the original results value and go ahead and run this here now let's see what results is notice that you think well i thought we ran this on dc and member serve one it was two domain controllers well this is one thing you might run into because powershell tries to format the output in a way that you would expect the console sometimes it works sometimes it doesn't so what you see is not what you get with powershell sometimes to really see what's in results we can pipe this to select star which says get all the objects but again look and see that was the first inclination i want to see everything i think that select star will do that well it doesn't in this case because we don't see every one of them now sometimes you can do this you can specify the index so since results is an array instead of using select i can see which elements are in that array with 0 or 1 and then notice that i have member serve 1 and dc so dc is kind of hidden in there to where you don't usually see it unless you are looking so that's one thing to keep in mind just looking to see let's just make sure that one of these looks okay before putting us into the tools so we have results one member serve one so we have each of the values that we are looking for now notice that it has name and value here for the property names we need those in a hash table looks like we got everything done so let's remove all of the demonstration code that we had here and we will put this into our 80 health check tool to round out the feature set we need to output results at the end so our health check tool would understand this and let's just go ahead and run this on its own and see what happens everything ran fine let's bring this into a function and we'll call this invoke 80 database info we will add the ram block and put all this code into the function just like we have previously tab that over to make it look nice don't need this comment anymore looks like we're good so let's go back to our ad health check tool again for the final time add the script that contains the function that we are going to execute ad-database.ps1 add our final property in here ad database info that's good and then we need to grab the function name and poked database info that should work so now instead of invoking this directly i'm going to invoke this from the console so i can assign it to a variable so we can look at the output more closely so that's demos invoke ad check dot ps1 all right so that should execute the script so now it is executing and it will take a little bit because as we add more and more features to this i will take a little bit longer i will go ahead and wait here for just a second and through the magic of video editing we shall be right back where we will explore the output a little bit more all right looks like it finally got finished here so let's see what output looks like looks like we have everything in here so we have all of the previous ones and we also have our new ad database info so let's look at our ad database info a little bit and again we just see remember serve one but now we can just reference it with zero and one again then we have membership one and dc the original formatting you see here is going to be a problem whenever you would just normally look into this but in our next module we're going to build an html report to where we'll be able to address the problems like this otherwise just uh casually going through here there is no cache passwords on the dc so that's going to be blank and it looks like everything else is still here that rounds out our ad health check tool so now in our next module stay tuned so we will take this raw output and convert it into a nice looking report in this module we're going to take the tool we've been building throughout the course and put a bow on top we'll be taking what once was an ad hoc tool and transform it into something that can send out html formatted messages on a regular basis via email throughout this module we're going to be focusing primarily on three topics the first is converting our ad health check tools output to html we'll do this to get into a format that's a little easier to read and allows us to use html and css to manipulate the output of the report much easier we're then going to go into automating the report and running it with a scheduled tasks i'll go over how to create a schedule task with you with powershell to invoke that 80 health check tool to ensure it's ran every so often and then finally we'll add email capability to the health check tool this will ensure the results of our html format report is seen by the appropriate people to keep tabs on ad when working with html and powershell the command you're going to have to get used to is convert to html this command is a shortcut for taking objects and converting them to an html table you'll see that this command is pretty simple there's really not much to it however it's a great shortcut for converting objects with the properties to html tables in a couple different formats however if you'll need to add any other formatting to the report you're on your own really don't worry though i'll walk you through some basic tweaks to the final report to make it pop let's now get into our first demo of the module where i'll show you how to convert objects to html once you've got the basics down we'll then jump straight into converting the output of our ad health check tool to html so we have our 80 health check tool all done and now we just need to spiff it up a little bit and to do that we have to use html so before we go into some details about applying html to our ad health check tool let's first just go over a quick demo here and show you what it's like to work with html and powershell the first thing we're going to do is we're going to grab just a general output here so i've chosen to use git service so i'm just getting all the windows services on a particular machine and i'm choosing to output the status the name and the display name properties for each of the objects that git service returns so i will go ahead and just run this and then you can see that i have a variable here that contains one object per each windows service so i have quite a few there right now these objects are displayed in the powershell console with a table format whenever you'd like to convert this to html powershell provides this convert to html command what this does is this essentially replicates the formatting that you see here in the powershell console just with an html table so let me show an example so to use this we just simply pipe the services variable so we pipe all those objects over to convert to html then once i do that then i have a big string called services.html and now i can see that it looks quite a bit different it's actually created the entire html web page for me even with the doctype the head tag the title tag and so on by default for each of the objects that are passed to convert to html it will create an html table here so you can see that we have an html table with each of the objects defined as rows in the table now this is the default output here this looks fine with a plain text display but i would like to see this in something that will actually render the html to do that i will just output this content here to a file called services.htm now i can do that with just simply passing it to out file which takes all that text that we just built there which in this case is html over to create the file called c services htm as a shortcut to bring us up an internet explorer i will just use invoke expression pass that c services htm and now i'm opening it up in internet explorer and you can see here that internet explorer renders the html just fine looks great status name and display name the properties of each objects are in bold there and it just has a nice table format each of the windows services so in a nutshell that's the gist of convert html so let's take a little bit farther here now convert to html also has some additional parameters to it one is the title parameter here whenever i bring this file up again you'll notice that the title here is just html table it just makes a general html table maybe i want to change up that title a little bit i can do that by using the title parameter here i would just name it windows services output it to see services htm again which just overwrites the file and then whenever i look at it again you'll see now that the title is windows services so there's various little tweaks and things you can do there's not a whole lot you can do unfortunately with convert to html but there are a few little tweaks here and there that you can do things if you're curious for all the other parameters you can do obviously you can use get help for just about any command and i encourage you to do that because we're not going to go over each of the individual parameters here just suffice to say if you need to do anything else with html first look at the convert to html help content and then if you don't see the functionality in there we'll have to figure out how to do it a different way the convert to html command also has a head parameter if you're familiar with html it is a tag at the top of every html page so right now i just have the head tag with a title tag inside of it the head tag in html allows you to define a few things one of them is css formatting now i'm no css guru by any means and i don't expect you to be this header here that i've captured i just googled it and was able to find a good example of how to format a table this is where the design friendly people in the audience will come in handy because they're good at designing and being creative that's not me at all just suffice to say i wanted to show you a good example how to make this table look a little bit better and once i have that header i can define that head tag here and then i can just pass the header string here to the head parameter so i will go ahead and run this again and then now i will check on the file and now you can see that we have some borders and we have the top in blue that's a good example of using css css options are unlimited but like i said i'm definitely no css expert and this is not a css course but this gives you a good example of what is possible now finally just to wrap up this demo here i would like to use the pre and post content parameters of convert to html now the pre and post content parameters are parameters that allow you to specify text before the table element and after the table element so let me show you an example let's say that i want to name this html page the windows service report for computer and then whatever name the computer name it's running on so i will add this here to my session just load this in and then at the bottom in the footer section i want to say found however many services it found on the computer total services so common header and footer situation for an html report and once i had that i can just simply use the pre-content and post content parameter to convert to html in this instance i'm using splatting i don't believe we went over splatting yet but it's a very simple concept but it's very powerful and allows you to really organize your code so notice that up here for convert to html i'm using the title parameter and the head parameter everything is on one line now imagine that you have 10 parameters if you would they would get spread out all the way across tier and i would have to do this and that scrolling back and forth all the time powershell best practices dictate that you should probably never keep your line length over 150 so 125 to 150 if you're starting to get longer than that you should probably look into doing some things that cut the line length down and one way to do it is through splatting here with splatting i can assign a variable and assign it a hash table and then inside of that hash table i can define each of the parameters that we need to pass to the convert to html function so i have titlehead pre-content and postcontent parameters this is doing the exact same thing as i was doing here so in this instance here 25 i could have defined a hash table with a title and head keys in it and then passed it to the convert to html function and it would do the exact same thing splitting is just a really good way to organize your code and to keep the line length down saying that i'm going to pass all these convert html params to our convert html function output it to services once again and now we'll check it out and see what it looks like so now notice that we have some text up here windows service report for a computer and then it expanded that variable out for client one so this computer is client one and then at the end you see there it says found 181 total services so the pre and post content is a really good way to set the table header and the footer content as i said there's a few other parameters to convert to html which we didn't get covered but by all means if you want to explore a little bit further to convert to html just always use get help convert to html and you'll be able to find a lot of that good information in there all right so it's now time to take our ad health check tool and convert it to html sometimes it's as easy as sending all of the output that we have directly to convert to html but since our 80 health check tool has gotten fairly advanced we need to go through and do a few tweaks to the tool itself and do a little bit of manipulating let's get started here with that so the first thing i need to explain is what we've done here is i have the invoke ad health check tool script that we've built throughout the course ninety percent of it is exactly the same but there's a few things that had to be changed in it in order to get everything properly formatted to html so i'll go over those few things at first so the first thing you see here is that we don't have all of these scripts defined to be dot sourced to demonstrate this to show you what it did look like let's go over here to demos here invoke 80 hill chick this is what it used to look like so we used to have a scripts array here with all of the different scripts in it and then we dot source everything in the array itself however up here we've completely removed the array and instead of just looping through the array i'm actually reading all of the files in the scripts path folder here so you can see here that in the demos slash scripts folder in this demos directory here i'm actually just reading all the files in there so this is a way that i don't have to duplicate some effort and define each file name in an array now i can say just give me all of the files in that folder and dot source them all so that's one change that i had made here so the rest of it this is all pretty much the same we are grabbing the ad users again and then here is where we start defining what we want the report to look like so before the report was very simple actually if you remember however we want to spruce it up a little bit before you even get started coding at all it's first important to define what you would like the report to look like so i've done that here so i've taken all the different attributes and things that i report already outputs and then i roughly define these into a format that i would like to see when everything is done here all of this i haven't added any properties or anything like that i've just simply changed how the formatting looks that's the first thing we need to do here i've broken this out in a few different sections here so as i was going building this demo just as you will with building your own tools you're going to have multiple different attempts so in this first attempt i try to get some kind of html that looks similar to what was doing and then i decided well no i need to add something else and then you go back through it and no i need to add something else again so that's how this demo is going to be structured so the first thing i need to do is i need to break out each of the sections so you can see up here that i have a dc diag test results section i have a replication status section and a database status section and so on so i need to break out each of those sections so the first section i have here i'm calling account display and i have a few of the different attributes on here so this is going to be all of the attributes here in this first section so i didn't change anything the output is not changed at all we are gathering all of the same information that we were previously however i'm just assigning these all into a hash table so i can group them together so i'll go ahead and run this and now i have the count display hash table with all of the appropriate values in it you see that i have all the different values that i was looking for there previously here next thing i need to grab all the user passwords that are going to expire soon this is word for word exactly the same as what it was in the 80 health check tool that we covered previously so it's just another property here called expiring password so that's exactly the same let's actually go through and create the html so because i have all these in a single hash table with the count display as you've learned before you can convert that into a ps custom object so when i convert this into a ps custom object you can see here that it turns to lockdown accounts password not set etc so each of these are properties and once we have the object i can then pipe that to convert to html and because i need the title to be active directory health check report i can simply provide the title parameter here to convert to html and here's an option that we didn't have before let's go ahead and just output this and show you what this looks like this is going to take this count display custom object here and convert it to html actually i'm going to output this to a file and show you what i'm going to change up here so let's say out file c ad health check b4 and then we'll do invoke expression c80 health check before so notice that it's in a table format so we have the properties all along the top line so all the property names are on the one line and then all the values are on the line below it if you notice that does not follow what i want the output to look like you see here that i want a property name and then a property value on each line so the individual lines this is known in powershell as a list format in order to get this kind of output you have to use the as parameter on the convert to html function here so you can see here that i have as list this defaults to as table but i need to use it as a list so let's go ahead and run this and now let's see what that looks like i believe it's 80healthcheck.htm now notice that it's set to a list format so i have exactly like i would like it to be so i have each property here on one column and then the properties on the other so first task done and then the next thing i need to do is i need to append all of these different tables to this html file so previously we just had one big file and we didn't do much with it we were just creating a new html file every time we ran since we're running this all for one script we need to append this information to do that we can use a few different things here so this is the very first one so i'm saying create the entire page first so this convert to html command that will actually create the file afterwards i don't need to actually create the file again i just need to append new content to the file to do that i'm then going to run my invoke dc diag function that we had previously exactly the same as before and then once i gathered the output of dc diag here you see that i'm passing dc diag to convert to html now this time you see i'm using a fragment parameter here by default convert to html creates the entire page so it has the doctype the head the title and all that information if you use just the fragment parameter here convert to html will just create the table itself and then i'm also using the post content here to create an html line break right after that let me go ahead and show you what this is i believe that i already have the contents of dc diag out so i do here let's try this out and see here so i had to run this now you can see it's appended the table to our existing htm files so i have the output of our accounts that we had earlier and now you can see has test result entity test name has all of the information that we have from invoke dc diak here right below it it didn't create a whole nother htm file instead it just created that html table and appended it and we're using the exact same thing for our invoke replication monitor so we're grabbing the results of that just like we were in the previous module adding that to there if we would look at this one more time you see here that we have the same information we just had and then it just invoked the table at the end just as simple as that we're just appending on to the html as we go along after we've added the replication status then we just need the ad database info doing the exact same process that we were before so i can run this and then we will check the htm file again and then notice that we have everything we need but it's close we have all the tables but we need a little tweaking here this doesn't look exactly like we needed to based on our previously defined structure that we had the next phase here we need to add table captions unfortunately there's not a way to create actual caption tags in html by default with the convert to html function however we can sort of replicate that with the pre content command here you'll see here that i'm defining pre content i'm using the spaces and then the br here is a line break so that just means a break inside of the html contents here if you refer up to how we want this to look notice here we have dc diag test results and a bunch of dashes then we have replication status and dash just database status and dashes i'm iteratively going through this and just making sure that the output that i'm getting looks exactly like the output that i defined in the first place to add the captions i will just use the pre content i would just add this and this is the only difference that i have instead of using just post content with the line break i'm actually using pre content here as well let's go ahead and run each of these lines here this is going to recreate the htm and then we run this again now notice we have lines and we have lines here and we have the names of the captions right above it we're getting closer step by step this is all about building a tool like this you can't do it all in one shot because this can get very complicated very quickly so you just do one piece at a time now we have the table captions here the next thing that we need to do is we need to tweak things a little bit so let me show you what i mean here referring up to this again notice that i have replication status and then i have domain controller last replication attempt replication status here same thing with database status we have the database status label and then we have the properties here however looking at our current output this looks good we have the replication status looks good but look at database status we have ps computer name and ps show computer name i don't want those in the output at all in order to do that we can either limit those properties inside of the db info if i look at db info here well first of all it doesn't even show up the reason for this can be a number of different things let's see if it shows up with select dot star so you notice that it didn't even show up with select dot star now there's some instances to where this will happen to keep things simple let's just say that it's much easier to convert this out to html so convert it down to a text format and see what happens in order to remove these with the convert to html you can actually specify properties that you only want to see for this property parameter i'm using domain controller db file path db size and white space log enable which is exactly what i want to see i don't want to see any other ones so i will run this again and create the htm file and then i will look at this again and now notice that those two properties have gone away this looks exactly like i need it to as a once off just make sure that i got everything oh looks like i did forget one thing here so i want a rand footer at the bottom here and with the name of when it ran so let's go ahead and just add this here on the fly that footer is below the database status table here in order to get this below the database status i can use a post content here below this table which will then add it to there so let's go ahead and put this at the bottom here database info convert html so i have pre content and notice that i'm not using post content so i would just put in post content here and i will say ran colon and then i want the date so get date and because i am converting this over to a string i don't need get date to be an object so i know getdate has a two string method i can enclose all of this with a dollar per in now we should be able to get that footer so let's check it out and see once again no errors which is good test the results and now you see we have ran and then the date and the time that it ran notice that it's not a very fancy report by any means in this course i wanted to show you the basics here so how you get this out to html once you get it out to html you can see that it's just an iterative process i encourage you if you need to change this up in any way or make it look prettier you can definitely do that using some of the css techniques that we saw in the later demo but for now we have everything exactly like we needed to so then stay tuned for the next demo where we'll go through and we'll really put the finishing touches on the ad health check tool as with any semi-complicated software project our 80 health check tool could stand some tidying up at this point building scripts like this is an iterative process when a project is completed you'll usually stand back and think you know well i really would have done it this way the first time and that's no problem since it's just code just ensure that the time is added to the end like we're doing here we're not going to change the aed health check tool drastically here rather make it more efficient easier to read and thus more manageable this is done by using the dry method or don't repeat yourself this is a core concept in software development that essentially means use variables and loops whenever you can instead of repeating code this makes the tool much more manageable and finally i'll use powershell regions to modularize the code a little bit this is a small but important detail to point out because as you'll see once more code is added being able to hide and show specific parts of the code makes maintaining it so much easier as with building a typical powershell tool our last demonstration on working with the 80 health check tool is a demonstration on just cleaning it up so what do i mean by cleaning it up well i mean don't change anything functionally with a tool but take a look back at the tool and think about what things you may have changed so how easy is it to maintain how readable is the code and that sort of thing so you'll find this every time when you build a tool in powershell at the end of the fairly large project you'll end up saying well you know i wish i would have done that differently or i need to make this tweak here so i can change this more easily in the future so those are the sort of questions that you need to ask and these are the sort of questions that i've asked with a tool and here's what i came up with so this is an example of our 80 health check tool and notice that i've named it invoke 80 health check report the previous ones were just called adhealt check and functionally this is exactly the same as our other one i've added a few formatting tweaks and things with the html but nothing that really affected the raw output i'll go through from top to bottom on this and explain each of the things that were changed and why i changed them to give you maybe some good ideas for your other projects so the first thing i have here regions i use regions sparingly a few of the other demos regions are really good way to hide code so notice here that the code that i have in this script is 99 lines long however if i just collapse the regions i'm making this code more modular so i can easily see what it does without getting confused by seeing all the other codes so that's the first real change that i made the first region in this case i called it setup i usually have a setup region or section some my more complicated scripts because for powershell best practices it's good to define all of that original all the meta things so what do i mean by meta well i mean all of the data that you'll be using throughout the script so for example here on line 18 i have the dc so i'm grabbing all of the domain controllers in previous demos we were getting domain controllers from a few different places we were getting it over and over and over again we were actually repeating ourselves and making unnecessary calls to the domain controls over and over again as i went through i thought like well oh yeah i'm actually doing it more than once here let's just bring it up to the top in this setup section and then now i can use it within the script i could just call dc's over and over without actually having to do that same thing with 80 users just doing it one time i'm grabbing all of the raw data that i need up front and putting it into this setup section now once i do that i'm then creating a function parameter declaration section so let me show you why i did that so if we go back to our old script here so we'll go back to our one that we created in our last demo that would be a good representation here so notice that in here i am repeating myself quite a bit so i have convert to html convert to html convert to html and i'm having the same general parameters on a lot of this stuff but in reality all this code is doing is it's generating three or four different sections for a report so why would i have to repeat this over and over again if i have so many different similarities this is part of the dry method or the don't repeat yourself whenever you're done with your code and you want to clean it up it's a way to really define and identify each of the areas that would make this code more readable here i have 110 lines but if i want to go ahead and change one of these i will have to change it here you know i'd have to change it here i might have to change it up here you need to create a situation where you only change it in one spot so let me show you up here i'm defining all of these in one spot so first of all i'm defining the header that we're using for the table in our previous example we use the header just for one table here with css i can actually use this for all the tables since i'm changing this style here to just this table element this is going to apply to all the tables next you see this section separator i've defined a variable with the html line break here and all the dashes i did that because if you can see here i have line break dashes line break dashes line break dashes so i noticed that i'm using this quite a bit that's a really good indicator that you need to assign this to a variable next is the sections array sometimes this can get advanced so let me tell you the reasoning why i did this so i have these sections array here notice i have four different hash tables i've conceptualized the 80 health check tool because whenever we ran this we had four different reports four different sections we had one section two sections three sections four sections and each of these are very similar you know they're just html tables and notice this is the new report that it generates but notice that there are just html tables so i conceptualized how this works and then wanted to apply these and just label these as sections it's a really good way to kind of bring up and give you an abstract away some of this code to where you can manage it easier so in each of the sections i've defined a function name so i'm associating a function name with each of these sections looking at the top one here notice i just have my properties and my accounts previously i didn't have this as an actual function i just had it down here in count display however i had all the other ones as functions you know i had invoke dc diag invoke 80 database info invoke replication monitor each of these were sections this count was a section here but i still had it out right here in the raw script it's a good idea to standardize that and make it into a function so i did so i created a get object counts function all that looks like is i just essentially called it object counts put it into a function called get object counts i'll explain the parameters in a little bit but notice that it's just a simple matter of taking that out and putting it in the function the only reason i did that was because to replicate how the other sections were created because then i can create this loop here each of the functions had a few different parameters i'm using the users and domain controller i've defined parameters for each of these functions so if you notice here i have users and domain controller i did that because i can now define the users and dc's up here in my setup section i've divided them here and here one time and then once i define them here one time i can just pass them to all of my different functions so here i'm passing users and domain controller and then using those inside of the function same thing with my replication monitor here i just need domain controller so i'm using it in here if i go to any of the other ones a database i put a parameter up here called domain controller i'm just passing it in and using it how i need to in there and the same thing goes with all the rest of them i parameterized the functions so that i can define it once in my main script and then just use it over and over again and pass it to my other functions since each section has specific parameters needed for the convert to html command i'm defining all the parameters needed for each of the functions so here i have all the parameters that are needed for convert to html same thing with here notice they're a little bit different i have fragment here pre-content post content they're a little bit different so i couldn't actually use the same ones over and over again because they weren't required so i need a different convert to html params now notice that these are a hash table as you learned in the previous demos applying these with splatting once you get more advanced than powershell you'll use splatting a lot in the situation and then the same thing with out file so i have out file params that's the params i'm going to pass to out file and did the same thing for each of these sections so i have the get object counts section here the invoke dc diag invoke replication monitor and invoke 80 database info so i've associated each section in this report to an individual function and then defined out all the specific parameters that are needed to run each of the functions and commands that i needed this part right here this was a big help for me because now whenever i need to change this i don't have to go looking through all the lines to figure out which lines i need to do i can simply come up here to sections and say in my object counts i just want to see users that are enabled you know here i can just do where enabled put that in here now i know that that would affect all of my object counts for all my ad users i can do it once and it applies many times really good habit to get into so once i have all of the sections defined here now i can collapse this region and i can just focus on the next one when writing good powershell tools in the bottom here you'll notice that it's pretty small the reason is because you need to do all of your planning up top as much as possible these two regions here were the hardest by far because you're doing all the hard work you're defining this variable equal this variable when this function runs is it passing these parameters to this function correctly and this and that when you actually get down to executing functional code if you've done it right it's usually very very small so actually executing the code is usually pretty easy so in this instance since i have defined each of those sections in the sections variable i can now apply it for each loop so i can apply the same logic or the same code to each of these sections in order to do that now i can just define one of my function params my convert html and out file params so i can define each of those parameter sets and then here notice that my function name is actually a variable now i can do that with using the ampersand here so i'm using the ampersand which is the executable symbol here which makes this executable so instead of invoke dc diag dash domain controller dc's i'm actually running this here essentially just takes this step further and replaces that function name that we were statically putting in there before to a variable when it's a variable you have more flexibility and more control and then since i have function params defined in a hash table i can then use splatting to simply pass that to the specific function convert it to html using the same splatted parameters and then out file using the same splatted parameters so in essence all of this code that was in here you know the huge majority of this code notice all this code is really really ugly in essence this all comes down to this line here does exactly the same thing i'm just gathering up all that data and defining all those relationships earlier in the process and then now it's just a simple matter of looping over the sections and then executing each of the functions with the right parameters our output is exactly the same now i've added a title here which is pretty easy to do with the pre-content as you learned previously and i'm using the css header for each of the tables so i have the nice pretty output for each of those tables so that concludes all the work that we're going to do with the ad health check tool so i hope the the whole process going from scratch all the way up to this point really helped you i purposely intended to not do everything perfectly the first time going throughout the demos because i really wanted to show you not just how to build an ad health check tool but to actually learn the process on building a general tool to do whatever you want i hope that was a good demonstration for you for building the ad health check tool next up we are going to be focused on taking the 80 health check tool building some schedule tasks for it so we don't have to worry about invoking this manually anymore so now we've got our ad health how to all built and it's running great awesome oh but wait a d just blew up because i forgot to run it oops well let's nip this in the bud next time and make sure to build a scheduled task to automatically execute it on an interval now technically we could do this manually but this is a powershell course let's do it with powershell in the upcoming demo we'll go over how to execute the script from a scheduled tasks by doing so we'll cover what it takes to get a scheduled task in powershell that you can apply to other tasks as well so we've now got the ad health check tool all created and it's working great however it doesn't really matter if it's the best tool ever if it's not ever executed let's ensure that it's executed on a regular basis and build a schedule task around that building a scheduled task we can do this manually but since this is a powershell course i've decided to show you how to do this with powershell that way you can just automate this later on if you need to whenever i first started building scheduled tasks with powershell i thought well just call new schedule tasks and pass a few parameters and be done well that is not the case as you can see because if you really look under the covers of a scheduled task it can get pretty advanced there's a lot of different objects to worry about so let's go over that a schedule task has a specific action so it has a file that needs to be executed somehow and in this instance we are executing a powershell script so notice that we have the new schedule task action command and the parameter is execute and we have a parameter of powershell.exe so that's just the powershell engine and then we have an argument parameter here and this in case it's ps arg so it's a variable that i'm setting that passes the arguments to the file so this is important to know whenever you are executing a powershell script via a scheduled task or anywhere else other than invoking from the console directly it's a good idea to specify a few different parameters technically the only one that you really need to do is file so if you pass dash file to powershell.exe when calling it from cmd.exe for example the command prompt all you really need to do is pass file and the name of the script so in this instance i have script path as variable because the variable name is too long you just have the name of the full path of the powershell script so in actuality the only thing that's really required is this however when you're doing this from a scheduled task or some kind of other automation engine it's a good idea to include these two parameters on here non-interactive and no profile the reason is because whenever powershell.xd brings up by default it's going to create a profile we didn't go over what profiles are in this course but suffice it to say whenever you are executing a script in a scheduled task you typically do not need a profile it's just overhead that's not necessary that's why you can use the no profile command here and the same thing with non-interactive so non-interactive sets powershell in a mode to say you're not actually going to bring up the console and start typing commands with it this lets powershell know that all i want to do is execute this script and then die so that's all that's going to happen these two parameters here are a way to make this more efficient so let's go ahead and we'll do this one at a time as i'm explaining each of these i'll do that so that creates the action variable here so we haven't actually created any scheduled tasks we are just building up to that point the next thing that's optional which i usually try to do is set a scheduled task principle so let me bring up the schedule here and i'll show you what i'm referring to whenever i create a scheduled task i typically want the option to say run whether a user is logged on or not i don't want to have a dependency in place to have some user logged on to my machine this option right here when running a task use the following user account and it has a user account here run whether the user is logged on or not i always want this 99 percent of the time i want this set because i don't want to depend on the user being logged on and in order to do that i have to set a principle here and set a logon type of s4u and then i'll specify user id in this case i'll just use administrator this is not necessary if you are running under the credential that you create the schedule task under it will just create the schedule task under whatever credential you are using but i usually add this in here for all of my scheduled tasks to invoke powershell scripts next thing is the settings this is the new scheduled task settings set command is a way that you can specify all kinds of various settings to this this is completely optional again if you just hit dash here notice i have a lot of different options here now you can set any of these you want this is a good way to really get granular with your schedule task and set it up however you need typically these are the only two that i always set for powershell script so i have start when available which essentially just makes it startable when it's created and then hidden because if i'm creating this in some automated way i don't want it to show up inside of the task scheduler necessarily may not be a problem just being anal sometimes for now just so i can demonstrate this let's just take this off and then we will create that variable once i have the action the principle and the settings variable created i can then actually go and create the scheduled task object itself and then it's just a matter of combining all those two into a task so now that i have task the script still is not created so if i refresh this you see that the script still is not created in here to actually create the script finally is to use the register scheduled task and then provide the input object of the task i'll give it a task name of adhealt check so when i run this this actually will run the check so notice that it gave me access is denied that was because you need to run powershell as administrator when doing this i'm not running the powershell ise as administrator so i'm going to go ahead and do that here so let's bring up the ise and i'll right click run as administrator and then let's go ahead and open up this file again now since went over each of the sections one at a time i can just run the whole script once all right i still got access is denied i believe that's because of this scheduled task principle here instead of cleaning this up let's do this together so the first thing i want to do is just comment this out and then run the script again see what happens access is denied again so i'll go ahead and delete the principle out so i'm not even going to use the principle again and see what happens now so it was the principal option here it did not allow me to set it as administrator so let's now look and see what it looks like we have 80 health check tool and now notice what happened when running a task i am logged in as my lab administrator but now it says run only when a user is logged on i do not want to run only when the user is logged on because it's not good practice to leave a user logged on all the time if you can't help it so notice that instead of administrator it's set to my domain name slash administrator so next thing i want to do i want to try and put that in there and give it another shot and see if that works so i will add the principle back in uncomment that and then instead of administrator i would just do my lab slash administrator run this again now see that it worked all right to confirm i will go over to my task scheduler refresh and then now you see run whether user is logged on or not so there is some discrepancies there between a local administrator or domain administrator in this case i wanted it to run as a domain administrator not technically necessary for the ad health check tool and just needs to read various things from ad that's all there is to creating a scheduled task now you could easily wrap this up into a function but since we're only going to be building one scheduled task to invoke the ad health check tool we don't necessarily need to spend a whole lot of time automating the schedule tasks we are only going to be doing this one time for our final demo we're going to incorporate email into our ad health check tool because even though a scheduled task might be executing the script doesn't necessarily mean that anyone's going to be looking at it to do this we'll use the send mail message commandlet you'll see that once the report is built adding email capabilities is a fairly trivial task and it's due to the simplicity of the send mail message commandlet for our final demo of the module let's add email capability to our ad health check tool and to do this is a piece of cake so this should be a pretty short demo because of the great functionality that the sendmail message command has send a mail message is very simple in our case since the ad health check tool is already in html format we can just simply use this as a body to the message we can also do it as attachment or whatever but for now we are just going to be specifying in the body for the email first i'll define the html file path in this case it's just a root of c i can then just read the email body with git content so email body will now be the email contents of our tool so notice that we have all of the html content in here and then really after that it's just as simple of running send mail message with the right parameters it's pretty easy we have sendmail message the two so where do you want to send it to this could be a group email or something like that subject i named my subject adhealt check report body is html this is optional here because sometimes you may have a plain text email message that you would like to send but since our report is already in html we can actually make the body as html specify the body which is the html content we just created where it's gonna coming from and then the smtp server here so really that's all there is to it to send out the email knowing this let's now just quickly bring this into our ad health check tool that will round out our tool which will pretty much round out the course as well so let's put it into our final one so we have the report here we've generated the file so after this for each loop here is done our file will be generated now we can just copy and paste this here we actually already have the html file path if we go out here to out file params file path was html file path make sure that's set correctly so we've already got the variable defined up here so we can use it down here again so we have the email body we're referencing it here once it's generated we're referencing it we don't need this anymore to demonstrate that that's all there is to it once the htm file here has been created without file it will come down to the line 101 here and then it will shoot send off this email i'm not going to show the email because i do not have an smtp server in my demo environment however that's something that you will need to have in your environment most of the time you have some kind of internal sntp server that allows smtp relay from an internal host for example this is where you would put this in here in order to send email you will need an smtp server on the local machine that you're running the script from or you can use some shared smtp server with the smtp allowed relay commands for your machine to relay through since you've made it this far congratulations you've completed the powershell and active directory essentials course now rather than reading off a summary of everything we covered i thought it'd be more important to leave you with three important concepts for learning powershell in general the first is that anything is possible we covered a lot around powershell and how it interacts with ad but we just barely scratched the surface as to what powershell is capable of due to its prevalence in the industry and flexibility powershell can be used for just about anything if you're not sure just do some googling around before starting on that next task next just break stuff now granted don't break stuff in production get a nice test environment for that i found that really just breaking stuff makes me learn the fastest you're required to fix it and during that process you'll learn so much more than you would just simply viewing a course like this and following it verbatim go back through some of the course and deviate from my instructions break it but figure out how to fix it and finally just be sure to apply these principles to a real world task i'm talking about not just using some of the examples i've provided in the course but use your own take an existing process that you'd like to automate and figure out how to do it with powershell add metrics to the ad health chick tool we've built in the course i mean just don't consider this all you need to know for powershell in ad get out there and explore
Info
Channel: Varonis
Views: 34,628
Rating: undefined out of 5
Keywords: Varonis, Data Security, Threat Detection, Compliance, active directory, windows powershell, active directory cybersecurity, powershell, learn powershell, powershell training, learn powershell online free, learning powershell, powershell tutorial, powershell examples, powershell scripts, powershell script, powershell scripting, writing powershell, how to write powershell, how to write powershell scripts, powershell demo, powershell live code
Id: -zDXTLiX_wk
Channel Id: undefined
Length: 302min 45sec (18165 seconds)
Published: Tue Jan 04 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.