Invoke-ChatOps: Level up and change your culture with chat and PowerShell
Olin, Brandon
Chat is not where you put cat gifs anymore. This talk will detail the social and technical benefits of adopting ChatOps in your organization using PoshBot, a PowerShell-based bot framework. Provide more value to your business and put your conversations to work using PowerShell.
 So afternoon everyone. My name is Brandon Olin and I'm in dev black ops on Twitter. And this session is really is about invoke chat ops level up and change your culture with chat and power shell. First off, does anyone do chat ops in their organization right now? Couple. Anyone know what it is but haven't done it yet? Who has no clue what this is? Okay. I think all of you will take something out of this. That's good. Here's some links to the slide on speaker deck and the code on GitHub that I'll go over today. The slides are really worth anything. The code is interesting though. This is the agenda that I'm going to go over. Basically what is chat ops? What is the specific problem set that this tries to solve? The benefits of working in this way? Some example frameworks out there and specifically the one that I'm going to be talking about because I wrote it in this power shell conference. Some examples, commands that you would probably do in a chat ops environment. And really the bulk of this is an overview of what posh bot is in a demo and hopefully some time for Q&A. But I've given this talk before with an hour and a half and that wasn't even enough time so I'm going to try to cram through it as much as I can in 45 minutes. All right. So let's get started. What is chat ops? This is a pretty succinct definition from James Freiman, formerly of GitHub. I think he's still a stack storm. And what this really is, we're taking the things we're already doing, all the work that everyone in here is doing, solving problems on systems and we're putting that in line with the conversations that we're having and in this case inside a chat window. We're putting those concepts together. This is another a little bit longer definition from Atlassian but basically it says the same thing. You're taking all these tools and all these conversations and notifications and putting them in a single interface in a single context. And I'll kind of go over some of the benefits of doing that. This is an example problem that, you know, the typical Brent problem that this chat ops is trying to solve. So imagine a fictional user named Bob. He has a problem and he calls the help desk or chats with someone on the help desk named Sally. He says something's wrong with this server. I don't know what's wrong. Can you look at it? Sally is a help desk person or some type of operations person and she doesn't know what that system is. Brent, our favorite person Brent does and maybe he can help with this. Two hours later, magic happens. The server is fixed. Bob is happy that his problem was resolved. Sally is happy that the problem went away and she can close the ticket. But there's all kinds of issues that this kind of highlights. I'm going to go over what these are. First off, is anyone named Brent in here? I'm sorry that everyone hates you now. Yeah. So what are some of the opportunities that this kind of highlights? What chat ops can help with this is it can improve the context. You notice there was a problem. Something happened. The fixed it. No one knows what that is. And then the person got notified that it was resolved. Sally never learned anything about that experience. Either that it Bob really. So Sally or Bob didn't gain any knowledge on how to fix this particular issue. And neither Sally or Bob were empowered to do this themselves and ideally Bob should be able to fix this problem himself. Giving either one of these people access to fix this problem themselves can reduce your meantime to resolution. And ultimately we want fewer Brents in the organization. Not the actual person. We like Brent. But he is overworked. He's critical to the team. If he gets hit by a bus, the world crashes. But we want to reduce the human bottleneck that Brent represents in all of our organizations. And we all are or we all have been Brent in our careers. Here's some of the other benefits that chat ops can bring. Like I said, knowledge sharing, empowering the team to fix their own problems. And that's both IT people and business people. It's really anyone in the organization. Situated with an awareness is everyone knows what's going on. Everyone knows the problem that's happening. It's all in one view. You can enable faster onboarding as people get into the organization. They have a good sense of how that organization works just by looking at the chat history of that group. Retrospectives or you know, blameless postmortems. You can by having all this stuff logged in history in a permanent history, you have a basically a flight recorder of an incident that you can go back to and look at what you did right or what you did wrong in that case. Technical benefits. Obviously, this is all driven by automation. Like I said, reducing the time to resolution. You have history and logging of everything you're doing here. And ultimately you can improve safety and increase security as well. Here are some example frameworks out there. Probably the grandfather of most of them is HuBot. These are all based on different languages. HuBot is written in JavaScript and Coffee Script, Airbot, Python, Collegalix, Ruby, Bot Framework. There wasn't one for PowerShell. So I created one called PoshBot and that's what I'm going to go over today. But really any of these will work for chat ops and all of them work really well for what they're designed to do. But ultimately if you want to implement this in your organization, pick something that you're familiar with that's native to how you work. Because there's really a bot probably in any language out there. Here's some example commands that you can probably think of a whole lot more that you probably write in a chat bot. You can restart services, you can get and resolve tickets, queries and APIs, modify AD or get AD information, create VMs or change infrastructure in some way, check processes, get some graphs or performance metrics to help you in troubleshooting, query systems, even deploy code and kick off pipelines, slap people with trout if you are old enough to get that reference. Really anything that you can do, PowerShell you can do in a bot. And that's really the point of this. So what I'm going to go over today is a bot frame that I created called PoshBot. It's nearly 100% class based, PowerShell class based. And if you saw my session on Tuesday, I kind of went over some of the gotchas with classes that I learned by writing this bot. Modules, PowerShell modules become chat ops commands in the bot and that's really what this gives you. If you can write a PowerShell module and you can write functions, you can execute them in a chat bot with really very little if any extra effort than that. It has a notion of role based access control. You obviously want to secure some of these commands from people. Not everyone should be able to execute everything. I'll go over some triggers and scheduled commands and some of the other functionality that the bot will give you that you may find interesting to enable certain scenarios. So this is parameter injection, stateful data, black list and white list for commands and channels. There's an asterisk under multiple chat networks and I know someone will ask me about teams and I'll give you the answer about why there's an asterisk there. But really this is written, since it's written in classes, you can extend classes and implement this framework on multiple chat backends. But primarily I use Slack and this is written and tested on Slack the most. So that's it really for the slides. Let's get into a demo. Does anyone have any questions? Is it really loud over there? Okay. So let's go off and start the bot. This is a simple script I have here to start the bot. We're going to import the module. We're going to import a configuration file which is really just a PowerShell object that has a lot of configuration lines on how the bot is going to behave. We're going to set some runtime specific configuration that I'll show you later in that middle section about plugging configuration and I'll show you how that works. We're going to create an instance of a chat backend that the bot is going to reference. In this case I'm going to give it a Slack API token that's how it's going to authenticate the Slack and make a connection. And then I'll create the bot and start it. And later on I'll also show you how you can write a very simple script to run this as a service. You can also run this in a container as well. I've tested that. So let's go ahead and start this. So you got all that verbose output. So we can see our bot here is now green. That green is good. So let's go actually bring it and invite him. So now that bot will be listening on this channel and receiving commands. All right. So let's run a command here. Let's see if it's up. Okay. Good. We have status. We can see our bot returned some output. So one of the most frequent things you're probably going to be running when you're doing chat ops in your organization is help. You're going to have lots of commands in here and you're not going to be sure exactly how they operate. So let's run a help command for get plug-in. There's a lot of building commands to PoshWat and they mostly have to deal with importing and managing modules or in this case I call them plug-ins and also some user management. Not a whole lot of chat ops goodness other than just getting the bot functional. Internally what this is doing is using get help on PowerShell functions and then consuming that and making it visible inside Slack. So let's actually look at the help for help. You can see you can get detailed or examples and that's really just a normal get help syntax. You can see you can get the normal help that you would expect from PowerShell. So what do we have installed right now? Just one built in. You can see there's a whole bunch of commands here. Like I said, mostly just to deal with plug-in management and user management. Let's go ahead and install a plug-in. When I say plug-in, this is just a PowerShell module. I call them plug-ins because you can add some extra metadata to them to make them operate differently inside the bot. But these modules, they're just modules and you can execute them from the command line like any other module. Let's go ahead and install one. Sorry, fine plug-in. What this is going to do is actually search the PowerShell gallery for modules that have PoshBot in the name or have a PoshBot tag. So any of these, you can just import right away. Most of these I created like Dilbert and Giffy and Tic-Tac-Toe and things, Wolfram, just fun stuff, just demo stuff really to get going. I was happy to see that someone created a VMware module out there that really just showcases the real benefit of using this. It's actually getting real work done. That plug-in will snapshot and remove snapshots from VMs right from Slack. Let's go ahead and install some of these. I already have these actually installed in my machine, but if I didn't, they would just get installed from the gallery like a normal plug-in or a normal module. Anyone know what name it is? You do? Do you use it? Yeah, I do. I like it. What name it is, it's a simple module out there that just generates random text for test data. So if you want to generate a whole bunch of addresses or people, you can use name it to generate stuff like that. I like to highlight it because it has nothing to do with PoshBot whatsoever. It just generates random strings, but you can import it into PoshBot and execute this stuff right from Slack. So let's try it. So it has a person command or a function. You can go and run that. You can see it executed the command and gave us the results. Internally, what PoshBot is doing is executing these commands in a job, sucking out the various verbose and output and error streams and giving you the results back in Slack. You'd also know if that command had failures and it will market as such. You can see this one had nothing in the output or the error stream, so it assumes that that command was successful. If anyone has any questions, you can speak up as well. Yeah? It started under my credentials. You can run it as a service, running under whatever user you want. The jobs will also run under whatever that user is. And I'll show you what the correct way probably is to run functions that would need credentials to go and do something else because you wouldn't want to run PoshBot as an elevated user. So I created a, oops, that's wrong. Give me back an error. Hi, Don. P.S. Summit. Okay. So here's a set of example commands that I've written to show you some of the various capabilities of the bot. So before I do that, I'm going to go over the concept of triggers. Triggers are how these commands get executed. Normally, in the most common way, it's going to be just normal command triggers. I say bang and a command name and I execute that command. And that's what I've been doing up to this point. This is also configurable. You can use a different character other than bang, but that's a common one. So let's execute this get hello world command. So you can see we get some power swap that's familiar to us. Mandatory parameter was not provided. That command didn't work. Marked it as failed. Let's actually look at that command. So there's absolutely nothing special about that function other than it requires a mandatory parameter and it returns some output. Sure. Here names based. I'll show you that. Good question. So let's satisfy the parameter. We'll get back a result. So that's the example of just a normal command trigger. And that's the most common. In particularly Slack and other chat networks as well, emit events when things are happening on the network that aren't people chatting in a window. People join and leave channels. Channels get created. Topics get changed. So you can trigger based on those events as well. So let's try changing the topic. That's going to emit event, an event that Popswad is going to see and execute a command. And we can see what this function would look like. And this is where you start adding Popswad specific metadata to these commands to make them operate differently. And the bulk of this is really this custom attribute that I created that you can tell, you can decorate your functions with and when Popswad imports these, it's going to treat these differently and trigger them differently. So here you can say it's not an actual command trigger that I'm going to execute. I want you to trigger on an event. And specifically the channel topic change event that the backend is going to receive from the chat network. And when that event gets happened, it's going to trigger this. This type of command, obviously you can't pass input to it because the user is not actually directly invoking this command. So just caveat there. Yeah. Can it grab information about the UV? Like can it see what the topic change is to? Yes. I'll show you that. So the second, that's probably the least common trigger is events because they're not really all that useful. Regex is going to be the second most common. You can trigger based on the command matching some arbitrary Regex string. So if someone just types some text in here, it's going to match that to a command. If it had some commands that were triggered on Regex. So let's look at what that does. So that was my cookies function. And again, I'm telling you, it's not a true command. It's going to trigger on Regex and specifically cookies. So you can put whatever Regex expressing you want in there and it will trigger on this. I don't know why this keeps scrolling to the top. So again, same thing. I'm going to trigger on ship it. Anytime I see ship it in the string, I'm going to pick a random squirrel and give him a squirrel. So in all I'm doing is doing a write output slack. We'll see that as just a URL that it got responded to and it will automatically unfurl it. So those aren't too useful unless you really like squirrels. So let's do a little bit more complex thing. Get multiple things. I didn't give it anything. It's just going to return with empty parameters that I received. Let's give it a little bit complex thing. Let's give it an array of strings and an integer. So you can see that the parameter thing one received three things. It automatically parsed that and recognized it was an array and thing two was an integer. So let's look at that function and see how that operates. There's nothing possible specific in there. All I'm doing is accepting two parameters to with collections and then returning their output. The PoshBot will parse that string that in similar to basically the AST. So anything you type in the command line or I say command line in slack, it's basically what it is. It's going to get parsed similar to just power show on the command line because internally it's using the AST to tokenize these things and break them up. So it's not just taking your string and doing like an invoke expression. You can't do like parameter, you know, power shell injection. It's going to actually look at, analyze what you typed in here and do a whole bunch of stuff behind the scenes. So we all write perfect power shell every time. We can also, PoshBot will recognize errors or exceptions that the command emits and mark that command as failed and also return those back and mark them that, hey, this command had a failure because it's reading the airstream of the job that it's executing these under. And again, there's nothing specific in here. I'm just saying right there. It's still a little more complex thing because sometimes we want pretty output. Let's create a VM, give it some parameters. So, oh, we didn't pass our parameter validation for CPU. We gave it too much. Let's make that happy. So I created a fictional server right there. I wish they were that quick. And you can see that function. I said create VM to create it, but you can see that the command, the actual power shell function had create-vm. Now, if I try to run that, PoshBot is not going to know what that is because I told PoshBot to disregard what the actual function name is. I want it to be called create-vm without a dash. So you can override the function name and call these things whatever you want, internal to PoshBot. And you can see I'm doing some normal parameter validation, returning an object. The special thing here I'm doing is I'm, instead of just returning a string or an object to the output stream, I'm calling new PoshBot card response and telling it a title and some text, which I've formatted, and I'll return the title here and the text. So you can tell within your command how to, you know, do some more custom formatting for the responses of your command. You can just return arbitrary text, but if you want it to look pretty sometimes, a Slack card is useful. Any questions on that? No? Yeah? A little bit. That's going to involve some two-way communication between Slack. I haven't done any coding on it yet, but I've thought about how to work on that. That involves exposing PoshBot to the Internet, so Slack can communicate directly to it. Let's do another command here. Get random number. We'll get a random number. Now we can also say R&D or RAND and also execute that same command. So we have the notion of aliases as well. And you can do that in PoshBot by just specifying an alias property on the attribute that, say, this command is also known by these arbitrary other things. That's really annoying that this keeps on popping up. All right. So here's a little bit more complex example. It's permissions. It would be great if everything could be executed by everyone. Obviously, that can't happen. We need to secure some of these commands, especially if they're going to make changes to the environment or do some sensitive operations. Let's run this command called get secret plan. I don't have authorization to run that command. Let's see why not. Help, get secret plan. This command requires a permission here, which I don't have. So you can tag commands with permissions. Since I'm an admin, I'm going to give myself permission. I'll just copy this so I don't have to type it. So I'm going to add the PoshBot get secrets permission to the admin role, which I'm a member of. Okay. Let's run get secret plan again. Okay. It worked. That didn't get the output directly where I typed that command. That sensitive information, it DMed me that information. Internally, it actually just uploaded some CSVs to Slack. So you can do uploads as well of just arbitrary files. So that get secret plan said you need to have that get secrets permission to be able to execute this. You can have one or more permissions. You need to be a member of at least one of them. I'm also running this custom function called new PoshBot file upload, given it a path to a file and a title. And I'm also saying DM this response back to the calling user. If you don't have that, it's going to respond back to the channel that it received the message in. That all clear? So we can also get that to another user. Let's say let's call a henchman role. We'll add that permission to that role and we'll create also a group. People get added to groups. I might add my alter ego to that group as well. So now my other user here can also run, not get secrets, get a secret plan. So now he's authorized to execute that command as well. So you can inline and Slack give people access to execute commands. You can also mimic. Sometimes you want to give that little extra confirmation before you execute a command. So if I want to remove something called foo, it's going to say, are you sure you want to do that? I say yes, I'm sure. So let's use the force switch because we always love that. And you can see it's going to execute and it recognizes that was three items that I passed in is going to operate on each one of them. And that is, um, remove something internally. I'm just saying did you pass a force switch? If not, let's return a warning back to the user. If they did pass a force switch, let's actually do what they asked us to do. So there's nothing really pospot specific there. That's just imitating the force functionality. So everything I've been doing so far has been one at a time, command one at a time, but if this is a busy channel, you got lots of people loving the chat ops and executing stuff, you want things to run in parallel. Let's run a long command that's going to go off and do something. And we can also run other commands as well. Why that long running command is often doing this thing. These are all executed as jobs for their old set completely separate from each other. And eventually that long running command is going to complete in three, two, one, zero. Okay. There it is. So I mentioned scheduled commands at the beginning a little bit. You can do some basic scheduling with pospot. If you want to do really advanced things like run this thing on the third Friday on, you know, on the full moon. That's not what this is for. This is basic intervals to execute commands. You want to execute this thing once a day at 7am to give you some type of status or something like that and have it available when you get in the office. Let's see. We don't have any scheduled commands right now. Man get help. These are all ALIS for the same command. Let's see what commands match schedule. And you can see some right here. These are all the commands that deal with setting and removing scheduled commands. Let's look at the new schedule command. We can see the syntax for it. We actually need a special permission to be able to schedule commands. So I'm going to create a new schedule to run the status command every 10 seconds. You can run things on hours, seconds, minutes, days. So now we have one. We can see it listed there. And there's the output of the status command. That formatting is not very well. And execute it again. Let's shut that up because that's way too often. Let's remove that. So that's basic schedule command right there. Whatever you type right here, it's basically whatever you type with bang, command, parameters, whatever you want to put in that string, that's what it's going to get executed. It's going to get executed in the context of the user who scheduled it. So if that user doesn't have permissions to run that, that command is going to fail because they don't have the permissions to run it. So here's a little bit more advanced thing. And this is command approvals kind of give you the ability to launch the missile. You need to have two people turn the keys and approve that before it launches. You can enable that for particularly sensitive commands and you want to force that someone else approves it just before you run it. Are you listening? There it is. Okay. That's a bug that I got to fix. So this command needs approval by someone else. And it says you need to have someone in the admin or release groups approve this. And for them to approve it, go ahead and run this. Let's go to my alter ego and have him do it for me. Actually before that, let's see if we can do it. Because we're in admin and no, we can't. You can enable that if you're cool with that. You can approve your own stuff. That's not by default though. So my alter ego, can he do it? No, because he's not in the admin or the release groups. So let's go be nice to him and let's go create a release group and we'll add him to it. Thank you. Not out of the box. Yeah. That would be a good use case to do that. We can also see the anything that's pending and these will eventually time out. That's configurable by default. It's going to be 30 minutes for that person to approve it. Otherwise that command is going to go away. Let's go ahead and prove it. You can see it right there that he proved it and then the output gets command and behind the scenes gets executed. Yeah. All of these commands get executed as jobs, just normal, power shell jobs. Yeah. So you can also of course deny something. If I want to run this again and I want to say prod. Have this have my boss say nope. Not going to do that. Channel rules. You can also control what commands get executed and what channels. Even Poshpot will have to be listening on that channel but maybe you don't want to allow Giffy in the management channel. Let's go back to the general and you can see my practice right there. Nope. Can't do that. I've disallowed it. I'm taking a chance by executing Giffy here. Every time I've run power shell it's been completely safe. We'll get something from Giffy. So how do we enable that is let's look back at our, I haven't shown you this bot configuration. These are the approvals. This is also the configuration where you define what commands need to be approved by what people. So I'm going to say 30 minutes. The command is going to expire. Anything matching that expression. Plug in command version. And it's just wall cards are accepted as well. And then an array of groups that you need to be in to approve that. Channel rules. Similar thing. And these go in the order of, these go from most specific to least specific. So you can say in the general channel allow every command but also exclude anything from the posh bot.giffy plugin. Otherwise just allow everything in every channel. And you can be pretty granular with these rules if you want to. So that's channel rules. So everything I've been executing up to this point has been logged. So we can see our history. And we can see a whole bunch of commands being executed. A bunch of data about that. We can look at a specific one. Get a little bit more information about it. What explicit command they ran. Who did it. Optionally if that was in a command that required approval. Who approved it. And also all of that is also written to a log here that you can configure your retention with. I gotta refresh that. Refresh. So in a JSON file you have a whole bunch of information about what message was received from Slack. What the command was. What the output of the command is. Who approved it. All kinds of information here. And you can ship this off to some type of log aggregator if you want to analyze it. There's also a detailed log of what the bot is doing internally as well. And all that's, the retention for all those you can configure. So those are all commands that don't have any credential needs. You know, to getting those. So this is kind of an interesting one is Wolfram. Everyone know what Wolfram Alpha is? That's really cool website to go ask information of. So I have a command here and actually I got, I stole this from Doug Fink. This is like four lines of PowerShell tech to hit the Wolfram API. So I have this Ask Wolfram command. Anyone know what this is? Real quick. Guess? Alright. 25 miles an hour. So that requires an API that you can get freely from Wolfram to go hit that. You know also Google's URL shortener also requires an API key. I can give it something that's going to return me back a response. So let's look at how that happens because the Wolfram module is out in the gallery but I don't want to ship my API key out with that. So let's look at how you can enable to ship modules that require credentials and have those credentials be supplied at runtime. So let's look at the shortened one because that's the one that's right here. Again, I'm renaming it to shortened. And I have this other attribute here that's attached to a mandatory parameter called API key. And I'm saying when this command gets executed by PoshBot, dynamically insert the value of that configuration that's going to pull from the bot configuration and supply it to the command. And it's basically going to splat it like you would normally when you splat commands to functions. And you can see back in my Start PoshBot that I was dynamically setting that configuration for the Wolfram module, given a value of API key, given setting of something that I've already set. But normally you'd probably want to pull this from a credential store or something like that. But PoshBot will say, okay, well, I need an API key. Go get it from this configuration arbitrarily named. You can give it whatever you want. And this could be a credential. It could be a string. And it does whatever kind of data you want that you don't want to ship with your module. You can stick in here. That's parameter injection. And that's really useful to make. Like VMR plugin, obviously you're not going to ship credentials with that. That's going to be specific to every environment. Also the URL for vSvenr, things like that. You don't want those to be mandatory parameters on the commands, but you can't ship them with the module. The bot, you know, the person who's running the bot is going to have to set that up as configuration. So these are all executed as jobs, meaning that they're stateless effectively. You know, the job runs some code and gets destroyed. There are some use cases where you would want a command to run and then run again and also have the state from the previous run. So you could, you could roll that your own if you wanted to. So I'm going to run this, get my stuff and I didn't provide what I wanted to get. So let's say I want to get the value of foo and I don't have anything. So set my stuff. Set, set some values here. And we'll go retrieve that value. Okay, I got a value there. And what that was internally doing was setting a file here specific to the module. And it's really just export CLI data. So I just dumped some data that POSPOT will make available to the command if it requests it. So that set my stuff command is using a function created by warren frame when he added to POSPOT some ability to set data that was helpful. Okay, so your question about like, I think it was about who was executing the command or a little bit of extra context to the function about who was running these commands. I got a little bit of a few minutes here. So let's, let's show you what that looks like. This is all the data that you have available to you when you execute a command. This is a global object that I insert in the job that shows you, you know, who executed the command. What was the message that received from the network and you can do what you want with this data. So if you want to do extra validation about the actual specific user that executed that, what channel it was in, you know, things like that, you can, you can do with that what you want. And the stateful data, let's see, it's also another thing you can do with this. So let's, let's actually play a game with it. Games have state and I don't have any active games, but let's create a new one. Okay, we got a game. Let's play. And then he'll join. And then go back and forth and have basically this command reads in that state data, rehydrates the game, plays it, and then gives it back to the disk every time. You could probably come up with something more useful than tic-tac-toe, but that was something fun to play with. So namespace, you mentioned multiple commands that have the same name. Internally, Popspot has namespaces. So the actual command that gets executed is the plugin, colon, name, colon, version. So you can be specific and actually import multiple versions of modules and execute different versions of that command. I don't have really time to show you that, but you can, this is how you do it, you would just do a fully qualified name here. Same with disabling. And, okay, so I got to run out of time here. So you can also run it as a service. Here's a little document on how to do that. This is on the doc, the Popspot, the docs.popspot.io site. This is all the documentation. I have it pretty complete. Okay, so that's it with the demo. Why aren't you showing up? There we go. Okay, so how you can get kind of started with chatops is starting small, read-only information. Don't go start creating VMs and destroying things right off the bat. Also tell your security folks that you're probably doing this would be a good idea. Make it easy to do the right thing, put parameter validation, make it very easy to run the commands the correct way, provide same defaults, so kind of fall into that pit of success when these things get executed. You can get a champion to kind of help evangelize this way of working to your organization. Obviously you want to write commands to solve problems that are probably time sucks that are very easy to solve and also take up a lot of your time. I would focus on those commands first. Creating VMs and stuff like that would be something that you could potentially look at. And make it fun, do fun things with this, make it a joy to work with day to day. This is where you can find me, Dev Black Ops on Twitter. My blog is totally out of date. Not a lot of useful information up there. But I am active on Twitter and GitHub quite a bit. These are other projects that I work on. So Saki, recently I became the maintainer of that project. Various Pops for Up plugins, Pops for Up itself. There's some testing based frameworks and stuff like that. There's a whole bunch of stuff you can check out on my GitHub. So that's all I have. Thank you. Thank you.
 So afternoon everyone. My name is Brandon Olin and I'm in dev black ops on Twitter.  And this session is really is about invoke chat ops level up and change your culture  with chat and power shell. First off, does anyone do chat ops in their organization right  now? Couple. Anyone know what it is but haven't done it yet? Who has no clue what this is?  Okay. I think all of you will take something out of this. That's good. Here's some links  to the slide on speaker deck and the code on GitHub that I'll go over today. The slides  are really worth anything. The code is interesting though. This is the agenda that I'm going  to go over. Basically what is chat ops? What is the specific problem set that this tries  to solve? The benefits of working in this way? Some example frameworks out there and  specifically the one that I'm going to be talking about because I wrote it in this power  shell conference. Some examples, commands that you would probably do in a chat ops environment.  And really the bulk of this is an overview of what posh bot is in a demo and hopefully  some time for Q&A. But I've given this talk before with an hour and a half and that wasn't  even enough time so I'm going to try to cram through it as much as I can in 45 minutes.  All right. So let's get started. What is chat ops? This is a pretty succinct definition  from James Freiman, formerly of GitHub. I think he's still a stack storm. And what this  really is, we're taking the things we're already doing, all the work that everyone in here  is doing, solving problems on systems and we're putting that in line with the conversations  that we're having and in this case inside a chat window. We're putting those concepts  together. This is another a little bit longer definition from Atlassian but basically it  says the same thing. You're taking all these tools and all these conversations and notifications  and putting them in a single interface in a single context. And I'll kind of go over  some of the benefits of doing that. This is an example problem that, you know, the typical  Brent problem that this chat ops is trying to solve. So imagine a fictional user named  Bob. He has a problem and he calls the help desk or chats with someone on the help desk  named Sally. He says something's wrong with this server. I don't know what's wrong. Can  you look at it? Sally is a help desk person or some type of operations person and she  doesn't know what that system is. Brent, our favorite person Brent does and maybe he can  help with this. Two hours later, magic happens. The server is fixed. Bob is happy that his  problem was resolved. Sally is happy that the problem went away and she can close the ticket.  But there's all kinds of issues that this kind of highlights. I'm going to go over what  these are. First off, is anyone named Brent in here? I'm sorry that everyone hates you  now. Yeah. So what are some of the opportunities that this kind of highlights? What chat ops  can help with this is it can improve the context. You notice there was a problem. Something  happened. The fixed it. No one knows what that is. And then the person got notified  that it was resolved. Sally never learned anything about that experience. Either that  it Bob really. So Sally or Bob didn't gain any knowledge on how to fix this particular  issue. And neither Sally or Bob were empowered to do this themselves and ideally Bob should  be able to fix this problem himself. Giving either one of these people access to fix this  problem themselves can reduce your meantime to resolution. And ultimately we want fewer  Brents in the organization. Not the actual person. We like Brent. But he is overworked.  He's critical to the team. If he gets hit by a bus, the world crashes. But we want to  reduce the human bottleneck that Brent represents in all of our organizations. And we all are  or we all have been Brent in our careers. Here's some of the other benefits that chat  ops can bring. Like I said, knowledge sharing, empowering the team to fix their own problems.  And that's both IT people and business people. It's really anyone in the organization. Situated  with an awareness is everyone knows what's going on. Everyone knows the problem that's  happening. It's all in one view. You can enable faster onboarding as people get into the organization.  They have a good sense of how that organization works just by looking at the chat history  of that group. Retrospectives or you know, blameless postmortems. You can by having all  this stuff logged in history in a permanent history, you have a basically a flight recorder  of an incident that you can go back to and look at what you did right or what you did  wrong in that case. Technical benefits. Obviously, this is all driven by automation. Like I said,  reducing the time to resolution. You have history and logging of everything you're doing here.  And ultimately you can improve safety and increase security as well.  Here are some example frameworks out there. Probably the grandfather of most of them is  HuBot. These are all based on different languages. HuBot is written in JavaScript and Coffee  Script, Airbot, Python, Collegalix, Ruby, Bot Framework. There wasn't one for PowerShell.  So I created one called PoshBot and that's what I'm going to go over today. But really  any of these will work for chat ops and all of them work really well for what they're  designed to do. But ultimately if you want to implement this in your organization, pick  something that you're familiar with that's native to how you work. Because there's really  a bot probably in any language out there. Here's some example commands that you can  probably think of a whole lot more that you probably write in a chat bot. You can restart  services, you can get and resolve tickets, queries and APIs, modify AD or get AD information,  create VMs or change infrastructure in some way, check processes, get some graphs or performance  metrics to help you in troubleshooting, query systems, even deploy code and kick off pipelines,  slap people with trout if you are old enough to get that reference. Really anything that  you can do, PowerShell you can do in a bot. And that's really the point of this.  So what I'm going to go over today is a bot frame that I created called PoshBot. It's  nearly 100% class based, PowerShell class based. And if you saw my session on Tuesday,  I kind of went over some of the gotchas with classes that I learned by writing this bot.  Modules, PowerShell modules become chat ops commands in the bot and that's really what  this gives you. If you can write a PowerShell module and you can write functions, you can  execute them in a chat bot with really very little if any extra effort than that.  It has a notion of role based access control. You obviously want to secure some of these  commands from people. Not everyone should be able to execute everything. I'll go over  some triggers and scheduled commands and some of the other functionality that the bot will  give you that you may find interesting to enable certain scenarios. So this is parameter  injection, stateful data, black list and white list for commands and channels. There's an  asterisk under multiple chat networks and I know someone will ask me about teams and  I'll give you the answer about why there's an asterisk there. But really this is written,  since it's written in classes, you can extend classes and implement this framework on multiple  chat backends. But primarily I use Slack and this is written and tested on Slack the most.  So that's it really for the slides. Let's get into a demo. Does anyone have any questions?  Is it really loud over there? Okay. So let's go off and start the bot. This is a simple  script I have here to start the bot. We're going to import the module. We're going to  import a configuration file which is really just a PowerShell object that has a lot of  configuration lines on how the bot is going to behave. We're going to set some runtime  specific configuration that I'll show you later in that middle section about plugging  configuration and I'll show you how that works. We're going to create an instance of a chat  backend that the bot is going to reference. In this case I'm going to give it a Slack  API token that's how it's going to authenticate the Slack and make a connection. And then  I'll create the bot and start it. And later on I'll also show you how you can write a  very simple script to run this as a service. You can also run this in a container as well.  I've tested that. So let's go ahead and start this. So you got all that verbose output.  So we can see our bot here is now green. That green is good. So let's go actually  bring it and invite him. So now that bot will be listening on this channel and receiving  commands. All right. So let's run a command here. Let's see if it's up. Okay. Good. We  have status. We can see our bot returned some output. So one of the most frequent things  you're probably going to be running when you're doing chat ops in your organization is help.  You're going to have lots of commands in here and you're not going to be sure exactly how  they operate. So let's run a help command for get plug-in. There's a lot of building  commands to PoshWat and they mostly have to deal with importing and managing modules or  in this case I call them plug-ins and also some user management. Not a whole lot of  chat ops goodness other than just getting the bot functional. Internally what this is  doing is using get help on PowerShell functions and then consuming that and making it visible  inside Slack. So let's actually look at the help for help. You can see you can get detailed  or examples and that's really just a normal get help syntax. You can see you can get the  normal help that you would expect from PowerShell. So what do we have installed right now?  Just one built in. You can see there's a whole bunch of commands here. Like I said,  mostly just to deal with plug-in management and user management. Let's go ahead and install  a plug-in. When I say plug-in, this is just a PowerShell module. I call them plug-ins  because you can add some extra metadata to them to make them operate differently inside  the bot. But these modules, they're just modules and you can execute them from the command  line like any other module. Let's go ahead and install one. Sorry, fine plug-in. What  this is going to do is actually search the PowerShell gallery for modules that have PoshBot  in the name or have a PoshBot tag. So any of these, you can just import right away. Most  of these I created like Dilbert and Giffy and Tic-Tac-Toe and things, Wolfram, just fun  stuff, just demo stuff really to get going. I was happy to see that someone created a  VMware module out there that really just showcases the real benefit of using this. It's actually  getting real work done. That plug-in will snapshot and remove snapshots from VMs right  from Slack. Let's go ahead and install some of these. I already have these actually installed  in my machine, but if I didn't, they would just get installed from the gallery like a  normal plug-in or a normal module. Anyone know what name it is? You do? Do you use it?  Yeah, I do. I like it. What name it is, it's a simple module out there that just generates  random text for test data. So if you want to generate a whole bunch of addresses or  people, you can use name it to generate stuff like that. I like to highlight it because  it has nothing to do with PoshBot whatsoever. It just generates random strings, but you  can import it into PoshBot and execute this stuff right from Slack. So let's try it. So  it has a person command or a function. You can go and run that. You can see it executed  the command and gave us the results. Internally, what PoshBot is doing is executing these commands  in a job, sucking out the various verbose and output and error streams and giving you  the results back in Slack. You'd also know if that command had failures and it will market  as such. You can see this one had nothing in the output or the error stream, so it assumes  that that command was successful. If anyone has any questions, you can speak up as well.  Yeah? It started under my credentials. You can run it as a service, running under whatever  user you want. The jobs will also run under whatever that user is. And I'll show you  what the correct way probably is to run functions that would need credentials to go and do something  else because you wouldn't want to run PoshBot as an elevated user. So I created a, oops,  that's wrong. Give me back an error. Hi, Don. P.S. Summit. Okay. So here's a set of example  commands that I've written to show you some of the various capabilities of the bot. So  before I do that, I'm going to go over the concept of triggers. Triggers are how these  commands get executed. Normally, in the most common way, it's going to be just normal command  triggers. I say bang and a command name and I execute that command. And that's what I've  been doing up to this point. This is also configurable. You can use a different character  other than bang, but that's a common one. So let's execute this get hello world command.  So you can see we get some power swap that's familiar to us. Mandatory parameter was not  provided. That command didn't work. Marked it as failed. Let's actually look at that  command. So there's absolutely nothing special about that function other than it requires  a mandatory parameter and it returns some output. Sure.  Here names based. I'll show you that. Good question. So let's satisfy the parameter.  We'll get back a result. So that's the example of just a normal command trigger. And that's  the most common. In particularly Slack and other chat networks as well, emit events when  things are happening on the network that aren't people chatting in a window. People join and  leave channels. Channels get created. Topics get changed. So you can trigger based on those  events as well. So let's try changing the topic. That's going to emit event, an event  that Popswad is going to see and execute a command. And we can see what this function  would look like. And this is where you start adding Popswad specific metadata to these  commands to make them operate differently. And the bulk of this is really this custom  attribute that I created that you can tell, you can decorate your functions with and when  Popswad imports these, it's going to treat these differently and trigger them differently.  So here you can say it's not an actual command trigger that I'm going to execute. I want  you to trigger on an event. And specifically the channel topic change event that the backend  is going to receive from the chat network. And when that event gets happened, it's going  to trigger this. This type of command, obviously you can't pass input to it because the user  is not actually directly invoking this command. So just caveat there. Yeah.  Can it grab information about the UV? Like can it see what the topic change is to?  Yes. I'll show you that. So the second, that's probably the least common trigger is events  because they're not really all that useful. Regex is going to be the second most common.  You can trigger based on the command matching some arbitrary Regex string. So if someone  just types some text in here, it's going to match that to a command. If it had some commands  that were triggered on Regex. So let's look at what that does. So that was my cookies  function. And again, I'm telling you, it's not a true command. It's going to trigger  on Regex and specifically cookies. So you can put whatever Regex expressing you want  in there and it will trigger on this. I don't know why this keeps scrolling to the top.  So again, same thing. I'm going to trigger on ship it. Anytime I see ship it in the  string, I'm going to pick a random squirrel and give him a squirrel. So in all I'm doing  is doing a write output slack. We'll see that as just a URL that it got responded to and  it will automatically unfurl it. So those aren't too useful unless you really like squirrels.  So let's do a little bit more complex thing. Get multiple things. I didn't give it anything.  It's just going to return with empty parameters that I received. Let's give it a little bit  complex thing. Let's give it an array of strings and an integer. So you can see that the parameter  thing one received three things. It automatically parsed that and recognized it was an array  and thing two was an integer. So let's look at that function and see how that operates.  There's nothing possible specific in there. All I'm doing is accepting two parameters  to with collections and then returning their output. The PoshBot will parse that string  that in similar to basically the AST. So anything you type in the command line or I say command  line in slack, it's basically what it is. It's going to get parsed similar to just  power show on the command line because internally it's using the AST to tokenize these things  and break them up. So it's not just taking your string and doing like an invoke expression.  You can't do like parameter, you know, power shell injection. It's going to actually look  at, analyze what you typed in here and do a whole bunch of stuff behind the scenes.  So we all write perfect power shell every time. We can also, PoshBot will recognize errors  or exceptions that the command emits and mark that command as failed and also return those  back and mark them that, hey, this command had a failure because it's reading the airstream  of the job that it's executing these under. And again, there's nothing specific in here.  I'm just saying right there. It's still a little more complex thing because sometimes  we want pretty output. Let's create a VM, give it some parameters. So, oh, we didn't  pass our parameter validation for CPU. We gave it too much. Let's make that happy. So  I created a fictional server right there. I wish they were that quick. And you can see  that function. I said create VM to create it, but you can see that the command, the actual  power shell function had create-vm. Now, if I try to run that, PoshBot is not going to  know what that is because I told PoshBot to disregard what the actual function name is.  I want it to be called create-vm without a dash. So you can override the function name  and call these things whatever you want, internal to PoshBot. And you can see I'm doing some  normal parameter validation, returning an object. The special thing here I'm doing is  I'm, instead of just returning a string or an object to the output stream, I'm calling  new PoshBot card response and telling it a title and some text, which I've formatted,  and I'll return the title here and the text. So you can tell within your command how to,  you know, do some more custom formatting for the responses of your command. You can just  return arbitrary text, but if you want it to look pretty sometimes, a Slack card is  useful. Any questions on that? No? Yeah?  A little bit. That's going to involve some two-way communication between Slack. I haven't  done any coding on it yet, but I've thought about how to work on that. That involves exposing  PoshBot to the Internet, so Slack can communicate directly to it. Let's do another command here.  Get random number. We'll get a random number. Now we can also say R&D or RAND and also execute  that same command. So we have the notion of aliases as well. And you can do that in PoshBot  by just specifying an alias property on the attribute that, say, this command is also  known by these arbitrary other things. That's really annoying that this keeps on popping  up. All right. So here's a little bit more complex example. It's permissions. It would  be great if everything could be executed by everyone. Obviously, that can't happen. We  need to secure some of these commands, especially if they're going to make changes to the environment  or do some sensitive operations. Let's run this command called get secret plan. I don't  have authorization to run that command. Let's see why not. Help, get secret plan. This command  requires a permission here, which I don't have. So you can tag commands with permissions.  Since I'm an admin, I'm going to give myself permission. I'll just copy this so I don't  have to type it. So I'm going to add the PoshBot get secrets permission to the admin role,  which I'm a member of. Okay. Let's run get secret plan again. Okay. It worked. That  didn't get the output directly where I typed that command. That sensitive information,  it DMed me that information. Internally, it actually just uploaded some CSVs to Slack.  So you can do uploads as well of just arbitrary files. So that get secret plan said you need  to have that get secrets permission to be able to execute this. You can have one or  more permissions. You need to be a member of at least one of them. I'm also running  this custom function called new PoshBot file upload, given it a path to a file and a title.  And I'm also saying DM this response back to the calling user. If you don't have that,  it's going to respond back to the channel that it received the message in. That all clear?  So we can also get that to another user. Let's say let's call a henchman role. We'll add  that permission to that role and we'll create also a group. People get added to groups. I  might add my alter ego to that group as well. So now my other user here can also run, not  get secrets, get a secret plan. So now he's authorized to execute that command as well.  So you can inline and Slack give people access to execute commands. You can also mimic. Sometimes  you want to give that little extra confirmation before you execute a command. So if I want  to remove something called foo, it's going to say, are you sure you want to do that?  I say yes, I'm sure. So let's use the force switch because we always love that. And you  can see it's going to execute and it recognizes that was three items that I passed in is going  to operate on each one of them. And that is, um, remove something internally. I'm just  saying did you pass a force switch? If not, let's return a warning back to the user. If  they did pass a force switch, let's actually do what they asked us to do. So there's nothing  really pospot specific there. That's just imitating the force functionality. So everything  I've been doing so far has been one at a time, command one at a time, but if this is a busy  channel, you got lots of people loving the chat ops and executing stuff, you want things  to run in parallel. Let's run a long command that's going to go off and do something. And  we can also run other commands as well. Why that long running command is often doing this  thing. These are all executed as jobs for their old set completely separate from each  other. And eventually that long running command is going to complete in three, two, one, zero.  Okay. There it is. So I mentioned scheduled commands at the beginning a little bit. You  can do some basic scheduling with pospot. If you want to do really advanced things like  run this thing on the third Friday on, you know, on the full moon. That's not what this  is for. This is basic intervals to execute commands. You want to execute this thing once  a day at 7am to give you some type of status or something like that and have it available  when you get in the office. Let's see. We don't have any scheduled commands right now.  Man get help. These are all ALIS for the same command. Let's see what commands match schedule.  And you can see some right here. These are all the commands that deal with setting and  removing scheduled commands. Let's look at the new schedule command. We can see the syntax  for it. We actually need a special permission to be able to schedule commands. So I'm going  to create a new schedule to run the status command every 10 seconds. You can run things  on hours, seconds, minutes, days. So now we have one. We can see it listed there. And  there's the output of the status command. That formatting is not very well. And execute  it again. Let's shut that up because that's way too often. Let's remove that. So that's  basic schedule command right there. Whatever you type right here, it's basically whatever  you type with bang, command, parameters, whatever you want to put in that string, that's what  it's going to get executed. It's going to get executed in the context of the user who  scheduled it. So if that user doesn't have permissions to run that, that command is going  to fail because they don't have the permissions to run it. So here's a little bit more advanced  thing. And this is command approvals kind of give you the ability to launch the missile.  You need to have two people turn the keys and approve that before it launches. You can  enable that for particularly sensitive commands and you want to force that someone else approves  it just before you run it. Are you listening? There it is. Okay. That's a bug that I got  to fix. So this command needs approval by someone else. And it says you need to have  someone in the admin or release groups approve this. And for them to approve it, go ahead  and run this. Let's go to my alter ego and have him do it for me. Actually before that,  let's see if we can do it. Because we're in admin and no, we can't. You can enable that  if you're cool with that. You can approve your own stuff. That's not by default though.  So my alter ego, can he do it? No, because he's not in the admin or the release groups.  So let's go be nice to him and let's go create a release group and we'll add him to it. Thank  you. Not out of the box. Yeah. That would be a good use case to do that. We can also  see the anything that's pending and these will eventually time out. That's configurable  by default. It's going to be 30 minutes for that person to approve it. Otherwise that command  is going to go away. Let's go ahead and prove it. You can see it right there that he proved  it and then the output gets command and behind the scenes gets executed. Yeah. All of these  commands get executed as jobs, just normal, power shell jobs. Yeah. So you can also of  course deny something. If I want to run this again and I want to say prod. Have this have  my boss say nope. Not going to do that. Channel rules. You can also control what commands  get executed and what channels. Even Poshpot will have to be listening on that channel  but maybe you don't want to allow Giffy in the management channel. Let's go back to  the general and you can see my practice right there. Nope. Can't do that. I've disallowed  it. I'm taking a chance by executing Giffy here. Every time I've run power shell it's  been completely safe. We'll get something from Giffy. So how do we enable that is let's  look back at our, I haven't shown you this bot configuration. These are the approvals.  This is also the configuration where you define what commands need to be approved by what  people. So I'm going to say 30 minutes. The command is going to expire. Anything matching  that expression. Plug in command version. And it's just wall cards are accepted as well.  And then an array of groups that you need to be in to approve that. Channel rules. Similar  thing. And these go in the order of, these go from most specific to least specific. So  you can say in the general channel allow every command but also exclude anything from the  posh bot.giffy plugin. Otherwise just allow everything in every channel. And you can be  pretty granular with these rules if you want to. So that's channel rules. So everything  I've been executing up to this point has been logged. So we can see our history. And we  can see a whole bunch of commands being executed. A bunch of data about that. We can look at  a specific one. Get a little bit more information about it. What explicit command they ran.  Who did it. Optionally if that was in a command that required approval. Who approved it. And  also all of that is also written to a log here that you can configure your retention  with. I gotta refresh that. Refresh. So in a JSON file you have a whole bunch of information  about what message was received from Slack. What the command was. What the output of the  command is. Who approved it. All kinds of information here. And you can ship this off  to some type of log aggregator if you want to analyze it. There's also a detailed log  of what the bot is doing internally as well. And all that's, the retention for all those  you can configure. So those are all commands that don't have any credential needs. You  know, to getting those. So this is kind of an interesting one is Wolfram. Everyone know  what Wolfram Alpha is? That's really cool website to go ask information of. So I have  a command here and actually I got, I stole this from Doug Fink. This is like four lines  of PowerShell tech to hit the Wolfram API. So I have this Ask Wolfram command. Anyone  know what this is? Real quick. Guess? Alright. 25 miles an hour. So that requires an API  that you can get freely from Wolfram to go hit that. You know also Google's URL shortener  also requires an API key. I can give it something that's going to return me back a response.  So let's look at how that happens because the Wolfram module is out in the gallery but  I don't want to ship my API key out with that. So let's look at how you can enable to ship  modules that require credentials and have those credentials be supplied at runtime.  So let's look at the shortened one because that's the one that's right here. Again, I'm  renaming it to shortened. And I have this other attribute here that's attached to a mandatory  parameter called API key. And I'm saying when this command gets executed by PoshBot, dynamically  insert the value of that configuration that's going to pull from the bot configuration and  supply it to the command. And it's basically going to splat it like you would normally  when you splat commands to functions. And you can see back in my Start PoshBot that  I was dynamically setting that configuration for the Wolfram module, given a value of API  key, given setting of something that I've already set. But normally you'd probably want  to pull this from a credential store or something like that. But PoshBot will say, okay, well,  I need an API key. Go get it from this configuration arbitrarily named. You can give it whatever  you want. And this could be a credential. It could be a string. And it does whatever  kind of data you want that you don't want to ship with your module. You can stick in  here. That's parameter injection. And that's really useful to make. Like VMR plugin, obviously  you're not going to ship credentials with that. That's going to be specific to every  environment. Also the URL for vSvenr, things like that. You don't want those to be mandatory  parameters on the commands, but you can't ship them with the module. The bot, you know,  the person who's running the bot is going to have to set that up as configuration. So  these are all executed as jobs, meaning that they're stateless effectively. You know, the  job runs some code and gets destroyed. There are some use cases where you would want a  command to run and then run again and also have the state from the previous run. So you  could, you could roll that your own if you wanted to. So I'm going to run this, get my  stuff and I didn't provide what I wanted to get. So let's say I want to get the value  of foo and I don't have anything. So set my stuff. Set, set some values here. And we'll  go retrieve that value. Okay, I got a value there. And what that was internally doing  was setting a file here specific to the module. And it's really just export CLI data. So I  just dumped some data that POSPOT will make available to the command if it requests it.  So that set my stuff command is using a function created by warren frame when he added to POSPOT  some ability to set data that was helpful. Okay, so your question about like, I think  it was about who was executing the command or a little bit of extra context to the function  about who was running these commands. I got a little bit of a few minutes here. So let's,  let's show you what that looks like. This is all the data that you have available to  you when you execute a command. This is a global object that I insert in the job that  shows you, you know, who executed the command. What was the message that received from the  network and you can do what you want with this data. So if you want to do extra validation  about the actual specific user that executed that, what channel it was in, you know, things  like that, you can, you can do with that what you want. And the stateful data, let's see,  it's also another thing you can do with this. So let's, let's actually play a game with  it. Games have state and I don't have any active games, but let's create a new one.  Okay, we got a game. Let's play. And then he'll join. And then go back and forth and  have basically this command reads in that state data, rehydrates the game, plays it,  and then gives it back to the disk every time. You could probably come up with something  more useful than tic-tac-toe, but that was something fun to play with. So namespace,  you mentioned multiple commands that have the same name. Internally, Popspot has namespaces.  So the actual command that gets executed is the plugin, colon, name, colon, version. So  you can be specific and actually import multiple versions of modules and execute different  versions of that command. I don't have really time to show you that, but you can, this is  how you do it, you would just do a fully qualified name here. Same with disabling. And, okay,  so I got to run out of time here. So you can also run it as a service. Here's a little  document on how to do that. This is on the doc, the Popspot, the docs.popspot.io site.  This is all the documentation. I have it pretty complete. Okay, so that's it with the demo.  Why aren't you showing up? There we go. Okay, so how you can get kind of started with chatops  is starting small, read-only information. Don't go start creating VMs and destroying  things right off the bat. Also tell your security folks that you're probably doing this would  be a good idea. Make it easy to do the right thing, put parameter validation, make it very  easy to run the commands the correct way, provide same defaults, so kind of fall into  that pit of success when these things get executed. You can get a champion to kind of  help evangelize this way of working to your organization. Obviously you want to write  commands to solve problems that are probably time sucks that are very easy to solve and  also take up a lot of your time. I would focus on those commands first. Creating VMs and  stuff like that would be something that you could potentially look at. And make it fun,  do fun things with this, make it a joy to work with day to day. This is where you can  find me, Dev Black Ops on Twitter. My blog is totally out of date. Not a lot of useful  information up there. But I am active on Twitter and GitHub quite a bit. These are other projects  that I work on. So Saki, recently I became the maintainer of that project. Various Pops  for Up plugins, Pops for Up itself. There's some testing based frameworks and stuff like  that. There's a whole bunch of stuff you can check out on my GitHub. So that's all I have.  Thank you.  Thank you.
