Become a PowerShell Debugging Ninja
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 60 | |
Author | ||
License | CC Attribution - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/37365 (DOI) | |
Publisher | ||
Release Date | ||
Language | ||
Producer | ||
Production Year | 2018 |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
1
10
14
18
24
25
26
32
34
40
41
44
46
54
00:00
InformationSystem programmingTwitterPower (physics)Interior (topology)Division (mathematics)Error messageSineExecution unitSimulationInclusion mapRule of inferenceAddressing modeProgrammable read-only memoryWage labourMaxima and minimaLimit (category theory)Visualization (computer graphics)Different (Kate Ryan album)Graph coloringError messageMultiplication signCore dumpFunctional (mathematics)String (computer science)BitSystem administrator2 (number)Representation (politics)Presentation of a groupData managementScripting languageMathematicsPhysical systemProduct (business)CASE <Informatik>Gastropod shellFile formatContent (media)InformationPoint (geometry)CodeSubject indexingDemo (music)Slide ruleRight angleDefault (computer science)Line (geometry)Sign (mathematics)Linear regressionSoftware developerIntegrated development environmentSoftwareDebuggerComputer architecturePlanningIsing-ModellWindowComputer programmingElectronic mailing listWordCategory of beingProfil (magazine)Function (mathematics)Complex (psychology)NumberObject (grammar)Computer animation
09:24
Power (physics)Advanced Boolean Expression LanguageSummierbarkeitWechselseitige InformationMaxima and minimaInformationGamma functionFormal languageException handlingAsynchronous Transfer ModeChemical equationConvex hullElectronic data interchangeLTI system theoryLatent class modelNormed vector spaceInterior (topology)Precedence diagram methodInclusion mapProcess (computing)Forcing (mathematics)Electronic mailing listFile formatObject (grammar)Category of beingError messageException handlingInterior (topology)InformationFigurate numberSubsetSound effectBitRootCausalityTouchscreenSelectivity (electronic)CASE <Informatik>Point (geometry)Software bugSign (mathematics)Right angleTraffic reportingReal numberSource codeComputer networkLevel (video gaming)WeightCovering spaceCodeTracing (software)Stack (abstract data type)Series (mathematics)Form (programming)Group actionUtility softwareSystem callString (computer science)Function (mathematics)Multiplication signDefault (computer science)Table (information)Functional (mathematics)QuicksortLine (geometry)Scripting languageEntire functionGreatest elementModule (mathematics)
18:47
outputCategory of beingError messageLimit (category theory)Precedence diagram methodHill differential equationInclusion mapMenu (computing)CountingPrice indexAiry functionInfinityProgrammable read-only memoryExecution unitTwin primeNormed vector spaceConvex hullGastropod shellElectronic data interchangePointer (computer programming)Power (physics)CodeSelf-organizationScripting languageBlock (periodic table)Type theoryPeer-to-peerError messageException handlingSubject indexingDifferent (Kate Ryan album)Software testingFunction (mathematics)Physical systemCASE <Informatik>QuicksortRight angleModule (mathematics)Square numberPoisson-KlammerSystem callFunctional (mathematics)Point (geometry)Direction (geometry)AuthorizationStack (abstract data type)Uniform resource locatorOrder (biology)Division (mathematics)Data structureNumberTracing (software)Object (grammar)Cursor (computers)Group actionCausalityLine (geometry)WritingSinc functionRevision controlStructural loadSource code
28:09
Menu (computing)Precedence diagram methodHoaxPower (physics)Convex hullInclusion mapExecution unitThomas KuhnDivision (mathematics)SummierbarkeitDialectColor managementGEDCOMAlgorithmic information theoryMIDIGroup actionWindowPointer (computer programming)Linear partial informationMaxima and minimaEmpennageBitConstructor (object-oriented programming)Error messageSoftware testingRevision controlSocial classCodeDemo (music)Group actionData structureTouchscreenProper mapAbsolute valueComputer fileFunctional (mathematics)1 (number)File formatGame controllerPoint (geometry)NumberGoodness of fitLevel (video gaming)Latent heatMultiplication signExpected valueRight angleEndliche ModelltheorieBlack boxParameter (computer programming)Context awarenessDisk read-and-write headWindowSystem callCASE <Informatik>InformationLine (geometry)Module (mathematics)Grand Unified TheorySign (mathematics)Core dumpMathematicsSource code
37:31
Computer wormMenu (computing)Power (physics)Host Identity ProtocolInclusion mapAvatar (2009 film)Duality (mathematics)Normed vector spaceHill differential equationMaxima and minimaPersonal identification numberExecution unitDivision (mathematics)Link (knot theory)FluxSystem callSet (mathematics)Error messageCodeException handlingBitControl flowPoint (geometry)Directory serviceFunctional (mathematics)Statement (computer science)WritingFunction (mathematics)Scripting languageModule (mathematics)Different (Kate Ryan album)Line (geometry)Position operatorDebugger2 (number)Message passingRight angleForcing (mathematics)Multiplication signRow (database)Block (periodic table)InformationCategory of beingCASE <Informatik>Stack (abstract data type)Sign (mathematics)Software testingTouchscreenString (computer science)Visualization (computer graphics)DivisorProcess (computing)NumberSystem callKeyboard shortcutComputer fileMultiplicationSource codeSource code
46:53
Convex hullLocal ringInfinityContinuum hypothesisElectronic visual displayDebuggerPolygon meshProgrammable read-only memoryGamma functionHill differential equationHardware-in-the-loop simulationGastropod shellNP-hardLine (geometry)MIDIFlip-flop (electronics)Invariant (mathematics)Computer wormWechselseitige InformationScalable Coherent InterfaceFunction (mathematics)Normed vector spaceSalem, IllinoisSimultaneous localization and mappingMaxima and minimaFingerprintGraph (mathematics)Demo (music)Execution unitDean numberError messageCASE <Informatik>Level (video gaming)Process (computing)System callScripting languageRemote procedure callControl flowFlow separationLine (geometry)Position operatorFunctional (mathematics)MathematicsWindowDifferent (Kate Ryan album)Type theorySpacetimeOcean currentSet (mathematics)DebuggerStack (abstract data type)Computer programmingSign (mathematics)Condition numberCore dumpContent (media)Exception handlingVisualization (computer graphics)Point (geometry)Electronic mailing listComputer fileCodeNumberVariable (mathematics)Default (computer science)BitMilitary baseContext awarenessMultiplication signMessage passingGoodness of fitKeyboard shortcutSoftware developerSource code
56:15
System callRankingPower (physics)Rule of inferenceElectric currentDirected graphMagneto-optical driveMUDSimulationComputer wormWeb pageIdentity managementNP-hardDampingPermianConvex hullLocal ringSynchronizationWindowSineMaxima and minimaDuality (mathematics)CountingColor managementThomas KuhnMenu (computing)Normed vector spaceExecution unitComputer iconView (database)Metropolitan area networkPolygon meshBit rateProgrammable read-only memoryProcess (computing)Control flowLine (geometry)Point (geometry)Revision controlSet (mathematics)Computer fileDebuggerPointer (computer programming)Error messageSource codeVisualization (computer graphics)Exception handlingOpen sourceLoop (music)Module (mathematics)Core dumpContent (media)Hecke operator1 (number)Bit rateCodeMultiplication signSoftware bugPhysical systemKeyboard shortcutGreatest elementAliasingRight angleCursor (computers)Variable (mathematics)Block (periodic table)Uniform resource locatorGame controllerSemiconductor memoryQuicksortHydraulic jumpCondition numberIterationSystem callProper mapFunctional (mathematics)Source code
01:05:37
Power (physics)Convex hullOnline chatExecution unitMIDILipschitz-StetigkeitWechselseitige InformationMaxima and minimaGamma functionInformationLimit (category theory)CountingFluxMenu (computing)Module (mathematics)outputHill differential equationInclusion mapInformationDebuggerScripting languageControl flowPoint (geometry)Condition numberSet (mathematics)Sheaf (mathematics)2 (number)Revision controlNumberComputer clusterMultiplication signParameter (computer programming)MereologyLevel (video gaming)Computer fileDifferent (Kate Ryan album)Visualization (computer graphics)WritingMultiplicationModule (mathematics)Functional (mathematics)Line (geometry)Group actionBlock (periodic table)System callAliasingBitoutputArithmetic meanFunction (mathematics)Software testingConnected spaceStreaming mediaError messageCheat <Computerspiel>
01:14:59
Hydraulic jumpUser interfacePermianConvex hullModule (mathematics)Power (physics)Inclusion mapImage warpingLocal ringGastropod shellVariable (mathematics)Execution unitPolygon meshMagneto-optical driveoutputCorrelation and dependencePersonal identification numberHill differential equationFlynn's taxonomyMereologyPoint (geometry)Service (economics)Type theoryModule (mathematics)Right angleState of matterTwitterCASE <Informatik>Control flowOpen sourceScripting languagePhysical systemBlack boxMoment (mathematics)CodeVisualization (computer graphics)WindowIsing-ModellCore dumpLine (geometry)Game theoryLevel (video gaming)NumberDebuggerInformationBlock (periodic table)Object (grammar)Functional (mathematics)Power (physics)Stack (abstract data type)Attribute grammarMultiplication signError message
01:24:21
Discrete element methodConvex hullSineoutputCAN busHill differential equationPermianModule (mathematics)Hydraulic jumpMaxima and minimaMotion blurInformationIdentity managementLink (knot theory)Execution unitWindowCapability Maturity Model IntegrationSimulationNP-hardPoint (geometry)Block (periodic table)Control flowAsynchronous Transfer ModeContext awarenessLine (geometry)Game controllerLevel (video gaming)NumberFunctional (mathematics)Latent heatAngleSemiconductor memoryIsing-ModellDoubling the cubeSystem callModule (mathematics)DebuggerPhysical systemPoisson-KlammerAttribute grammarLoop (music)WeightCodeProcess (computing)InformationCodeRevision controlObject (grammar)Ocean currentCausalitySinc functionType theoryVariable (mathematics)Scripting languageDifferent (Kate Ryan album)Computer filePOKERemote procedure callStack (abstract data type)Queue (abstract data type)Right angleSpacetime
01:33:43
Mortality rateHill differential equationPower (physics)Convex hullComputer musicDiscrete element methodDean numberLocal ringExecution unitDirected graphMaxima and minimaMenu (computing)Lipschitz-StetigkeitProgrammable read-only memoryNormed vector spaceInclusion mapElectric currentEmailElectronic visual displayLattice (order)LeakCountingVacuumProcess (computing)CodeScripting languageDebuggerExistential quantificationKeyboard shortcutCASE <Informatik>Object (grammar)Point (geometry)Figurate numberSpacetimeLine (geometry)DemosceneLocal ringLoop (music)HookingElectronic mailing listControl flowSystem callComputer fileRemote procedure callVirtual machineIsing-ModellWindowDoubling the cubeDifferent (Kate Ryan album)Inheritance (object-oriented programming)Core dumpComputer animation
01:39:59
Lattice (order)Process (computing)Cone penetration testUniform resource nameControl flow graphNormed vector spaceCountingDebuggerComputer wormGamma functionError messageTime zoneMenu (computing)Interior (topology)RootOnline helpInfinityNumberCodeProcess (computing)Scripting languageFerry CorstenWindowState of matterSpacetimeMultiplicationPoint (geometry)Entropie <Informationstheorie>Core dumpMultiplication signLevel (video gaming)Menu (computing)Line (geometry)Ising-ModellMathematicsEvent horizonComputer wormVisualization (computer graphics)DebuggerCASE <Informatik>Software bugVariable (mathematics)Computer fileRemote procedure callFigurate numberAnalytic continuationComputer animation
01:45:37
Core dumpFile formatModule (mathematics)Installation artEmailFacebookEvent horizonComa BerenicesTwitterCodeContent (media)Slide ruleMultiplication signAddress spaceModule (mathematics)InformationComputer animationXML
Transcript: English(auto-generated)
00:10
Good morning. There's nothing like the smell of a debugger to wake you up in the morning. I love coming to this conference and I love delivering this session. This is one I've
00:22
delivered in the past. Chris Wall's come here in the past to this session, although I've freshened it up a bit for working with PowerShell Core. I love delivering this here because there's no other conference where I can come and talk about PowerShell debugging and have this many people in a room, especially when there are other sessions going on at the same time with Don Jones and Mark Minassi and there's some big name presenters
00:43
who are doing content right now and you guys are coming here to learn about PowerShell debugging, which is great. My name is Kirk Munro. I'm a geek. I spend a lot of time working with PowerShell. Well, I have spent a lot of time working with PowerShell. I spend a little less time these days because I'm a product manager for Learn On Demand Systems. A lot
01:03
of my thoughts these days are about teaching people all technologies, not just teaching people PowerShell because that's what we do with Learn On Demand Systems is we help people learn tech. I've been a PowerShell MVP for the past ten years. For you guys who haven't met me or haven't seen me talk before, I can tend to speak a little quickly.
01:21
If I do, feel free to call out and ask me to slow down. I delivered this session last year to a room that was standing room only in the back and I had an hour to do it and it was a lot of information. This time, I get to relax a little bit, breathe a little more, hopefully pause to see where there's questions. I can do some stuff ad-hoc.
01:45
I really want you guys to chime in and call out where you want me to clarify on certain points and that's it. It's a little less rushed, a little bit more relaxed going through what I know and tricks that I use to help me do solid debugging so that I can
02:02
get my code working more quickly. We're going to talk about debugging skills, debugging demos. This is a very demo heavy session. There's hardly any slides because you're not going to learn PowerShell debugging from a slide deck. Some of this is native content. A lot of this is native content. I also show off a little bit of my work
02:23
where I've done some things to extend the debugger and try to push it a little bit further and some cool things that you can do with that and also just kind of talk about general tips, recommendations, best practices through the whole thing. I'm going to go into demos here in a minute but first, I just want to ask a few questions. One of the things
02:40
that's interesting about this conference this year is they asked us to demo within Visual Studio Code using PowerShell, well, using that environment for our shell environment. I thought, well, I'm going to push myself further and also go directly into PowerShell core for the start of the debugging. This is plan A with PowerShell core. This is my plan B.
03:01
If things go a little bit off here, I haven't demoed on PowerShell core before, but I've gone through this and it looks like it's working fine and that's great, but if things go a little off, then I'm going to jump over to plan B where you might see me switch to ISE. Hopefully, that's not a bad word for people in the room. I still use ISE. How many people still use ISE? Yeah, lots of people, right? This is recording and this is
03:24
going to be pushed out live to the web. There's tons of people using ISE. It is a great tool, and Visual Studio Code has that level of complexity. It's not enough like ISE to make it easy to jump to ISE, so there's nothing wrong with ISE. The things I'm talking about
03:41
are general skills. They can apply if you're using Visual Studio Code, PowerShell core, on Unix, Visual Studio Code, PowerShell core on Windows, PowerShell ISE on Windows, working with Azure Cloud Shell. I'm going to go through general debugging skills and tips and tricks that are going to hopefully make you figure out what's going on with your scripts
04:01
faster in all these different environments. Don't get stuck on the fact if I'm doing something in ISE or something in Visual Studio Code, there's certain places where I'll call out what differences are just so you guys know what those are all about and that's about it. So, let's get started. Now, back of the room, when I looked, that was fine for me. Is that
04:24
alright for you guys in the back of the room? Yeah, okay, great. So, one thing, actually I'm just going to ask a question to the room. Something really simple. So, inside of PowerShell ISE, I can change the color of my error messages. Inside of Visual Studio
04:42
Code, I haven't figured out a way to do this. I think it's not there. Can somebody confirm that that's not there? Joel, you tinker with this stuff. Do you know? Okay, so normally, so one of the first things I do when I do this talk and it's a fairly straightforward thing is, so I'm just going to load up a bunch of stuff here. One second. So, I've
05:02
got this reset function and this reset function, you'll notice there's this to-do here with a line commented out. Because one of the things I like to do, one of the big recommendations I make to people, and this is silly, but it's important just the same, is change the color of error messages. It can make a big difference. If you control any kind of profile script
05:22
that you push out to your environment or you're working with a bunch of PowerShell users and you want to just give them a tip that's going to help them out, change the color of the error. Because it's weird, but I've seen many seasoned administrators run PowerShell commands, you know, they ask me how do I do this or I need a script to do that, and you give it to them, and they run it, and then they come back over
05:44
to your desk and they say, it failed. And so you say, what happened? And they say, it was red. And so, it's really surprising, I mean, I'm joking here a little bit, but the fact that it's red, right off the bat, people see, oh, there's an error.
06:02
And they think, I'm not a PowerShell user, and so I don't know how to read this, and so I'm going to go get the guy who does. And so that's exactly what they do for people like me. So, change the error color. Because oftentimes, the error message says exactly what the error is. There's plenty of times where it does not, which is fine,
06:21
but in this case where it does, you want them to be able to read the error messages. And changing the color can make that difference. And normally I like to do that right at the start and I can do that over here after, but inside of here I can't, and so imagine this is green. Okay. So, moving on. Yeah, and I can't change the color, that's fine,
06:43
skip over that. So, I'm just going to load up my error variable. Actually, I'm going to clear my error variable first. So, if you don't know, in PowerShell, there is a variable available by default called error, dollar sign error, and that's where
07:03
all errors go. And I'm just going to basically prime the pump a little bit here, and let me make sure that I've got stuff here that actually runs on this system. Oh yeah, that's going to, differences between core and, this is just what I missed, between PowerShell Core and PowerShell Windows. So, I've got this function here that's going
07:27
to load up 20 errors. And so now, if I look at my error count, just to make sure that worked. So, I've got 20 errors. So, all errors are stored in error, and so I can
07:44
just look through them all, and when you do that, let me actually move this a little bit so I see a little bit more of the bottom view, you can get, it can be very overwhelming because you guys probably already know a lot of errors in PowerShell are not terminating errors. And so, sometimes you can have a script and you run it and
08:01
it says, holy cow, not only am I not working, but I'm not working all over the place. And it's a whole lot of errors. And so, trying to digest that can be overwhelming, but there are certain tricks that you can use to break down that information. And some of these tricks just come from working in software development. Like my background, I started my career doing software development and then architecture and then PowerShell and product
08:23
management. And so, taking some of those programming skills that I developed years ago, oftentimes you want to look at things like, well, what are my errors that are the most common, or what's my first error, because sometimes it can have a cascading effect, and so there's different tricks that you can do. So, one of the things that, so if you look at
08:41
the specific error details, now, just to show you what that ran, so just from here down, right, this is one error. And notice that I took my, I can index into it, right, so I took dollars on error zero, and I said, okay, format list and show me all the properties. And it gives
09:00
me this weird-looking output. The reason, PowerShell's got a fair number of interesting quirks. One of the quirks is that there are certain objects that you cannot get the detailed information for by default. So, even if I told it to format list star, or even if I picked it to format table, it's going to give me this string blob, which is the
09:23
string representation of the error telling me what line it was on and so on. But that's useful, but that's hiding information from me that can help me troubleshoot my errors. So what you need to do is you use force. So if I do, if I pipe to format list star
09:42
dash force, then I actually get the list information. And so I get all the properties. And so I can see there's this exception property. And the exception property, that's something that comes from .net under the covers. And so that tells me if something happened inside of .net, what that actual exception was. It could come from PowerShell
10:01
too, because you can generate exceptions there. But at any rate, it gives me the underlying exception to the error if there was an exception. And then, going down a little further, then I can see other details, like I can see the script stack trace. So if I was running this inside of a large series of PowerShell PS1 files, one calls another, calls another.
10:22
Or function A calls function B calls function C, as happens in this case. You can actually see the stack trace. So you can see it went from, well the error happened at C on line 10, and it was called by B on line 13, and now that was called by A on line 17. And so you can peel back the onion, and you can go figure out where the source of
10:43
the problem came, and at what point do you want to start troubleshooting it based on where it happened in the call stack. Because when you're looking at a stack trace, and you have an error that happens here, you have to identify, did that error happen because of a bug right here? Did that error happen because of the way I invoked it here or higher
11:04
up? I passed in some data that I wasn't expecting, in which case, yes, I can fix this guy and make it handle unexpected data and report something appropriate. But you need to figure out when you call these things, whether it was inside the code you called, or whether it was the way you called it from the outside, and looking at the call
11:22
stack and figuring out where the stack trace, and figuring out where that is, is important. Now let me scroll down a bit. So when the top level error information isn't clear, general process. You get an error. You're looking at the error, and you look at it from the outside from PowerShell, and you're looking at the error message, and then
11:40
you can look at the stack trace. If you still don't know what's going on, then go a little deeper. I talked about the fact that there is exception, which is just a property. So if I look at the exception, now that didn't give me much information as well. So right here, error zero dot exception, it just gives me this string output saying
12:03
the path is not of a legal form. But exception is also an object because everything is in PowerShell's objects. So I can ask it for all of the properties by preparing it for my list star, and again for exceptions, I have to use force.
12:23
That's because for the same reason with errors. By default in PowerShell, they don't expose everything. Let me scroll up a bit. Now I'm looking at the exception, and I can see, was it thrown from a throw statement? I can see the message, which is the same thing
12:41
that's output when I just try to output it without force. Then I can see if there's an inner exception, and inner exceptions are important, and understanding that they're theirs is important. Not all exceptions have inner exceptions, but sometimes you have cascading effects where you get an error that has an exception, that has an inner exception, that has another inner exception, and so you just keep digging in a little
13:02
bit deeper to figure out where the root cause is, and it's good to know that that's there, and that you can actually use members to dot into it, because there are examples out there where the error message that you get back doesn't tell you a thing about what actually happened, and you go two, three levels inside, inside the exception, the
13:21
inner exception, the inner exception, and you look at that text, and it says exactly what was wrong, and it's clear as day. Those are examples where sometimes the error on the outside is obtuse, and you dig in, and then you find, oh, that's the nugget, that's what's actually going wrong with my script, and you can figure that out. Knowing that inner exception is there is important, and also, just calling out for exceptions,
13:44
they also have a stack trace. If you're doing any compiled cmdlets, or if you're working with C sharp binaries, or dot net binaries, and you have code, you can actually go and look up, you can find the stack trace here, and you can go and look up what was going on in that rabbit hole. A lot of debugging is about figuring out, trying
14:01
to identify, hey, I have a problem, does it tell me what the real problem is, and can I fix it? If not, how do I find the information that's in that problem to figure out how to fix it? You just got to figure out where to look in a lot of cases. Of course, sometimes there are places where you're going to get an error, and it's not going to really tell you what's going on, in which case you need to do a deeper dive
14:24
on thinking conceptually about what you're doing, and what it's working with, and try to peel back that onion. That's outside the scope of what I want to talk about right here. I'm trying to focus on showing you the information readily available to you, to help you get to the bottom of stuff, but it's not going to solve every scenario, that's all.
14:43
So now, inner exceptions, just like regular exceptions, you can pipe them to, there's still regular exceptions, it's just under a property called inner exception, and you can pipe it to format list star, with force, and get the details about what's going on. Oh, and if you don't like using force all the time, one of the things I do on the
15:08
side that I've done in the past, and I still maintain them, although format px needs an update because it does not work yet on PowerShell core, but that's going to come. I have a module called format px that makes it just basically so you can pipe to format
15:23
list star, and it'll give you format list star, it's not going to make you use the force to do it, because why would it, that doesn't make sense, and so I try to work around certain gotchas and format px, that's one of the gotchas, it's just this having to use dash force, another thing I try to work around is, you guys probably know that
15:41
when you pipe to format dash table or dash list or whatever, that that's the end of your command, because it converts, it doesn't just output, it actually converts the object to this format stuff, collection of objects that's complex and you can't pipe beyond it and do things, format px fixes that so that instead of converting it, it'll
16:02
figure out, okay, this is the default format you want, but I'm still sending the object down the pipeline, and then at the end of the pipeline, it looks and says, okay, here's the default format you want, and so it'll give it to you. So anyway, that's something that you guys can take a look at if you want. Questions so far? Why format list star?
16:21
So you don't have to, asterix just says I want all properties, the only reason I throw that there is when I know that I want all properties, I don't want to think about, there's a lot of cases in PowerShell where you have an object and they've defined what the default property set is, but not the entire property set, and so rather than guessing, if I know I want everything, just out of habit, I always do format list star.
16:42
You're welcome. So select almost, select star creates a new object that's not the same object and gives you all the properties based on what you piped into it. Format is creating a new object because of how the formatting layer works, but that's
17:01
internal details for PowerShell, but format's really about taking an object and saying how you want to show it on the screen. Select is about taking an object and saying, okay, I want some subset of this, or I want to massage it, and then continue to work with it. There was another question over here? Okay, great. Yes.
17:25
Oh, thank you. Yeah, that's actually a really important one, and I didn't mean to skip that when I was scrolling, so thank you very much for calling that out. Yes, okay. Actually, this is a really key point that I should have gotten into earlier, but doing it now is fine anyway.
17:40
So when you're dealing with dollar sign error and you have a lot of information, because they're objects and those objects have properties and PowerShell has these really cool things like grouping and sorting and formatting, you can apply those common utilities in PowerShell, the utility commands, and parse out your information to figure out, okay, how do I want to tackle what's going on in my script?
18:00
So if I just run this, now at the bottom, I can't scroll up here, but that's fine, here I get a count, because sometimes errors happen lots of times. So what I've told it to do is I have to take my collection of errors, group them using the default grouping, which is fine, because it's basically errors just by typing
18:21
it into group object, it'll group it based on the output text. So if you have an error that happens a whole lot, it'll just group it based on that. And then once they're grouped, sort it by the count, so in descending order, so I get the prioritized list, and then format in a table. And so here I can see, okay, this error happened eight times, this one seven, this one five. And so if I've got a script I ran and it says the holy cow, there was a lot of errors,
18:45
and I really want to try to prune that back, one of the things I might do, I might look at the first error, see if that's like, okay, that was a cascading effect, look at the first error that happened, and then try to resolve that one, or I might prioritize them so that I can start knocking them down in huge chunks, rerun, and it's going to just
19:04
get less and less and less until I get down to a working script. Thank you very much for calling that out. I really meant to show that. Does that make sense? Yeah, okay. Other questions? Yes. Is it useful to... Yes, that's correct.
19:20
Yeah, thank you. Yeah, so when I'm talking about, that's great. So when I'm talking about sometimes look at the first error, if you run something that's got a lot of errors, you might want to first clear your error stack, so $error.clear, and I'll talk about that in a second, and then rerun it so it's clean, so you just got the errors that happened from that run, and it's an array, but item zero is the
19:42
last error that happened. So yeah, it's a stack. It's pushing the errors down, so if you want the first error in your stack, you can use $error square bracket minus one square bracket, and that'll go all the way to the first guy that happened. And so that's a great point too. Thank you. Other questions? Okay.
20:00
So, stack traces. Okay, yeah, here we go. So I talked about the different stack traces, and so you can call them out directly. So $error, zero, .script, stack trace. That's for locations in PowerShell, and for commandlets, then you go into .exception, .stack
20:24
trace, and just notice the difference between one is script stack trace, and then the other one is .exception, .stack trace. And so that just helps you figure out what the possible causes were and what was going on in the various stacks.
20:41
Now when you're dealing with errors and you're going through the cleanup process, you can remove a specific error, and so you can do $error.clear and then rerun and then $error.clear and then rerun, or as you knock them down, you can remove them. So knowing it's a collection, you can do .remove for a particular object useful, so I can remove
21:01
the last error that happened, or I can remove at a certain index, or I can remove an entire range, so the last 10 errors that happened, I can take them out. And the reason why this is the last 10 is because this is not first index to last index in that command up there where my cursor is. It's first index and then count. So starting from index zero, get rid of 10 errors, so I can do that, and then I can
21:24
clear the whole thing when I've gotten rid of all the errors that I don't want. So now let's talk about another interesting quirk with how PowerShell handles errors. So if I run this line, so one divided by zero, and then writing to my host, notice
21:49
that I got the error I was expecting because I can't divide by zero, and this is a case where you need to read the red text because it tells you exactly what was going on, and then I got that write host call to work.
22:01
And so this is something that personally that's really bothered me about PowerShell, and I really wish it didn't work this way, but it's worked this way since PowerShell version one hasn't changed, and maybe now it's open source, we might be able to do something with it, but that hasn't happened yet. So one divided by zero is a terminating error, but it didn't terminate, and so the reason
22:26
it didn't terminate is because I didn't have it inside of a try catch block. So if I take this function, load it in PowerShell, and so all this function does is wraps my code inside of a try catch block, I'll talk about the other stuff it
22:42
does there in a second, and then I run that guy, I can see the error message, and I don't see will this run. And it's really important to know this because if you write PowerShell scripts or functions and modules and you're sharing that with other people, and the way it behaves
23:07
might be dependent on the person who called it depending on whether or not you're using try catch, because if you have an error that normally would be terminating if it was in try catch, and it's supposed to be terminating, but you didn't wrap it in try catch, and somebody invokes you and they wrap it in try catch, they're going to get different
23:23
behavior for the invocation of your script, because it will actually terminate in that case versus not in yours, maybe you don't want it to terminate, and you wrote your script and it just worked, and that's great, and you got the error, that's fine, you say okay that's benign, keep on going, do the work. But somebody says okay that's great, I love this script, I'm going to write a function,
23:43
I'm going to wrap it in try catch, I'm going to call this guy's code, it works really great, it doesn't do what was advertised, they come back and say it's not working. Well one of the reasons could be because of the try catch thing. So as a general rule, as a best practice, I try catch all the code that I work with in PowerShell inside of my functions and scripts.
24:03
Unless it's like a one-off script, I might be a little lazy, there are certain use cases, depends if I'm doing it for myself versus if I'm sharing it with the rest of the world. But if I'm sharing it internally in my organization or with peers or with the community, I will wrap in try catch to make sure the terminating errors act as terminating because
24:21
I want my script to run the same on every single system where it's run, no matter who calls it or how they call it. Make sense? Yes. So trap can, I'd have to think about that or try a few things to make sure that it works just as well. The only place that I use trap these days is inside of my module manifest and I only
24:45
do that so that I don't have to have this great big, huge try catch with indent, in which case I'll just do trap at the very top and then run my code and that seems to work fine. So I want to say yes, but since I hadn't been asked that question before, I'm like not 99% sure, but not 100% sure.
25:11
Yeah, that's a great use case. Yes, thanks Joel.
25:34
Thanks for calling that out. If you guys don't know him, by the way, that's Joel Bennett, another PowerShell MVP in the back. Great resource for talking to about this sort of thing.
25:43
So now let me talk about the other thing I'm showing here inside these commands. So I've got two different flavors of the command. So I've got them both loaded now. So test something and test something two. The only point here was just to generate some error and then have some code after the error and control how that happens.
26:00
So now I sort of already talked through this, but not 100%. So if I run test something two, it's inside our try catch. That's great. And I don't get the right host call because errors are terminating. And I'm catching it and re-throwing it, right? So if you work with try catch, the structure's pretty simple.
26:22
Try the code block of what you want to run. Catch what you want to do with an exception. You can specify an exception type when you want to handle certain exceptions. In this case, this is a generic catch all, all exceptions. And if you put throw inside of your catch all, or actually inside of any catch, it will just take your exception that it caught and re-throw it up higher to somebody else who is catching it.
26:46
Why? The difference between that one and, yeah, so here you can see the one that I just showed you at the bottom versus up top. The one where I'm storing the caller error action preference, and I am using write error.
27:05
Take a look at the difference. So look at the output right down here. I know it's red, but look anyway. So one divided by zero. So this error output tells me what the error was, and then it gives me line five, character nine inside of my script or function that I called.
27:25
And it gives me the actual code that was run inside of that function, which can be great if you are the author of the function because you want to know when something happens, where it happened internally.
27:41
But now compare that with this one. Oh, sorry, thank you. Got my numbers mixed up because I did it in reverse order. So compare that with this guy.
28:01
Same error message, except it tells me what was invoked to cause it. Test something was invoked, and that was the error that came up. And line one and character one, that refers to where test something was invoked, not the line with the error inside of the call, and it gives me my command, which could have parameters on it, you know, of what I actually invoked.
28:23
These are the errors that you guys get if you run a PowerShell commandlet and it generates an error, it doesn't give you back an error message saying, oh yeah, in C sharp file, do something dot CS on line 35 at character, or in column eight,
28:41
here's this internal C sharp code that had an error. Because you wouldn't want to see that, because it's a black box. If you run start service, get process, any Azure iron command under the sun, and you get an error, you want the error in the context of how you invoked it, not the error in the context of you're the guy who wrote the thing
29:00
and you want to know the internal details about that error. So that's why I always write my errors this way, in the top one. If you saw this talk last year, or you heard me talk about this before, there is a minor change based on, I forget who,
29:21
I wanted to call them out, but I forget who. Another community member helped figure out about storing the call to error action preference and just using write error. I used to use dollar sign PS commandlet dot throw terminating error, instead of using write error. I like this better because it's not getting down into the weeds quite as much and it's still using write error.
29:42
That structure, the first on line 101, it stores the error action preference of the caller. Then I have my code, which happens to throw a terminating error, and in my catch, I write out that code using the caller's error action context.
30:00
The reason why I do that, let me show you this. I don't think I have this in my file at the top. Yeah, so two different versions of this invocation. So now, I want to scroll this over a bit.
30:21
So all this is doing, I'm invoking test something, which is the version that I like, the one that has the structure around it with the internal write error and using error action preference. When I run it, and I say error action silently continue, it does exactly what I wanted. There was an error, but I told it just continue silently anyway,
30:43
and then it writes host to the screen. And so commands after that work. And similarly, if I run that same command, slightly modified, with error action stop, it stops. So as the caller, I have proper control over it,
31:03
and this is working a lot more like a compile commandlet. And this is a thing for me. So one of my pain points with PowerShell, I've got a good number of them, and I keep talking about pain points. I mean, PowerShell is great, but there are things that just kind of nag at you after a while. One of the things I really don't like is that I cannot write a function inside of a module and have
31:25
that function work and behave just like if I wrote a compile commandlet in C sharp. And I really wish that I could, because I want that keep, I don't want to necessarily have to go write compile commandlets to get that level of detail with how the errors are handled and to not work around some of these gotchas and so on.
31:41
But I can't do that. So I work around a lot of the gotchas, and then there's times where I'm just going to flip over and do it in C sharp because I can and because it will give me the behavior I'm expecting. So this is just one of those cases where being able to use error action to have it function the way that you want
32:00
for that to happen, for that to work properly, you need syntax like this guy right here where you catch the error action preference and then you use it inside of your right error call and your catch. On the flip side, if I call the other one, so,
32:22
let me just run it both at once, and that one works as well, and I'm scratching my head over figuring out why. However, not really scratching my head, but anyway,
32:46
there are scenarios, and this isn't one of them, and I thought I had this nailed before this call when I was tweaking this for this change, but there are scenarios where if you want error action, I want actually this is between core and Windows PowerShell, anyway, there are scenarios where error action will not control the proper behavior
33:05
of stopping where you want to stop and so on unless you follow the structure provided up above. So this is the case where my demo didn't exactly show what I was expecting, but I know I'm right on it based on experience and having gone, oh, actually, wait a second,
33:24
yeah, and actually having gone through this, and so I'll be chewing at this for the rest of the talk, trying to figure out why, but at any rate.
33:48
Yeah, that's a great example. I saw another hand go up, I thought. Yes. So I haven't tried that scenario with classes.
34:32
Generally speaking, when I'm working with classes and constructors, I'll try not to throw inside the constructor as a best practice. I'll let the rest of the code handle errors like that.
34:41
It depends on what you're doing, but it's a good practice to follow. But no, I haven't tried that one specifically. I can flip back to that based on, depending on time as we go through and do a quick look to see because it's easy enough to reproduce the behavior, but yeah, I haven't gone through that scenario. I saw another hand over here.
35:18
That's exactly it. This is a model where, yeah,
35:21
and thank you for calling that out. By following this model, like right here in this function, why am I storing caller error action preference and then using it where it's not doing anything with it? This model means that I don't care what's inside my try. So inside the try, I can work with error action preference, I can do different things, it doesn't matter. I've captured it and I know I'm going to use the caller's error action preference later on. So I just, I follow this model even for simple cases,
35:43
just because I know it's always going to have the caller error action preference, even if internal to my try catch, error action preference is being used by what I'm doing. Other questions? Yes.
36:01
Why, I'm sorry, say that one more time. Oh, the reason for this format versus the other one? Yes. The reason I use test something is because I want, so this format, where you have caller error action preference stored and reused, and we're using write error inside of the catch,
36:20
the reason why I use this format is twofold. One, so I have full control over using error action when I invoke my commands, and two, so that when I get my errors back, they give me information telling me how I invoke the error of what was wrong, rather than the guts inside the function where the error actually happened, right?
36:42
So this case here, where I get internals, if I give a command to you guys, I don't want you seeing an error in the internals and have you scratching your head saying, I didn't even invoke that, why is this saying, there's a one divided bit and so on, and having to dig into my code. I want you to look at my code as a black box, you've called a function, you've called a commandlet,
37:00
same idea, you're just calling it and you see the error based on where it was invoked and all those details. So those are the two reasons. Yes, yep, absolutely. This is great for when you do want to just, you don't want to have to dig into the function and see why the error actually happened.
37:21
One scenario is internal functions, right? So inside of a, when you have a module, you can export functions and you can have ones that are just internal for internal ones. This is fine because if I do get the error and I'm debugging and stepping through it and I get an error message, I want to see exactly what happened, not see how I invoked it because I know how I invoked it in that case, right?
37:40
So that's a really good scenario. Scripts you're using for yourself, or just a script file, where then this is great because it tells you exactly what happened. So that's a trade off between the two approaches. Yeah.
38:03
Yes, so there's my error.
38:22
So I can go in, oh yeah, I forgot force. And the reason why I forget force all the time because I use my module that does it for me. So here I got my error and now I can dig into it and I can look at the exception and here's where I can, okay, I tend to divide by zero and I come down here
38:41
and I see, see in my script stack trace, test something line six. And so that tells me, so right down here, yeah. So this shows me that I invoked this function called test something, line whatever in my script or my function where I called it.
39:00
And then inside of test something, there was an error at line six and on line six, the error happened to be the actual error message that was where divide by zero came from. So I can then dig into the details that way. And if I, I forget,
39:25
I'm doing this little ad hoc, right there. So invocation info is a great utility, is a great property on errors for troubleshooting
39:41
and figuring out how something was invoked. And so when I look at that error that I was just processing and I wanna see the invocation about the error, I can see line, script line number six offset nine, so my actual character position and then here's the error, here's the actual command which is that internal stuff. So you can still get at it.
40:01
Thanks very much, Joel, for calling that out. Yes, right. I don't have a definitive answer for that one
40:21
because I haven't taken it around with a lot of the two. I try writing PowerShell functions and scripts to stick to things like write error. I know you can use dollar sign, host dot, and there's write verbose and write error and so on. There's a bunch of different things. The actual difference under the covers, I'd have to go and look and I'm curious now to look in the PowerShell source code
40:41
and see what's being invoked under this. Yes, yeah, yeah. So that's something I used a lot too for logging purposes when I catch an error and so on.
41:01
So here, in my call to write error, I've got an error record and that's got properties and so I can use dollar sign underscore dot exception dot message to actually get at the actual string text that was used if I was logging it somewhere as well as showing it to the screen.
41:26
Yes, no, a naked throw is a re-throw. So the error variable, the question was when you invoke, when you just call throw, because you've caught an error and you're throwing it up higher up the stack, is that going to cause additional errors to show up in your dollar sign error collection?
41:41
And the answer is no, because the error collection only shows errors at the top level, not errors all the way along as it's being processed through try catch and so on. Other questions?
42:05
Yeah. I won't. So this is the difference between terminating and non-terminating errors. Generally speaking, errors are owned by the user. That's the way I look at it, right? So I'm not going to, unless I'm working around something really funky where there's some error that's being shown
42:22
that I know is not supposed to be shown, then I might do something that's a bit of an edge case. Generally speaking, I will never touch error. I'll let the user manage that because if there's multiple errors, that's multiple pieces of information to figure out why what happened happened and if there are multiple and I'm running my code this way, then I know there's only one terminating because terminating, that's the end of the road
42:43
and so I want to be able to see anything that happened along the way to get there. So yeah, I won't walk around with those things. Okay, I'm going to, I think that was the end of this file. Yeah, it was. So those are just general soft skills about dealing with errors. Let me close that out.
43:00
I don't need that guy for now. So now let's talk about some hard skills. So I'm just going to prime the pump here with a few functions. Now this function, this is just a stack of functions. I've got function A that does something and calls function B.
43:21
Function B does something and calls C and then function C does something and that happens to generate an error and so if I run this, now I see about to get the directory name which I put in as a write host statement. I don't see anything after that.
43:40
By the way, how many people do write host debugging? There's no reason to be ashamed of it. It's really useful. Write host is great just because of the fact that you can just output stuff here and there and then yank it out when you're done with it. So if you're really trying to figure out what's going on, the debugger's one way, write host is another. The debugger sometimes is just a little bit more depth
44:02
than I want to go into for certain things and so I'll just throw in a few write hosts and sometimes I'll throw in write hosts where it's just write host A, write host B, write host C just to see how far something got along and then yank it out when I'm done. So there's nothing wrong with that. I know people say write host kills kittens but I don't think so.
44:21
So you can see write host about to get the directory name here. This guy shows up and then there's a call and then why doesn't this second message show up? And so in practice, one thing you should be very, very careful of is almost never ever do a naked catch statement
44:40
with nothing inside of it where you're processing, re-throwing, doing something with an error message because it swallows all errors. And so if you write your code and you think okay, my error's benign, I don't need to do anything with it, so I'll just throw it into a catch in which case that's not about taking the error collection and cleaning it up. That's about stopping something from getting into the error collection because oh, it's benign, I don't need it,
45:01
so I'll just catch it. And then later on you call into something else inside of your try block that happens to throw something that actually is an error that means something to you and it's swallowed and you don't know what's going on and there's no error message, so how do you debug? So just general rule, don't put a naked catch block. But now what I wanna do here
45:21
is you've got a script here, it's not working, it doesn't tell you why, and so you wanna debug it. So let's enter the debugger. So inside of Visual Studio Code, now I'm going to roll this break point. So inside of Visual Studio Code,
45:40
you can set break points and they're visual, just like they are inside of PowerShell ISE and this is where you start getting used to the intricacies of the debugger and it's great to do as a general activity just to try it, if you haven't done it, just to start getting a feel for how it works. So if I press function F9, or just, yeah, F9, that sets a break point.
46:03
And the same shortcut exists in PowerShell ISE, it's just F9. And you see the little red dot show up there on the left-hand side of line 19. If I take this file and now I use F5 to run it, it stops on the break point.
46:21
And now I'm in the debugger. And this is that thing I think that you should try if you haven't tried it. How many people here have used the debugger, stepping through code, looking at const text? Okay, great, lots of people, okay. So for those of you who haven't, it is either the people who, yeah, who actually haven't, not the people who didn't lift their hand and actually have.
46:40
Knowing how to use the debugger is critical to figuring out what's going on. So you can set break points. Now that was just a hard break point, no matter what happens, I want to stop on that line. And in the debugger, so going down to the bottom here, you can do a lot of things. You can look at variables. So I can check the value of $x and it's not set yet because I haven't run that line. When you hit a break point,
47:00
it stops before the execution of the line, not after. So $x equals one, x has not been set yet. But if there were things I wanted to look at, I can inspect. You know you're in the debugger when you see DBG on the left of your prompt. So you're in a debugger prompt.
47:21
And the skills I'm going to show here apply broadly no matter where you're working with the debugger. So one of the key things to know that you can do in the debugger is you can run the h command. So the debugger has a set of commands that are really, really helpful for doing debugging at the command line,
47:42
which you might think, well, I don't need to because I'm using PowerShell ISE or because I'm using Visual Studio Code doing visual debugging. Visual debugging is great where you see line by line and you can use shortcuts like F10 and so on. But if you want to get beyond that, if you're debugging in a remote process, in a remote run space, if you're debugging inside of something
48:00
like Azure Cloud Shell where you don't have this visual environment, how do you debug? Well, you can set breakpoints and you can control the debugger using all these commands that show up. So step into, step over, step out. That's about telling the debugger to advance a certain way once you're on a certain line.
48:21
Continue, that's what you would use if you're, let's say you're debugging and you think, okay, I'm fine here, I want to keep on going to the next breakpoint. Continue, that's a free run until you're either done or you hit another breakpoint. Quit is in the case where you ran something, it's got a whole lot of errors, you start setting some breakpoints, you come in, you start figuring things out,
48:42
you want to go and fix those and restart. Well, quit says stop debugging, don't continue execution, don't run the rest of the script and then you can go and make some changes and then rerun it and get back in again. So I'll use quit a fair amount once I actually find something and I want to go fix it and then come back in. Detach is about when you do remote attaching
49:01
to the debugger, which you do for remote run spaces and for executing debuggers against PowerShell running in some other process, which is really cool. And I'll just call it out and I'll show you that, but you can actually have PowerShell being invoked by .NET inside of an executable program and you can actually have a breakpoint set in there
49:23
and hit that breakpoint and debug it from a remote process using command line tools. So getting to know these is pretty cool. K is for call stack. So I talked about inside of dollar sign error, the scripts call stack and then in the exception, the exceptions call stack. I can get the script call stack just by running K.
49:43
Whoops, why did I put it way up there? Oh, I know why, it's because I scrolled up and that's the thing with Visual Studio Code, hang on. So K gives me that call stack to show me what happened to get to this point from the beginning of this invocation.
50:01
Where did I start, what line numbers, what files, what commands were run and so that's about getting that detail while you're debugging. List is also really useful, especially in the case where you don't have a visual debugger because here I've got the file, right? And so I can come up here and I can see,
50:21
if I scroll down a bit, I can see where I am. But there's cases where you don't have a visual debugger if you're using just PowerShell.exe for example or Azure Cloud Shell or whatever and you can use L and you can see where you're at. So line 19 has a little asterisk next to it because that's where I'm currently sitting in the debugger
50:42
and I haven't yet run that line. So that's really really useful to figure out where you are and it also has an optional number that you can throw at the end of it. By default it shows a certain amount, I forget how many but you see it showing here lines 14 to 29. If I want to see the full file, let me just see if I remember the syntax.
51:01
Oh, that's right, starting line, ending line. So starting line zero and let's show 100 lines. Starting line, oh, line one, there. So it's one based for the starting line. If you're a developer and you're working with collections you think zero based, it's one based.
51:22
So yeah, from line one up until 100, in this case there's not 100, so I can see a broader context and I still get on line 19 the asterisk showing me where I am. And, oh yeah, enter is really useful for fast debugging for the command line
51:41
because if the last command you took was step and you're stepping through a whole lot of things, you don't, let's say you're using step over, you don't have to keep doing v enter v enter, you can just do v, hit enter to step once and then enter enter enter enter enter to step a whole bunch more times. So it's just a little faster convenience. And then question mark or h gives you this help message.
52:01
Now, how many people feel like they have a good understanding of step into, step over and step out? Okay, so even seasoned developers generally, oftentimes they're just gonna use the same one over and over again just because it's out of habit and not having to think about it.
52:21
The difference between the three is really useful depending on what you're doing and you need to know it because if you're controlling the debugger there's cases where you don't want to debug into stuff and other cases where you do. So step into is what you would use if your debugger is sitting on a breakpoint that's calling into a function or a script and you want to go inside that and step line by line inside the content of that guy.
52:41
So step into says take my current command and if I can, if there's code behind it, step in and then I can continue to step along and go through. Does that make sense? Yeah. And if you can't step into it, then step into works just like step over. So if you just want to step through everything,
53:01
step into because it's going to go in when it can, come out when it's done and it's going to hit every line and leave you in the debugger, yes. Step over is when you're on a line that calls into some subroutine, some function, some script and you know you don't want to go into it because it's code that you consider to be working and you just want to continue working
53:20
in your current file that you're looking at. So that's where you would use step over which is not skipping anything. All the code is still run inside of whatever it's being called but your debugger is just saying I'm not going to bother going in there. I'll put you on the next consecutive line in the current file, right? And then step out is for when you step into something
53:42
because you're thinking, okay, I'm not sure what's going on here. I'll step into this function, step, step, step, look at some variables. Oh no, this is fine, let me get out even though there's still 30 more lines here to go. Step out. That says run the next 30 lines and put my debugger on the first line outside of this call that would have been invoked next.
54:05
Yes. Yeah, exactly, yeah. Sometimes you step into and you think, oh shoot, I didn't mean to do that. Step out. Other times you debug a little bit and then you think, okay, I've gone far enough. I want to continue debugging one level up and so you can step out. So understanding those and working through how they work is really, really helpful.
54:21
Yes. Yes. Yeah, always goes up one level. Yeah, so step out just says I'm inside of something. I want to put the debugger one level higher if I can.
54:42
If I can't because I'm at the top level, it'll just run to the end. Yeah, if you're several levels deep, you might have to step out several levels to get back to where you want to be. Or you can just go and set a breakpoint at that higher position where you want to be and then say continue and it'll stop at that next breakpoint. So that's another thing that people do.
55:01
Turning breakpoints on and off while you're debugging is a normal thing. So showing some of that. Oh, so there is a command called set-ps breakpoint and it's just a native PowerShell command. Comes with PowerShell, works on PowerShell Core, PowerShell Windows, or Windows PowerShell.
55:21
And so you just run set-ps breakpoint and there's three different types of breakpoints that you can set. There's the line breakpoint. This is called a line breakpoint because it's telling the debugger I want to break as soon as you hit this line no matter what. You can do conditional line breakpoints where, and I'll get to that, where you can stop on a line, actually you can do conditional any breakpoints
55:40
based on stopping only when a certain condition is met. The three core types are line breakpoints, command breakpoints, and variable breakpoints. And you can set all three of those using set-ps breakpoint. So if I took this file, loaded it up into Azure Cloud Shell, I want to debug it, and I have the file local, right?
56:01
And I can see that there's line 19 and that's where I want to start my debugging. I can use set-ps breakpoint and give it the name of the file and line 19 and then run it and it'll hit that breakpoint. Other questions? Okay, so I'm just gonna step through a few things here. And so, and I have to refresh my memory
56:27
for these shortcuts for step into, over, and out one hundred times if it's been a while since I used them. And so on line x equals one, if I run s to step into, there's nothing to step into, so it works like step over.
56:40
And then on this one here where I invoke b, oh and of course now I can check the variable of x and see what it's set to. And then I can go in, so step into, and now I'm inside of b. And if I hit enter, that's interesting. That must be a bug in how this works inside of,
57:01
yeah, code. Because inside of PowerShell ISE, you hit enter and it just reruns the last command. So I'll have to log that one. At any rate, so I'm going to now use v step over, but I'm still inside my function so it's gonna stay there. So you start at the function where it's invoked, then you go inside, and so I can use v, step over,
57:22
and on c, if I was debugging and I didn't want to go in and I use v, let me just show you that actually, it puts me down at the bottom of this catch block, and the reason why it did that is because I told it don't step into c, just run over it, but c had an error where it threw an exception,
57:41
and that exception actually went into the catch block, but there's no lines inside my catch block, and so the debugger puts me at the line after the catch block. If I had code inside my catch block, it would've put me there because that's where the exception would've been caught. But it puts me after because I told it to step over the command that actually was hitting the error.
58:02
So as I'm debugging this sort of thing, now I can just run c, say okay, I missed it, so I've gotta go back. I still have my break point set, so now let's do f5 again, and now I'm going to step in to b, and into c, and now if I'm doing line by line
58:23
and trying to figure out, okay, that's working, great, the right host, that works, and then I try to run this here, and boom, it jumps, and so that's where an exception is thrown, when you get a jump like that unless it's going into another file and bringing you into another file, because you can do that. When it just throws you back up the stack,
58:41
that's the point where the exception happens, and so then I could say, okay, well, that's great, so I found my source of my problem, quit, so now let me remove this break point here, go up to that guy, save myself some time, and now run it, and I go right to the source where my issue was.
59:02
So when you're diagnosing this, it's a lot of in and out of the debugger, and then I get to my issue, and then I can inspect that line. In this case, I'm passing in a null value into an API that does not accept null, and so I'd have to fix that and move on, and turn that break point off.
59:23
Yeah, and you can turn your break points on and off while you're debugging too, so you can just, inside the debugger, I can just use F9 wherever I want to set them. Line break points are the one you're gonna use most commonly, but there are other ones that are useful too, like command break points, so let me show you that.
59:53
I'm just gonna go here in the sidebar. So yeah, when you're doing break points,
01:00:01
You can use F9 or you can come over to the side bar, put your cursor there where you see it, shows the little red dot when you're hovering over there and right click and that's where you can add a breakpoint or you can add a conditional one. If you do add breakpoint, that's just a line breakpoint and you can make it conditional and I should talk
01:00:20
to that too just to show you. So actually I'm going to cover that after so I'll get back to that one. You cannot use the visual debugger to set breakpoints at this point on variables and nor can you do four commands. That's where you go to set PS breakpoint which I believe I've got in my next file.
01:00:45
No, not my next one but I will get to it. So I'm going to come back to the question about setting breakpoints when you don't have the visual. Anyway, so this file here, all this is doing is a loop. The internal content is not that important. This is just a loop. Sometimes you've got something and it's running
01:01:01
and it's taking a heck of a long time and you're wondering what's going on and you've got access to the system where it's running in that PowerShell session and inside of Visual Studio Code maybe you ran something and you're like what's going on? And so if I run this, so it's running, it's just doing a lot of work, it's got a delay, whatever, it's been sitting here for a while, I want to figure out what's going on, I can press F6
01:01:23
in Visual Studio Code to tell PowerShell stop at a dynamic breakpoint the next time you can. Or inside of Visual Studio, sorry, inside of PowerShell ISE, I can use control B for the same thing. It's basically you're saying break into the debugger, right at the current location where you're at.
01:01:42
So the reason why this is almost always going to break on while true is because lines 9 through 18 run in the blink of an eye and line 20 takes a while and so by the time I do it, it trips up there. But you could hit a breakpoint in any location. It just says give me the debugger, I want to look around.
01:02:01
And so once you're in here, of course, then H gives you everything, all the help, L shows you your current location, you can see where you are in the call stack, if you're on a system where you don't have the visual, if you're on visual, it shows you which is nice and then you have the debugging capabilities and all of those skills step into, step over, step out, continue, quit, all that stuff applies.
01:02:24
Now, let me just, so another way you can enter the debugger is using wait debugger.
01:02:40
This is a trick that you would use if you were trying to debug a remote process, maybe a background job, maybe it's something in another run space, maybe it's code running inside of a PowerShell executable. You can use wait debugger to tell PowerShell to enter at a certain point. And so if you look at this script, it's copied
01:03:01
from the last one just with this one thing added right here, line 17 to 19. If the variable I, which I also added, sorry, so it's adding this variable I to count the iterations and once I becomes greater than or equal to five, it's going to wait for the debugger to connect to it. So if I run this, curious, so it's going to go
01:03:29
through a few iterations and now it hits a break point. And note, the break point it hit, it doesn't exist. It puts, wait debugger tells PowerShell stop what you're
01:03:43
doing, wait for a debugger to attach to it. In this case, I'm inside of a product Visual Studio Code that has a debugger, so it attaches right away. If it was a background job or a process in a run space, it just sits there idle waiting for somebody to connect to it so I can actually hit a break point, so I can actually start debugging it.
01:04:00
And the line it puts it on is the next line after wait debugger and that's because wait debugger itself is a command. Remember I said when you hit a break point, that command has not been run yet? So it can't put the break point itself on wait debugger, it puts it on the line after it because wait debugger already ran at that point. And then the debugger attaches and now I've got all of the things I can do.
01:04:21
And so the way I can do a conditional break point here for wait debugger is by using an if statement, right, so I can throw in some temporary code and do that sort of thing. Or another way I can do this, if I quit out of this debugger. So I've got this module called debug px and it's open source and it now works
01:04:48
as of this morning when I publish the update to it for on PowerShell core on Linux. Actually I pushed an update to a module it's dependent on, but at any rate it now works properly. This one is doing that exact same piece of code,
01:05:02
it's just a while loop that's doing a lot of stuff, but you see there's this break point command. This works on PowerShell version 5, 4 and 3. Wait debugger was added in PowerShell version 5. If you're using older versions of PowerShell, you might not have the wait debugger command, you can use debug px to give you something very similar.
01:05:22
It was kind of funny, it was Paul Higginbotham from the PowerShell team was actually working on wait debuggers at the same time that I was working on enter debugger, which is what the break point alias calls. And so if I run this, and Visual Studio code still being a little bit uncooperative, so I really want to run it.
01:05:45
So when it hits break point, it stops dead and actually hits it on the break point line itself, and that's through a bit of a creative work that I did, which is really a hack, where internally break point calls break point, and so when you call break point,
01:06:03
it sets a break point on the break point command and then calls break point and stops. So anyway, I just like the experience better, so I threw that in. So this is really cool because I can hit a break point at the line where I had it,
01:06:20
and then I can continue debugging. And you can also do it conditional, which is something you can't do with wait debugger. So let me just peek ahead. Yeah. So I'm going to quit the debugger here again. And by the way, you guys can just install, use install this module debug px if you want to try this piece out.
01:06:43
Yes, yep, that's coming up. Two more files before I get to it. So this is just a function called debug this. The difference here is two things. If debug, so lines 20 to 23, and break point, that's the break point command I showed you,
01:07:01
with a script block. That script block is the condition on which I actually want to stop on that break point. One of the things I like about break pointing this way is because I mentioned you can use set dash ps break point as a command. I should show that now just before I get too far down the rabbit hole on some of this stuff.
01:07:20
So if you get command, oh, I love visual studio code, but it's quirky. So if you get command, set dash ps break point, dash syntax. So there's three different syntaxes for it.
01:07:43
Dash script is the script that you actually want to have your break point in. So the top line is your line break point where you specify the script file, and then the line number. And you can put multiple lines if you want to set multiple break points at once. And you can specify columns if you're dealing with pipelining and so on. Action is a script block.
01:08:01
That's your condition. So if that action returns true, well, sorry, no. If inside of that script block you have the break keyword, then it'll break. If you don't, then it won't. So for me to do what I did here, where I did break point
01:08:21
and then a script block, I would have to do set dash ps break point dash script. I'm just going to cheat here, and that's my script file. And then line 25, action, and then curly braces. And inside of here, if $i is greater than or equal to 1,
01:08:49
then I want to, and the curly brace, break. And then close that curly brace. So that command that I just typed in,
01:09:00
set ps break point with my script file, the line number, and the action, that's how I could make a conditional line break point in this particular file. And the key part about the conditional thing here is I have to do that actual if syntax to make it work out versus this way I find it much easier. So I'll just modify my files.
01:09:21
So if I have a file that I'm going to run on Azure Cloud Shell and it's not working properly and I don't want to deal with set ps break point complexity, then I might just use my break point command to make sure Azure Cloud Shell has my debug px module loaded and away I go. That's personal preference, but you can use that ps break point, that's fine too.
01:09:40
Now the other thing here is this if debug section. How many people have run a command with dash debug? Still a good number. Okay. So one of the quirks about dash debug, how many people use that regularly? Okay. So one of the things about dash debug, dash debug comes from PowerShell version one, which is 10 years old now.
01:10:01
And they didn't have a debugger at the time. And so they added this dash debug common parameter so that when you run a command, I should do a time check, okay, so when you run a command, it will ask you on a line where there's some debug input if you want to, you know,
01:10:23
like a call to write debug, if you want to continue running or suspend so you can do some debugging. And so it's really a PowerShell version one debugger feature and it's never evolved since, which is a shame. And one of the things I don't like about it is inside of my scripts, I like using write verbose and write debug
01:10:42
to show different levels of information. Sometimes I don't want to see everything, but I want to see more than I get by default, so I'll use write verbose for that stuff. Other times I really want to go deep and see a lot of extra stuff, I might use write debug. Or maybe I'm working with a customer and the script's acting really weird and so I'll send him a debug version of the script,
01:11:01
which is just a script with a bunch of write debug calls. But then they run it, I say, okay, run it with dash debug. And then they get these prompts and they have to understand PowerShell and how that stuff works when I just want to gather debug information. And so I wrote debug px to have this if debug command, which is also an alias.
01:11:21
So if I am, so these two guys are just aliases. So breakpoint is an alias for enter dash debugger and if debug is an alias for invoke dash if debug, which is unfortunate, I couldn't come up with a better name, but anyway, it's nice inside of scripts just to use the alias.
01:11:41
This makes it so that anything that is output inside of if debug in lines, so lines 21 and 22, anything that's output from that will be output as debug, to the debug stream without stopping to ask me do I want to stop for a breakpoint because if I want to stop for a breakpoint, PowerShell version 2 plus, I'm going to use breakpoints.
01:12:02
I don't want to be prompted. So this is my workaround for being able to run a command with dash debug without being nagged because I'm calling write debug. I don't even have to call write debug. I just push output, whatever falls out of this if debug script block automatically gets output to the debug stream and keeps on going.
01:12:21
So I can throw in debug information. Actually, no, I do call write debug, sorry. Yeah. So, but that's interesting. I could make it work so it works the other way. But anyway, that's a side. So I do call write debug. But whatever I write to debug here, it's not going to stop.
01:12:41
Because the reason dash debug makes you stop and ask is because when you do dash debug, it's equivalent to doing what would be dash debug preference inquire, meaning ask the guy what do you want to do when I'm going to call write debug. I mean, if you ever ran a command with dash error action inquire, when it gets an error,
01:13:03
it's going to say what do you want to do? And it actually prompts you. So this is just my way of making it easier to have multiple levels of output, whether it's write verbose, write debug, or the basic output, and then have that just work. Questions? Okay. Let me get out of debug px here.
01:13:32
There we go. So, yeah, so I'm just going to do some more, actually,
01:13:40
one more thing for debug px before I get out of it. So I'm going to create a test module here, debug test, and import it. Now, if I look at this module from the outside,
01:14:01
I've got one command, invoke dash script block, but internally, it's got this other piece that wasn't exported called set dash internal stuff. And so I only see the one that was exported to me on the outside, right? Same as if you guys downloaded a module from the community, you're only going to see what was exported unless you dig into it.
01:14:21
If I look at the variables, there is no variable called hidden secret counter because it was not exported, yet inside of my module, I do have that hidden secret counter. So I've got, sometimes you have a module that has state, you're storing information, whether it's your connection information or something about the user name or whatever, something that's used inside that module and you're storing state, but you don't export
01:14:41
that because it's all internals. So my point here is just to show you that, yeah, you can have some internal stuff that's not exported. But what if you want to look at that internal stuff when you're running your commands? You can run debug dash module with your module name, and so what that does is that enters the debugger in the module scope.
01:15:01
So I've got my module called debug test, and it says I've hit a break point on enter debugger, which is my break point command, but where am I? I am at the top level scope of the module itself, so I can look around. That's all that I'm doing. So if I do list, I can see, this is a little bit confusing
01:15:23
about this piece because this is just something that I've added. It shows me that I invoked my module, so I wanted to invoke a command inside my module. I don't know if you guys know this, but you can actually, if a module has an internal command, you can actually invoke that directly by using dot,
01:15:43
as if you're going to dot source, the module object itself inside of brackets, and then the command in the module that you want to invoke. So that's a trick if you're trying to do some internal diagnosis and debugging from outside of a module. In this case, I'm saying, okay, dot, in my module scope,
01:16:02
I want to enter the debugger, and so that's what I've done. And so now that I'm in my debugger, I can actually get the value of my hidden secret counter because I'm inside of the top level scope, and it's the right scope too. It's scope zero. So I'm at the top level because there's stacks
01:16:21
when you're calling stuff, and so it's actually put me in the debugger at the bottom level. And so that's just something I use because I've got modules that are storing internal information, and I want to see what that is at a certain point in time. Maybe I invoke a few commands, and then something's not working, and as part of my troubleshooting, I can look at code, but another part
01:16:40
of my troubleshooting is to be checking the state of the module, and this allows me to do it, just debug-module, get me in the scope, and then I can start looking around. And then of course I can just detach the debugger to get me, and this is where the detach command comes in. Oh, that's interesting. That's a Visual Studio Code or PowerShell core thing because on ISE it's fine.
01:17:03
That's interesting. I'm going to probably have to restart PowerShell ISE because of that, or PowerShell Visual Studio Code.
01:17:20
Oh yeah, there we go. Thank you. That's really cool. Good tip, thank you. So, which is funny because, so when I was preparing
01:17:40
for this, one of the things that I was debating on, do I just do this in ISE or do I do this in Visual Studio Code, and I had seen people tweet about debugging in Visual Studio Code that certain tweets that made me think I should probably just stick with ISE, but at any rate, I thought, no, I'm just going to, this is debugging anyway, so why not.
01:18:01
That's right. So, got my module imported again. Now, so I detach the debugger. Now I can set a breakpoint. So this is another thing, too, when you're dealing with commands and you've got internal commands. This is one case where I would use set PS breakpoint a lot,
01:18:22
line 67, because you don't have to think about the script file. You just want to tell the debugger that the moment that something is called, stop. And so if it's an internal one, that's fine. It's still going to stop. It doesn't have to see it from the outside world. You're just telling the debugger, watch for the invocation of, in this case, set internal stuff.
01:18:41
And so, which is really useful. So if I do run that command, now I've got a breakpoint. And by the way, there's also get-ps breakpoint. So if you want to see what's there, what you have for breakpoints, you can check and see. And you can tell what type they are based on the columns.
01:19:00
So a line breakpoint would show me the line number here. Command breakpoint shows me this information. A variable breakpoint shows me this. So when you do get-ps breakpoint, you might see blanks, depending on what type of breakpoint you're looking at. That allows you to inspect and see what they are. And there's, of course, remove-ps breakpoint to take it out. And so notice that by me doing set-ps breakpoint
01:19:23
for the command, there's nothing, there's no visual cue because, well, right now, there's nothing inside of Visual Studio Code to recognize and show that I have a breakpoint on set-internal stuff, which would happen everywhere that it's invoked. So it's an invisible breakpoint. And now that I've done that,
01:19:45
now I can run my external guy that I exported. Oh, yes, sorry, one more thing.
01:20:03
So there's a reason why it didn't stop at the debugger here. So my intent is to tell the debugger stop on set-internal stuff. And then I want to run this command inside of my script block, and maybe I want to debug it
01:20:20
because I'm the guy who wrote it. But in this case, by command, this is actually a good example because in this case, the command takes a script block and it's going to do some stuff. If you're debugging your code, I don't want you debugging my code. I want to give you code, a module that you can work in as a black box, going more with the commandlet experience, right, where you don't get
01:20:41
to see the internals unless it's open source and you actually want to see that stuff. So what would happen if maybe you want to put your command breakpoint on start service? And inside of my code, I happen to be calling start service. And so then you've got a command breakpoint
01:21:00
that will stop anywhere that start service is invoked, including the internal stuff that I meant for you guys to have as a black box. How do I deal with that? And so you can actually tell the debugger to ignore stuff, which not many people do, and it's fine if you don't.
01:21:22
It's something that I like to do, again, because of trying to give people the black box experience. And so right here, system.diagnostics.debugger step through. That tells the PowerShell debugger,
01:21:41
whether it's PowerShell Core or Windows PowerShell, same thing, that tells them that the code internal to this particular function steps through it. If I invoke something else, that's fair game. But inside this guy, steps through it.
01:22:00
So I'm invoking at $scriptblock on line 38, right? So I'm invoking the script block that's passed into me. That would be fair game for the debugger. But the internal stuff that I wrote as being a black box and I don't want you to hit, I can control that by using that system.diagnostics.debugger step through.
01:22:21
Yes. Yes, it is. The reason why, so the question was, is that different from setting debug preference? This is a attribute set on this function that basically just turns off debugging of the function internal so that I cannot put breakpoints
01:22:41
in here, I won't trip over breakpoints and so on. I use this before I ship something. After I've gone through and I've tested it and I've polished it and I make sure it works, then I shut it down for the main reason that I'm trying to be respectful of people who are using my stuff so that they don't hit command breakpoints somewhere internal.
01:23:01
I want them to go to leverage the debugger and all the power the debugger has without getting into my things, without having to go into C sharp, because if I wrote it in C sharp, you know, compile commandlets, that's not going to be hit. So I try to be respectful of people who are calling my code in a couple ways. One, what I showed earlier, about the errors and how that shows what was invoked versus what's being
01:23:21
done internally. This is another way that I do it, about basically controlling the debugger. And there's two different things you can do. There's debugger step through and drawing a blank right now, do I have the other one in here? Yeah, so if I, debugger hidden, that's the other one.
01:23:47
Right, so there's two different ways you can do it. Debugger step through, I will use if I'm invoking other stuff, but I just don't want you to see what I have internal to mine. Debugger hidden, I will use if the only things I'm invoking are my stuff in my own module, and I'm basically saying
01:24:00
it's a black box, don't come in, you don't need to debug this, unless you really want to maybe step in and debug it, or you can turn stuff off and really get into it if you need to. But, generally speaking, you don't want to. There was another question over here? Oh.
01:24:23
No, no, this is not your view, this tells the debugger, don't pay attention to me. And so the debugger, this is something that even comes from .net and C sharp. You're just telling the debugger how you want it to behave, how you want it to look at the codes internally, there's nothing of precedence that's going to override this a certain way, you actually have it on or off.
01:24:46
Or, yes, or, so the question was, if you did set this and then you want to actually step in and be able
01:25:02
to break points and work with this stuff, and you maybe want to debug the internals of this, how would you do that? Do you manually remove line number 28? Is that what you do? That's one way. But another thing that you can do is set command debug mode,
01:25:21
get in set command debug mode. These commands allow you to take an entire module or a specific function and control that turning it on or off. Because the reason why I can turn it on or off is because it's based about, it's about what's in memory. If I take my function and I load that in the memory
01:25:41
by just running line 26 to the end of the function, then PowerShell has it in memory. At that point, I can use set command debug mode on the function itself to turn on or off the behavior of those system.diagnostics attributes. Make sense?
01:26:02
Okay. So, I told you this is about, you know, becoming a debugging ninja. There's a lot here, a lot of these things are just stuff you might not use, some things you might come through later on, depending on whether or not you're sharing code. I just like to show all of it and let people see what they can do with it.
01:26:23
Where was I? Oh yeah. So, since I'm using that step, debugger step through and not debugger hidden, note that I can still do this. So, I can still take line 73 up to 76 here and run it.
01:26:43
And I hit a break point. And the break point I hit is inside of my script block. And so, I can still debug, you know, let's say I'm running a function and it's going to take a script block and people are going to do something with that script block and I want them to be able to put on line two here, whatever in their script.
01:27:01
I want them to be able to hit F9 to set a break point and then run and hit that break point. They can still do it even though my internal piece is hiding the stuff internal to it just because I used that debugger step through and not debugger hidden.
01:27:22
Great question. So, stepping out is O and so let's do that. Now, out shows me out of my script block and now let's go out again.
01:27:41
And now, I'm actually inside of the stuff that's in. So, you can still manually step in. It's not blocking it all together. This is about automatic break pointing, right? So, these two properties, thank you for asking that question. These two attributes, the debugger hidden or the debugger step through are about automatic break point, whether it's a command break point
01:28:01
or a variable break point, those things are going to be ignored and a line break point would even be ignored, but I can still put my break point on the command I'm going to invoke and step into it or I can still, excuse me, step out of it. Excuse me, talking too much.
01:28:20
I can still step out of it if I've hit that break point inside of a, in which case, I would have to do multiple step outs to get back to where I wanted to go or set a break point at a higher level.
01:28:43
Oh, do you mean actually change the prompt, the PowerShell prompt itself? Yeah, and that's a good point. I'm surprised that this one does not, well, actually, no, that's for, that's when you do enter nested prompt, right, so there's host dot enter nested prompt
01:29:00
in PowerShell ISE and at that point, it'll show you a double angle bracket and then you can do another double angle bracket, but for the debugger itself, I don't think it keeps on doing more and more because they're only in one debugger, you're just in the debugger. Unless I'm mistaken, okay. Because I know back in PowerShell version one, I used to do host dot enter nested prompt sometimes
01:29:20
because I didn't have break points and that will cause PowerShell, that'll tell PowerShell, okay, stop, create a nested prompt, it'll do a double angle bracket and then I can look at variables from a higher scope and poke around and yeah. But I don't, I haven't seen that with the debugger itself. I mean, you can do it because there's a prompt function and you could actually make it work that way where you can set the prompt differently. The way they indicate the debugger here though is just
01:29:41
by putting debug colon on the left rather than doing the double angle. Yeah, one thing I've toyed around with too is when I'm debugging, having the prompt show me things like some kind of a call stack queue or line number or whatever above my prompt. I haven't gotten that part yet, but you can do prompt customization and so that's the things I think about.
01:30:03
And so, yeah, so I'm on a break point here and so I'm just going to quit to go back out again and clean up myself after I'm done. Other questions? Great questions by the way.
01:30:23
Yes, there is a variable for break points. So let me just, one thing I like about my debug px module is I can even do break points on files that are not saved at the command line just by typing in break point. If I just want to tinker with the debugger,
01:30:41
I can just type in break point and it puts them on a break point. And so if I do, oh, there it is, ps debug context. That's right.
01:31:00
So yeah, ps debug context is useful because, and thank you for calling that out, it includes the details about the current break point I'm on as well as invocation info about the current line that got me there to that break point. So when you hit a break point and you want to see the invocation info details
01:31:21
for that particular line or the break point itself, you can actually inspect the break point object. And I think that that's the only two properties. I'm just going to do a formatless star on that guy and I don't know if it's going to do a ask me or not.
01:31:41
No, that's it. So those are the only two things. So yeah, if I go into the break point there, I can take a look at the details of that particular break point that I hit and of course, I'm going to debug her and I can quit to exit. Thank you for calling that one out. I didn't have that one in this talk, but it's worthwhile knowing it's there. I actually haven't used that one that much. I'm curious if you guys do use that
01:32:01
and find that really useful. What scenarios you find that useful? I'd love to hear that, but personally I haven't used that a whole lot. Now, jobs. So I'm just going to create a few jobs.
01:32:24
So this is just taking, you know those scripts that I had earlier, I showed you two versions. One version that just ran into a loop and I manually did the function F6 or control break if I'm an ISE to actually hit a break point. And then the other one used wait debugger.
01:32:40
Those two scripts I just ran as a job. And so now I've got this collection of jobs and if I look at it, so you see this one here is running because this is just an endless loop with a two-second pause where it goes, gets some information, waits two seconds, gets it again and so on and it'll run forever.
01:33:01
And this one here, it shows us that a break point and that's because of the wait-debugger command. So this is really useful. That's where wait-debugger really shines when you have something that you want to modify that you're running outside of the scope or the context of your current PowerShell session and you want to debug it, a background job is a great example,
01:33:22
remote run space or a remote process, those are the examples, wait-debugger is great for that. So now that I've got my jobs, now the first job is running rampant, right? Job zero of those two and so if I run this, debug-job,
01:33:43
oops, shoot, fun fact, on a Mac, F8 on my Mac keyboard opens iTunes and I have to do function F8 to run the actual line.
01:34:01
So running debug-job with a job object tells PowerShell, okay, I want to debug this guy. Now this was job zero. Job zero is running wild. It's effectively hitting F6 on the job or Ctrl-B if you're using PowerShell ISE. You're just telling, you've got this job running, it's taking a long time, what's going on?
01:34:22
Debug-job tells PowerShell the next chance that you can possibly stop on the breakpoint using the debugger, do it. Not a breakpoint but just enter the debugger. The next point you can enter a debugger do it and so I did and so it says entering the run space on local machine Kirk's Macbook Pro and you see I'm in the debugger and then you see job two.
01:34:42
And so the reason why it's job two and not job one or job three is because these are parent jobs and the way jobs work is there's like a parent and a child and the child's actually doing the work and so job two is a child inside of here and you can see that by looking at job objects. You can actually see relationships and the children. So that's why this shows job two.
01:35:00
And so I mean I usually just look at the number and find the next highest guy of my jobs that are in the list and I know which one I'm on based on children and relationships. But now I'm in the debugger and if I use L and this is where L really shines I can see this is from the external file that I had that I showed you earlier
01:35:21
where there's a while loop and then a whole lot of stuff and the debugger stopped on while true because of my time delay. And now I've got the full debugger. I can check variables, step through, step in, step out, step over, all of that stuff while working instead of a background job. Anybody actually done debugging in jobs?
01:35:43
Okay. So this is actually really, really useful and one of the reasons why this is useful is because of what PowerShell Core is looking at going forward about how they want to be able to make it easier for you to run anything as a job to give you some kind of a threading capability. And anyway this is going to really help for that purpose.
01:36:05
And so then once you're in the job and you want to detach from it, this is where that detach command comes in. So if I go back to the list of commands, I talked about detach saying, you know, talk about it later, that's detaching the debugger. That's where your debugger is attached to another process
01:36:23
and it's debugging that process or another background run space. And so I do D and hopefully the code will cooperate and so it says leaving the debug run space. And this might be a case where ISE shines.
01:36:50
Yeah. So appropriate command. So I've, yeah, so this is the detach issue that I hit earlier.
01:37:01
I'm hitting it here again. Something's going on with that. That's something for one of us to look at and try to figure out whether there's a PowerShell team and figure out what's going on. So I'm going to go back and do this again. And now I'm going to do, I'm going to rerun these jobs.
01:37:30
Let me show them again. So I've got the same jobs running as before. One of them is at a break point and it's waiting for the debugger.
01:37:40
And so for that one, if I do debug job, it will actually enter the break point at that wait debugger call or actually the line after it for that reason I talked about earlier. And so this is the case where the break point shows up on line 21, which is the next line after PowerShell was told. Wait for the debugger to attach to it
01:38:01
and I can debug from that point on. So wait debugger's great. Because the thing about the F6 is that it works great if you have sleeps and pauses and stuff going on. It doesn't work great if you've got code that's just running really fast and doing a lot of things. I've had mixed results with that. So wait debugger is really good when you're working with jobs and most often that's the approach that I will use is actually using wait debugger rather
01:38:25
than just running ramp it. But if it's running ramp it, you can still do the debug job and try to hook into it. You just might not be able to hook into it depending on what's going on behind the scenes. And I haven't put my finger on exactly what those cases are for why.
01:38:40
Now, I'm not going to detach this guy. Oh yeah, the double, yeah, so that double prompt happens. So that's because of this part. Yeah, so you've got two different pieces, right? So these prompts are letting you know about the two, well so in the debugger inside of a different PowerShell session or PowerShell run space
01:39:02
where this job is running. And so that's why that shows up. So I'm not going to do detach in this case. I'm going to try to quit the debugger instead and see if that gives me back and it does not. So that's fine.
01:39:24
That comes with trying these things on Mac. Or on PowerShell Core and seeing how they go. So the other thing, actually this is where I got to switch. So I've got another script here and this one is about attaching to a remote PowerShell host
01:39:41
and debugging run spaces which does not work on Windows, on PowerShell Core on Unix because there is no enter PS host process command. But on Windows PowerShell or PowerShell Core on Windows you can use enter PS host process. And so I'm just going to take a second to unplug here,
01:40:04
flip over to plan B. And so number eight, there we go.
01:40:26
So first thing I'm going to do is I'm just going to start a process. So this is just going to basically take one of those files that I was running earlier and a different flavor of it
01:40:41
because one that works on Windows using get Windows event and launch it inside of PowerShell.exe. And so if I run that, so now, and then I've got to wait for it. I just want to make sure it starts up properly. And so let me just run this.
01:41:00
Okay, so I've got my PowerShell process and now in this case, the script that I ran was the entering the debugger without breakpoints, the one I would have to hit F6 on. I can use enter PS host process to enter a process where PowerShell is running. And so note that the prompt changes.
01:41:22
So I've got the process with the process ID down in the corner here as my prompt. So now I'm in my host process but I'm not yet in the debugger because inside of a process, when you're dealing with PowerShell running in a process, PowerShell runs inside of run spaces. And so I've attached to this process but I have not yet gotten the run space.
01:41:41
So I can see there's two run spaces here. So remote host is always created when you enter your, and I put notes in here by the way. In these files, I've just got to load up into GitHub so you guys can see them. By the way, on GitHub, you can find me on GitHub under just slash Kirk Munro, M-U-N-R-O, no E.
01:42:01
And I haven't yet but after this, I will load up my scripts into debugging dash session so you can see what these script files are. Now, two things here. So there's remote host and there's run space one and you can see remote host is busy and run space one is available. And so the notes here identify
01:42:22
that the remote host is what's created when I enter. And the other run spaces that you see, there might be multiple because depending on the process you attach to, it may use multiple run spaces. Those are the run spaces where the PowerShell payloads are running that you want to connect to. And so you need to figure out which run space that you want
01:42:40
to connect to and oftentimes, there's one, unless it's doing something fancy with run spaces. And so you can use debug dash run space and that tells PowerShell to enter the debugger in a run space that's identified by run space one in this process and allow
01:43:00
me to start debugging and seeing what's going on. And the cool thing that this does is because this was running a file and I'm in ISE, it opens the file and gives me the visual debugging capability as well, which is really cool. I'm not sure the details behind entropy as host process and PowerShell core on Linux and whether or not that's going to come at some point. Right now it's not there, but this is really cool
01:43:21
for when you're dealing with PowerShell running on Windows and so I've got my full debugger and I can use, I didn't talk about these earlier, under the debug menu, step over, step into, step out, continue, all of that stuff. Those are available inside the menu in ISE or ISE of course supports the same command, so H to list all the commands and I can use V and step
01:43:45
over and go line by line and in this case I can hit enter and it continues because it doesn't have the same bug that's in Visual Studio code in the debugger. So I can debug this and step through and look at variables and figure out what's going on.
01:44:03
And then when I'm done, I can use D to detach, so that lets it continue running, I'm still attached to my process and then I can use exit dash ps host process to go back out of my host process back into the command line. So that's how detaching is supposed to work by the way.
01:44:21
So D is just supposed to tell the debugger to detach and come back up to one level. There's some challenges with Visual Studio code on Linux anyway and so when I'm done, I can then stop my process. Yes, yes, yeah, yeah, you would see anything
01:44:51
with the code would just generally output, sometimes you run a command and it sends something out to the command line that you weren't expecting or just you don't care about and you'll see that stuff show up as you step through line by line.
01:45:00
It's just like you're running your code locally but you're connecting to it or both, which is really cool. There's also debugging things that I don't have set up from this talk like there's debugging desired state configuration, there's debugging processes even on neural machines, I don't have all that stuff worked out yet in this talk but this was much more fun to do this time
01:45:22
where I have the two hours than trying to, imagine all this information inside of an hour time slot. So thanks everybody for attending. I just want to show you one thing on my slide deck,
01:45:44
which should still be here and that is, yeah, so these things I talked about, debug px is that module that I showed you and that's under github.com slash kirkmanro, that's where I will post debugging that session
01:46:01
as with the content from this session and then these are other modules that I work on. History px is a really fun one if you're trying to write optimal code and you want to see how long commands take history px can really help you figure out what's going on with stuff that you've already run and so that's the kind of thing I work on and my contact information, the only thing you really need
01:46:23
to know is at Pasha Holick, if you reach out to me through Twitter I can give you the information for anything else that you want as far as contacting me and thanks. No need to applaud again, that was great. I'll be around not a long time today, I actually have to leave early but I will be around for the next hour or so.
01:46:42
If you guys do have questions I'll probably just be hanging around outside there and we can chat about stuff and address it then.