Invoke-ChatOps_0_47.png Invoke-ChatOps_48_95.png Invoke-ChatOps_96_143.png Invoke-ChatOps_144_251.png Invoke-ChatOps_252_1151.png Invoke-ChatOps_1152_2507.png Invoke-ChatOps_2508_7055.png Invoke-ChatOps_7056_8627.png Invoke-ChatOps_8628_9779.png Invoke-ChatOps_9780_10907.png Invoke-ChatOps_10908_12959.png Invoke-ChatOps_12960_13235.png Invoke-ChatOps_13236_13331.png Invoke-ChatOps_13332_13487.png Invoke-ChatOps_13488_13763.png Invoke-ChatOps_13764_15659.png Invoke-ChatOps_15660_18155.png Invoke-ChatOps_18156_18527.png Invoke-ChatOps_18528_29759.png Invoke-ChatOps_29760_32147.png Invoke-ChatOps_32148_34067.png Invoke-ChatOps_34068_35255.png Invoke-ChatOps_35256_35483.png Invoke-ChatOps_35484_38255.png Invoke-ChatOps_38256_39971.png Invoke-ChatOps_39972_40043.png Invoke-ChatOps_40044_43163.png Invoke-ChatOps_43164_43727.png Invoke-ChatOps_43728_47363.png Invoke-ChatOps_47364_47543.png Invoke-ChatOps_47544_48971.png Invoke-ChatOps_48972_50891.png Invoke-ChatOps_50892_51515.png Invoke-ChatOps_51516_51623.png Invoke-ChatOps_51624_51671.png Invoke-ChatOps_51672_51731.png Invoke-ChatOps_51732_51971.png Invoke-ChatOps_51972_53267.png Invoke-ChatOps_53268_53351.png Invoke-ChatOps_53352_53783.png Invoke-ChatOps_53784_54887.png Invoke-ChatOps_54888_56291.png Invoke-ChatOps_56292_56543.png Invoke-ChatOps_56544_57263.png Invoke-ChatOps_57264_58451.png Invoke-ChatOps_58452_58643.png Invoke-ChatOps_58644_58715.png Invoke-ChatOps_58716_59519.png Invoke-ChatOps_59520_59759.png Invoke-ChatOps_59760_62123.png Invoke-ChatOps_62124_63791.png Invoke-ChatOps_63792_64823.png Invoke-ChatOps_64824_65975.png Invoke-ChatOps_65976_67151.png Invoke-ChatOps_67152_67751.png Invoke-ChatOps_67752_68615.png Invoke-ChatOps_68616_68879.png Invoke-ChatOps_68880_69095.png Invoke-ChatOps_69096_69371.png Invoke-ChatOps_69372_69503.png Invoke-ChatOps_69504_69563.png Invoke-ChatOps_69564_71099.png Invoke-ChatOps_71100_71915.png Invoke-ChatOps_71916_72071.png Invoke-ChatOps_72072_72215.png Invoke-ChatOps_72216_72256.png
So afternoon everyone. My name is Brandon Olin and I'm in dev black ops on Twitter. And this session is really is about invoke chat ops level up and change your culture with chat and power shell. First off, does anyone do chat ops in their organization right now? Couple. Anyone know what it is but haven't done it yet? Who has no clue what this is? Okay. I think all of you will take something out of this. That's good. Here's some links to the slide on speaker deck and the code on GitHub that I'll go over today. The slides are really worth anything. The code is interesting though. This is the agenda that I'm going to go over. Basically what is chat ops? What is the specific problem set that this tries to solve? The benefits of working in this way? Some example frameworks out there and specifically the one that I'm going to be talking about because I wrote it in this power shell conference. Some examples, commands that you would probably do in a chat ops environment. And really the bulk of this is an overview of what posh bot is in a demo and hopefully some time for Q&A. But I've given this talk before with an hour and a half and that wasn't even enough time so I'm going to try to cram through it as much as I can in 45 minutes. All right. So let's get started. What is chat ops? This is a pretty succinct definition from James Freiman, formerly of GitHub. I think he's still a stack storm. And what this really is, we're taking the things we're already doing, all the work that everyone in here is doing, solving problems on systems and we're putting that in line with the conversations that we're having and in this case inside a chat window. We're putting those concepts together. This is another a little bit longer definition from Atlassian but basically it says the same thing. You're taking all these tools and all these conversations and notifications and putting them in a single interface in a single context. And I'll kind of go over some of the benefits of doing that. This is an example problem that, you know, the typical Brent problem that this chat ops is trying to solve. So imagine a fictional user named Bob. He has a problem and he calls the help desk or chats with someone on the help desk named Sally. He says something's wrong with this server. I don't know what's wrong. Can you look at it? Sally is a help desk person or some type of operations person and she doesn't know what that system is. Brent, our favorite person Brent does and maybe he can help with this. Two hours later, magic happens. The server is fixed. Bob is happy that his problem was resolved. Sally is happy that the problem went away and she can close the ticket. But there's all kinds of issues that this kind of highlights. I'm going to go over what these are. First off, is anyone named Brent in here? I'm sorry that everyone hates you now. Yeah. So what are some of the opportunities that this kind of highlights? What chat ops can help with this is it can improve the context. You notice there was a problem. Something happened. The fixed it. No one knows what that is. And then the person got notified that it was resolved. Sally never learned anything about that experience. Either that it Bob really. So Sally or Bob didn't gain any knowledge on how to fix this particular issue. And neither Sally or Bob were empowered to do this themselves and ideally Bob should be able to fix this problem himself. Giving either one of these people access to fix this problem themselves can reduce your meantime to resolution. And ultimately we want fewer Brents in the organization. Not the actual person. We like Brent. But he is overworked. He's critical to the team. If he gets hit by a bus, the world crashes. But we want to reduce the human bottleneck that Brent represents in all of our organizations. And we all are or we all have been Brent in our careers. Here's some of the other benefits that chat ops can bring. Like I said, knowledge sharing, empowering the team to fix their own problems. And that's both IT people and business people. It's really anyone in the organization. Situated with an awareness is everyone knows what's going on. Everyone knows the problem that's happening. It's all in one view. You can enable faster onboarding as people get into the organization. They have a good sense of how that organization works just by looking at the chat history of that group. Retrospectives or you know, blameless postmortems. You can by having all this stuff logged in history in a permanent history, you have a basically a flight recorder of an incident that you can go back to and look at what you did right or what you did wrong in that case. Technical benefits. Obviously, this is all driven by automation. Like I said, reducing the time to resolution. You have history and logging of everything you're doing here. And ultimately you can improve safety and increase security as well. Here are some example frameworks out there. Probably the grandfather of most of them is HuBot. These are all based on different languages. HuBot is written in JavaScript and Coffee Script, Airbot, Python, Collegalix, Ruby, Bot Framework. There wasn't one for PowerShell. So I created one called PoshBot and that's what I'm going to go over today. But really any of these will work for chat ops and all of them work really well for what they're designed to do. But ultimately if you want to implement this in your organization, pick something that you're familiar with that's native to how you work. Because there's really a bot probably in any language out there. Here's some example commands that you can probably think of a whole lot more that you probably write in a chat bot. You can restart services, you can get and resolve tickets, queries and APIs, modify AD or get AD information, create VMs or change infrastructure in some way, check processes, get some graphs or performance metrics to help you in troubleshooting, query systems, even deploy code and kick off pipelines, slap people with trout if you are old enough to get that reference. Really anything that you can do, PowerShell you can do in a bot. And that's really the point of this. So what I'm going to go over today is a bot frame that I created called PoshBot. It's nearly 100% class based, PowerShell class based. And if you saw my session on Tuesday, I kind of went over some of the gotchas with classes that I learned by writing this bot. Modules, PowerShell modules become chat ops commands in the bot and that's really what this gives you. If you can write a PowerShell module and you can write functions, you can execute them in a chat bot with really very little if any extra effort than that. It has a notion of role based access control. You obviously want to secure some of these commands from people. Not everyone should be able to execute everything. I'll go over some triggers and scheduled commands and some of the other functionality that the bot will give you that you may find interesting to enable certain scenarios. So this is parameter injection, stateful data, black list and white list for commands and channels. There's an asterisk under multiple chat networks and I know someone will ask me about teams and I'll give you the answer about why there's an asterisk there. But really this is written, since it's written in classes, you can extend classes and implement this framework on multiple chat backends. But primarily I use Slack and this is written and tested on Slack the most. So that's it really for the slides. Let's get into a demo. Does anyone have any questions? Is it really loud over there? Okay. So let's go off and start the bot. This is a simple script I have here to start the bot. We're going to import the module. We're going to import a configuration file which is really just a PowerShell object that has a lot of configuration lines on how the bot is going to behave. We're going to set some runtime specific configuration that I'll show you later in that middle section about plugging configuration and I'll show you how that works. We're going to create an instance of a chat backend that the bot is going to reference. In this case I'm going to give it a Slack API token that's how it's going to authenticate the Slack and make a connection. And then I'll create the bot and start it. And later on I'll also show you how you can write a very simple script to run this as a service. You can also run this in a container as well. I've tested that. So let's go ahead and start this. So you got all that verbose output. So we can see our bot here is now green. That green is good. So let's go actually bring it and invite him. So now that bot will be listening on this channel and receiving commands. All right. So let's run a command here. Let's see if it's up. Okay. Good. We have status. We can see our bot returned some output. So one of the most frequent things you're probably going to be running when you're doing chat ops in your organization is help. You're going to have lots of commands in here and you're not going to be sure exactly how they operate. So let's run a help command for get plug-in. There's a lot of building commands to PoshWat and they mostly have to deal with importing and managing modules or in this case I call them plug-ins and also some user management. Not a whole lot of chat ops goodness other than just getting the bot functional. Internally what this is doing is using get help on PowerShell functions and then consuming that and making it visible inside Slack. So let's actually look at the help for help. You can see you can get detailed or examples and that's really just a normal get help syntax. You can see you can get the normal help that you would expect from PowerShell. So what do we have installed right now? Just one built in. You can see there's a whole bunch of commands here. Like I said, mostly just to deal with plug-in management and user management. Let's go ahead and install a plug-in. When I say plug-in, this is just a PowerShell module. I call them plug-ins because you can add some extra metadata to them to make them operate differently inside the bot. But these modules, they're just modules and you can execute them from the command line like any other module. Let's go ahead and install one. Sorry, fine plug-in. What this is going to do is actually search the PowerShell gallery for modules that have PoshBot in the name or have a PoshBot tag. So any of these, you can just import right away. Most of these I created like Dilbert and Giffy and Tic-Tac-Toe and things, Wolfram, just fun stuff, just demo stuff really to get going. I was happy to see that someone created a VMware module out there that really just showcases the real benefit of using this. It's actually getting real work done. That plug-in will snapshot and remove snapshots from VMs right from Slack. Let's go ahead and install some of these. I already have these actually installed in my machine, but if I didn't, they would just get installed from the gallery like a normal plug-in or a normal module. Anyone know what name it is? You do? Do you use it? Yeah, I do. I like it. What name it is, it's a simple module out there that just generates random text for test data. So if you want to generate a whole bunch of addresses or people, you can use name it to generate stuff like that. I like to highlight it because it has nothing to do with PoshBot whatsoever. It just generates random strings, but you can import it into PoshBot and execute this stuff right from Slack. So let's try it. So it has a person command or a function. You can go and run that. You can see it executed the command and gave us the results. Internally, what PoshBot is doing is executing these commands in a job, sucking out the various verbose and output and error streams and giving you the results back in Slack. You'd also know if that command had failures and it will market as such. You can see this one had nothing in the output or the error stream, so it assumes that that command was successful. If anyone has any questions, you can speak up as well. Yeah? It started under my credentials. You can run it as a service, running under whatever user you want. The jobs will also run under whatever that user is. And I'll show you what the correct way probably is to run functions that would need credentials to go and do something else because you wouldn't want to run PoshBot as an elevated user. So I created a, oops, that's wrong. Give me back an error. Hi, Don. P.S. Summit. Okay. So here's a set of example commands that I've written to show you some of the various capabilities of the bot. So before I do that, I'm going to go over the concept of triggers. Triggers are how these commands get executed. Normally, in the most common way, it's going to be just normal command triggers. I say bang and a command name and I execute that command. And that's what I've been doing up to this point. This is also configurable. You can use a different character other than bang, but that's a common one. So let's execute this get hello world command. So you can see we get some power swap that's familiar to us. Mandatory parameter was not provided. That command didn't work. Marked it as failed. Let's actually look at that command. So there's absolutely nothing special about that function other than it requires a mandatory parameter and it returns some output. Sure. Here names based. I'll show you that. Good question. So let's satisfy the parameter. We'll get back a result. So that's the example of just a normal command trigger. And that's the most common. In particularly Slack and other chat networks as well, emit events when things are happening on the network that aren't people chatting in a window. People join and leave channels. Channels get created. Topics get changed. So you can trigger based on those events as well. So let's try changing the topic. That's going to emit event, an event that Popswad is going to see and execute a command. And we can see what this function would look like. And this is where you start adding Popswad specific metadata to these commands to make them operate differently. And the bulk of this is really this custom attribute that I created that you can tell, you can decorate your functions with and when Popswad imports these, it's going to treat these differently and trigger them differently. So here you can say it's not an actual command trigger that I'm going to execute. I want you to trigger on an event. And specifically the channel topic change event that the backend is going to receive from the chat network. And when that event gets happened, it's going to trigger this. This type of command, obviously you can't pass input to it because the user is not actually directly invoking this command. So just caveat there. Yeah. Can it grab information about the UV? Like can it see what the topic change is to? Yes. I'll show you that. So the second, that's probably the least common trigger is events because they're not really all that useful. Regex is going to be the second most common. You can trigger based on the command matching some arbitrary Regex string. So if someone just types some text in here, it's going to match that to a command. If it had some commands that were triggered on Regex. So let's look at what that does. So that was my cookies function. And again, I'm telling you, it's not a true command. It's going to trigger on Regex and specifically cookies. So you can put whatever Regex expressing you want in there and it will trigger on this. I don't know why this keeps scrolling to the top. So again, same thing. I'm going to trigger on ship it. Anytime I see ship it in the string, I'm going to pick a random squirrel and give him a squirrel. So in all I'm doing is doing a write output slack. We'll see that as just a URL that it got responded to and it will automatically unfurl it. So those aren't too useful unless you really like squirrels. So let's do a little bit more complex thing. Get multiple things. I didn't give it anything. It's just going to return with empty parameters that I received. Let's give it a little bit complex thing. Let's give it an array of strings and an integer. So you can see that the parameter thing one received three things. It automatically parsed that and recognized it was an array and thing two was an integer. So let's look at that function and see how that operates. There's nothing possible specific in there. All I'm doing is accepting two parameters to with collections and then returning their output. The PoshBot will parse that string that in similar to basically the AST. So anything you type in the command line or I say command line in slack, it's basically what it is. It's going to get parsed similar to just power show on the command line because internally it's using the AST to tokenize these things and break them up. So it's not just taking your string and doing like an invoke expression. You can't do like parameter, you know, power shell injection. It's going to actually look at, analyze what you typed in here and do a whole bunch of stuff behind the scenes. So we all write perfect power shell every time. We can also, PoshBot will recognize errors or exceptions that the command emits and mark that command as failed and also return those back and mark them that, hey, this command had a failure because it's reading the airstream of the job that it's executing these under. And again, there's nothing specific in here. I'm just saying right there. It's still a little more complex thing because sometimes we want pretty output. Let's create a VM, give it some parameters. So, oh, we didn't pass our parameter validation for CPU. We gave it too much. Let's make that happy. So I created a fictional server right there. I wish they were that quick. And you can see that function. I said create VM to create it, but you can see that the command, the actual power shell function had create-vm. Now, if I try to run that, PoshBot is not going to know what that is because I told PoshBot to disregard what the actual function name is. I want it to be called create-vm without a dash. So you can override the function name and call these things whatever you want, internal to PoshBot. And you can see I'm doing some normal parameter validation, returning an object. The special thing here I'm doing is I'm, instead of just returning a string or an object to the output stream, I'm calling new PoshBot card response and telling it a title and some text, which I've formatted, and I'll return the title here and the text. So you can tell within your command how to, you know, do some more custom formatting for the responses of your command. You can just return arbitrary text, but if you want it to look pretty sometimes, a Slack card is useful. Any questions on that? No? Yeah? A little bit. That's going to involve some two-way communication between Slack. I haven't done any coding on it yet, but I've thought about how to work on that. That involves exposing PoshBot to the Internet, so Slack can communicate directly to it. Let's do another command here. Get random number. We'll get a random number. Now we can also say R&D or RAND and also execute that same command. So we have the notion of aliases as well. And you can do that in PoshBot by just specifying an alias property on the attribute that, say, this command is also known by these arbitrary other things. That's really annoying that this keeps on popping up. All right. So here's a little bit more complex example. It's permissions. It would be great if everything could be executed by everyone. Obviously, that can't happen. We need to secure some of these commands, especially if they're going to make changes to the environment or do some sensitive operations. Let's run this command called get secret plan. I don't have authorization to run that command. Let's see why not. Help, get secret plan. This command requires a permission here, which I don't have. So you can tag commands with permissions. Since I'm an admin, I'm going to give myself permission. I'll just copy this so I don't have to type it. So I'm going to add the PoshBot get secrets permission to the admin role, which I'm a member of. Okay. Let's run get secret plan again. Okay. It worked. That didn't get the output directly where I typed that command. That sensitive information, it DMed me that information. Internally, it actually just uploaded some CSVs to Slack. So you can do uploads as well of just arbitrary files. So that get secret plan said you need to have that get secrets permission to be able to execute this. You can have one or more permissions. You need to be a member of at least one of them. I'm also running this custom function called new PoshBot file upload, given it a path to a file and a title. And I'm also saying DM this response back to the calling user. If you don't have that, it's going to respond back to the channel that it received the message in. That all clear? So we can also get that to another user. Let's say let's call a henchman role. We'll add that permission to that role and we'll create also a group. People get added to groups. I might add my alter ego to that group as well. So now my other user here can also run, not get secrets, get a secret plan. So now he's authorized to execute that command as well. So you can inline and Slack give people access to execute commands. You can also mimic. Sometimes you want to give that little extra confirmation before you execute a command. So if I want to remove something called foo, it's going to say, are you sure you want to do that? I say yes, I'm sure. So let's use the force switch because we always love that. And you can see it's going to execute and it recognizes that was three items that I passed in is going to operate on each one of them. And that is, um, remove something internally. I'm just saying did you pass a force switch? If not, let's return a warning back to the user. If they did pass a force switch, let's actually do what they asked us to do. So there's nothing really pospot specific there. That's just imitating the force functionality. So everything I've been doing so far has been one at a time, command one at a time, but if this is a busy channel, you got lots of people loving the chat ops and executing stuff, you want things to run in parallel. Let's run a long command that's going to go off and do something. And we can also run other commands as well. Why that long running command is often doing this thing. These are all executed as jobs for their old set completely separate from each other. And eventually that long running command is going to complete in three, two, one, zero. Okay. There it is. So I mentioned scheduled commands at the beginning a little bit. You can do some basic scheduling with pospot. If you want to do really advanced things like run this thing on the third Friday on, you know, on the full moon. That's not what this is for. This is basic intervals to execute commands. You want to execute this thing once a day at 7am to give you some type of status or something like that and have it available when you get in the office. Let's see. We don't have any scheduled commands right now. Man get help. These are all ALIS for the same command. Let's see what commands match schedule. And you can see some right here. These are all the commands that deal with setting and removing scheduled commands. Let's look at the new schedule command. We can see the syntax for it. We actually need a special permission to be able to schedule commands. So I'm going to create a new schedule to run the status command every 10 seconds. You can run things on hours, seconds, minutes, days. So now we have one. We can see it listed there. And there's the output of the status command. That formatting is not very well. And execute it again. Let's shut that up because that's way too often. Let's remove that. So that's basic schedule command right there. Whatever you type right here, it's basically whatever you type with bang, command, parameters, whatever you want to put in that string, that's what it's going to get executed. It's going to get executed in the context of the user who scheduled it. So if that user doesn't have permissions to run that, that command is going to fail because they don't have the permissions to run it. So here's a little bit more advanced thing. And this is command approvals kind of give you the ability to launch the missile. You need to have two people turn the keys and approve that before it launches. You can enable that for particularly sensitive commands and you want to force that someone else approves it just before you run it. Are you listening? There it is. Okay. That's a bug that I got to fix. So this command needs approval by someone else. And it says you need to have someone in the admin or release groups approve this. And for them to approve it, go ahead and run this. Let's go to my alter ego and have him do it for me. Actually before that, let's see if we can do it. Because we're in admin and no, we can't. You can enable that if you're cool with that. You can approve your own stuff. That's not by default though. So my alter ego, can he do it? No, because he's not in the admin or the release groups. So let's go be nice to him and let's go create a release group and we'll add him to it. Thank you. Not out of the box. Yeah. That would be a good use case to do that. We can also see the anything that's pending and these will eventually time out. That's configurable by default. It's going to be 30 minutes for that person to approve it. Otherwise that command is going to go away. Let's go ahead and prove it. You can see it right there that he proved it and then the output gets command and behind the scenes gets executed. Yeah. All of these commands get executed as jobs, just normal, power shell jobs. Yeah. So you can also of course deny something. If I want to run this again and I want to say prod. Have this have my boss say nope. Not going to do that. Channel rules. You can also control what commands get executed and what channels. Even Poshpot will have to be listening on that channel but maybe you don't want to allow Giffy in the management channel. Let's go back to the general and you can see my practice right there. Nope. Can't do that. I've disallowed it. I'm taking a chance by executing Giffy here. Every time I've run power shell it's been completely safe. We'll get something from Giffy. So how do we enable that is let's look back at our, I haven't shown you this bot configuration. These are the approvals. This is also the configuration where you define what commands need to be approved by what people. So I'm going to say 30 minutes. The command is going to expire. Anything matching that expression. Plug in command version. And it's just wall cards are accepted as well. And then an array of groups that you need to be in to approve that. Channel rules. Similar thing. And these go in the order of, these go from most specific to least specific. So you can say in the general channel allow every command but also exclude anything from the posh bot.giffy plugin. Otherwise just allow everything in every channel. And you can be pretty granular with these rules if you want to. So that's channel rules. So everything I've been executing up to this point has been logged. So we can see our history. And we can see a whole bunch of commands being executed. A bunch of data about that. We can look at a specific one. Get a little bit more information about it. What explicit command they ran. Who did it. Optionally if that was in a command that required approval. Who approved it. And also all of that is also written to a log here that you can configure your retention with. I gotta refresh that. Refresh. So in a JSON file you have a whole bunch of information about what message was received from Slack. What the command was. What the output of the command is. Who approved it. All kinds of information here. And you can ship this off to some type of log aggregator if you want to analyze it. There's also a detailed log of what the bot is doing internally as well. And all that's, the retention for all those you can configure. So those are all commands that don't have any credential needs. You know, to getting those. So this is kind of an interesting one is Wolfram. Everyone know what Wolfram Alpha is? That's really cool website to go ask information of. So I have a command here and actually I got, I stole this from Doug Fink. This is like four lines of PowerShell tech to hit the Wolfram API. So I have this Ask Wolfram command. Anyone know what this is? Real quick. Guess? Alright. 25 miles an hour. So that requires an API that you can get freely from Wolfram to go hit that. You know also Google's URL shortener also requires an API key. I can give it something that's going to return me back a response. So let's look at how that happens because the Wolfram module is out in the gallery but I don't want to ship my API key out with that. So let's look at how you can enable to ship modules that require credentials and have those credentials be supplied at runtime. So let's look at the shortened one because that's the one that's right here. Again, I'm renaming it to shortened. And I have this other attribute here that's attached to a mandatory parameter called API key. And I'm saying when this command gets executed by PoshBot, dynamically insert the value of that configuration that's going to pull from the bot configuration and supply it to the command. And it's basically going to splat it like you would normally when you splat commands to functions. And you can see back in my Start PoshBot that I was dynamically setting that configuration for the Wolfram module, given a value of API key, given setting of something that I've already set. But normally you'd probably want to pull this from a credential store or something like that. But PoshBot will say, okay, well, I need an API key. Go get it from this configuration arbitrarily named. You can give it whatever you want. And this could be a credential. It could be a string. And it does whatever kind of data you want that you don't want to ship with your module. You can stick in here. That's parameter injection. And that's really useful to make. Like VMR plugin, obviously you're not going to ship credentials with that. That's going to be specific to every environment. Also the URL for vSvenr, things like that. You don't want those to be mandatory parameters on the commands, but you can't ship them with the module. The bot, you know, the person who's running the bot is going to have to set that up as configuration. So these are all executed as jobs, meaning that they're stateless effectively. You know, the job runs some code and gets destroyed. There are some use cases where you would want a command to run and then run again and also have the state from the previous run. So you could, you could roll that your own if you wanted to. So I'm going to run this, get my stuff and I didn't provide what I wanted to get. So let's say I want to get the value of foo and I don't have anything. So set my stuff. Set, set some values here. And we'll go retrieve that value. Okay, I got a value there. And what that was internally doing was setting a file here specific to the module. And it's really just export CLI data. So I just dumped some data that POSPOT will make available to the command if it requests it. So that set my stuff command is using a function created by warren frame when he added to POSPOT some ability to set data that was helpful. Okay, so your question about like, I think it was about who was executing the command or a little bit of extra context to the function about who was running these commands. I got a little bit of a few minutes here. So let's, let's show you what that looks like. This is all the data that you have available to you when you execute a command. This is a global object that I insert in the job that shows you, you know, who executed the command. What was the message that received from the network and you can do what you want with this data. So if you want to do extra validation about the actual specific user that executed that, what channel it was in, you know, things like that, you can, you can do with that what you want. And the stateful data, let's see, it's also another thing you can do with this. So let's, let's actually play a game with it. Games have state and I don't have any active games, but let's create a new one. Okay, we got a game. Let's play. And then he'll join. And then go back and forth and have basically this command reads in that state data, rehydrates the game, plays it, and then gives it back to the disk every time. You could probably come up with something more useful than tic-tac-toe, but that was something fun to play with. So namespace, you mentioned multiple commands that have the same name. Internally, Popspot has namespaces. So the actual command that gets executed is the plugin, colon, name, colon, version. So you can be specific and actually import multiple versions of modules and execute different versions of that command. I don't have really time to show you that, but you can, this is how you do it, you would just do a fully qualified name here. Same with disabling. And, okay, so I got to run out of time here. So you can also run it as a service. Here's a little document on how to do that. This is on the doc, the Popspot, the docs.popspot.io site. This is all the documentation. I have it pretty complete. Okay, so that's it with the demo. Why aren't you showing up? There we go. Okay, so how you can get kind of started with chatops is starting small, read-only information. Don't go start creating VMs and destroying things right off the bat. Also tell your security folks that you're probably doing this would be a good idea. Make it easy to do the right thing, put parameter validation, make it very easy to run the commands the correct way, provide same defaults, so kind of fall into that pit of success when these things get executed. You can get a champion to kind of help evangelize this way of working to your organization. Obviously you want to write commands to solve problems that are probably time sucks that are very easy to solve and also take up a lot of your time. I would focus on those commands first. Creating VMs and stuff like that would be something that you could potentially look at. And make it fun, do fun things with this, make it a joy to work with day to day. This is where you can find me, Dev Black Ops on Twitter. My blog is totally out of date. Not a lot of useful information up there. But I am active on Twitter and GitHub quite a bit. These are other projects that I work on. So Saki, recently I became the maintainer of that project. Various Pops for Up plugins, Pops for Up itself. There's some testing based frameworks and stuff like that. There's a whole bunch of stuff you can check out on my GitHub. So that's all I have. Thank you. Thank you.
to solve? The benefits of working in this way? functionality that the bot will give you that you because the user is not actually directly PoshBot, dynamically insert the value of that cases where you would want a command to run and way of working to your organization. Obviously