{"id":3861,"date":"2013-04-07T11:59:00","date_gmt":"2013-04-07T11:59:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2013\/04\/07\/do-one-thing-and-do-it-well\/"},"modified":"2013-04-07T11:59:00","modified_gmt":"2013-04-07T11:59:00","slug":"do-one-thing-and-do-it-well","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/do-one-thing-and-do-it-well\/","title":{"rendered":"Do One Thing and Do It Well"},"content":{"rendered":"<p><span style=\"font-size: small\"><strong style=\"font-size: 12px\">Summary<\/strong>: Microsoft PowerShell MVPs, Don Jones and Jeffery Hicks, talk about a fundamental tool design consideration.<\/span><\/p>\n<p><span style=\"font-size: small\">Microsoft Scripting Guy, Ed Wilson, is here. This week we will not have our usual <strong>PowerTip<\/strong>. Instead we have excerpts from seven books from Manning Press. In addition, each blog will have a special code for 50% off the book being excerpted that day. Remember that the code is valid only for the day the excerpt is posted. The coupon code is also valid for a second book from the Manning collection.<\/span><\/p>\n<p><span style=\"font-size: small\">This excerpt is from <a href=\"http:\/\/www.manning.com\/jones4\/\" target=\"_blank\">Learn PowerShell Toolmaking in a Month of Lunches<\/a>&nbsp;<br \/>&nbsp; By Don Jones and Jeffery Hicks<\/span><\/p>\n<p><span style=\"font-size: small\"><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0068.wes-4-7-13-1.jpg\"><img decoding=\"async\" style=\"border: 0px currentColor\" title=\"Photo of book cover\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0068.wes-4-7-13-1.jpg\" alt=\"Photo of book cover\" \/><\/a><\/span><\/p>\n<p><span style=\"font-size: small\">Here&rsquo;s a basic tenant of good Windows PowerShell tool design: do one thing, and do it well. Broadly speaking, a function should do one&mdash;and only one&mdash;of these things:<\/span><\/p>\n<ul>\n<li><span style=\"font-size: small\">Retrieve data from someplace<\/span><\/li>\n<li><span style=\"font-size: small\">Process data<\/span><\/li>\n<li><span style=\"font-size: small\">Output data to some place<\/span><\/li>\n<li><span style=\"font-size: small\">Put data into some visual format meant for human consumption<\/span><\/li>\n<\/ul>\n<p><span style=\"font-size: small\">This fits well with the command-naming convention in Windows PowerShell: If your function uses the verb Get, that&rsquo;s what it should do: get. If it&rsquo;s outputting data, you name it with a verb like Export, or Out, or something else. If each command (okay, function) worries about just one of those things, then they&rsquo;ll have the maximum possible flexibility.<\/span><\/p>\n<p><span style=\"font-size: small\">For example, let&rsquo;s say we want to write a tool that will retrieve some key operating system information from multiple computers and then display that information in a nicely formatted onscreen table. It&rsquo;d be easy to write that tool so that it opened Active Directory, got a bunch of computer names, queried the information from them, and then formatted a nice table as output.<\/span><\/p>\n<p><span style=\"font-size: small\">The problem?<\/span><\/p>\n<p><span style=\"font-size: small\">Well, what if tomorrow we didn&rsquo;t want the data on the screen but rather wanted it in a CSV file? What if one time we needed to query a small list of computers rather than a bunch of computers from the directory? Either change would involve coding changes, probably resulting in many different versions of our tool lying around. Had we made it more modular and followed the basic philosophy we just outlined, we wouldn&rsquo;t have to do that. Instead, we might have designed the following:<\/span><\/p>\n<ul>\n<li><span style=\"font-size: small\">One function that gets computer names from the directory<\/span><\/li>\n<li><span style=\"font-size: small\">One function that accepts computer names, queries those computers, and produces the desired data<\/span><\/li>\n<li><span style=\"font-size: small\">One function that formats data into a nice onscreen table<\/span><\/li>\n<\/ul>\n<p><span style=\"font-size: small\">Suddenly, everything becomes more flexible. That middle function could now work with any source of computer names: the directory, a text file, or whatever. Its data could be sent to any other command to produce output. Maybe we&rsquo;d pipe it to <strong>Export-CSV<\/strong>&nbsp;to make that CSV file&nbsp;or to <strong>ConvertTo-HTML<\/strong>&nbsp;to make an HTML page. What about the onscreen table we want right now? We&rsquo;re betting <strong>Format-Table<\/strong>&nbsp;could do the job, meaning we don&rsquo;t even have to write that third function at all&mdash;less work for us!<\/span><\/p>\n<p><span style=\"font-size: small\">So let&rsquo;s talk about function design. We&rsquo;re going to suggest that there are really three categories of functions (or tools): input, functional, and output.<\/span><\/p>\n<h3><span style=\"font-size: small\">Input tools<\/span><\/h3>\n<p><span style=\"font-size: small\">Input tools are the functions that don&rsquo;t produce anything inherently useful, but are rather meant to feed information to a second tool. So a function that retrieves computer names from a configuration management database is an input tool. You don&rsquo;t necessarily want the computer names, but there might be an endless variety of other tools that you want to send computer names to&mdash;including any number of built-in Windows PowerShell commands.<\/span><\/p>\n<p><span style=\"font-size: small\">Here&rsquo;s a good example of how to draw a line between your functions. Let&rsquo;s say you&rsquo;re writing a hunk of commands intended to retrieve computer names from your configuration management database. Your intent today is to query some WMI information from those computers&mdash;but aren&rsquo;t there other tools that need computer names as input? Sure! <strong>Restart-Computer<\/strong>&nbsp;accepts computer names. So does <strong>Get-EventLog<\/strong>, <strong>Get-Process<\/strong>, <strong>Invoke-Command<\/strong>, and a dozen more commands. That&rsquo;s what suggests (to us, at least) that functionality for getting names from the database should be a standalone tool. It could potentially feed a lot more than only today&rsquo;s current needs.<\/span><\/p>\n<p><span style=\"font-size: small\">Windows PowerShell already comes with a number of input tools. Sticking with the theme of getting computer names, you might use <strong>Import-CSV<\/strong>, <strong>Get-Content<\/strong>, or <strong>Get-ADComputer<\/strong>&nbsp;to retrieve computer names from various sources. To us, this further emphasizes the fact that the task of getting computer names is a standalone capability, rather than being part of another tool.<\/span><\/p>\n<h3><span style=\"font-size: small\">Functional tools<\/span><\/h3>\n<p><span style=\"font-size: small\">This is the kind of tool you&rsquo;ll be writing most often. The idea is that this kind of tool doesn&rsquo;t spend time retrieving information that it needs to do its main job. Instead, it accepts that information via a parameter of some kind&mdash;that parameter being fed by manually entered data, by another command, and so on.<\/span><\/p>\n<p><span style=\"font-size: small\">So if your functional tool is going to query information from remote computers, it doesn&rsquo;t internally do anything to get those computers&rsquo; names; but instead, it accepts them on a parameter. It doesn&rsquo;t care where the computer names come from&mdash;that&rsquo;s another job.<\/span><\/p>\n<p><span style=\"font-size: small\">When it&rsquo;s been given the information it needs to operate, a functional tool does its job and then outputs objects to the pipeline. Specifically, it outputs a single kind of object, so that all of its output is consistent. This functional tool also doesn&rsquo;t worry about what you plan to do with that output&mdash;it simply puts objects into the pipeline. This kind of tool doesn&rsquo;t spend a nanosecond worrying about formatting, about output files, or about anything else. It does its job, perhaps produces some objects as output, and that&rsquo;s it.<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: small\"><strong>Note<\/strong>&nbsp;&nbsp;&nbsp;Not all functional tools will produce output of any kind. A command that just does something&mdash;perhaps reconfiguring a computer&mdash;might not produce any output, apart from error messages if something goes wrong. That&rsquo;s fine.<\/span><\/p>\n<h3><span style=\"font-size: small\">Output tools<\/span><\/h3>\n<p><span style=\"font-size: small\">Output tools are specifically designed to take data (in the form of objects), which has been produced by a functional tool, and then put that data into a final form. Let&rsquo;s stress that: final form. We looked up final in our dictionary, and it says something like, &ldquo;pertaining to or coming at the end; last in place, order, or time.&rdquo; In other words, when you send your data to an output tool, you&rsquo;re finished with it. You don&rsquo;t want anything else happening to the data. You want to save it in a file or a database, or display it onscreen, or fax it to someone, or tap it out in Morse code&hellip;whatever. Windows PowerShell verbs for this include <strong>Export<\/strong>, <strong>Out<\/strong>, and <strong>ConvertTo<\/strong>, to name a few.<\/span><\/p>\n<p><span style=\"font-size: small\">Consider the inverse of this philosophy: If you have a tool that&rsquo;s putting data into some final form, like a text file or an onscreen display, that tool should be doing nothing else. Why?<\/span><\/p>\n<p><span style=\"font-size: small\">Consider a function that we&rsquo;ve created, named <strong>Get-ComputerDetails<\/strong>. This function gets a bunch of information from a bunch of computers. It then produces a pretty, formatted table on the screen. That&rsquo;s a text-based display. Doing so means we could never do this:<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: small\">Get-ComputerDetails | Where OSBuildNumber &ndash;le 7600 |<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: small\">Sort ComputerName | ConvertTo-HTML | Out-File computers.html<\/span><\/p>\n<p><span style=\"font-size: small\">Why couldn&rsquo;t we do that? Because, in this example, <strong style=\"font-size: 12px\">Get-ComputerDetails<\/strong> is producing text. <strong style=\"font-size: 12px\">Where-Object<\/strong>, <strong style=\"font-size: 12px\">Sort-Object<\/strong>, and <strong style=\"font-size: 12px\">ConvertTo-HTML<\/strong> can&rsquo;t deal with text&mdash;they deal with objects. <strong style=\"font-size: 12px\">Get-ComputerDetails<\/strong>&nbsp;has put our data into its final form, meaning&mdash;according to the dictionary&mdash;that <strong style=\"font-size: 12px\">Get-ComputerDetails<\/strong> is &ldquo;coming at the end&rdquo; and should be &ldquo;last in place.&rdquo; Nothing can come after it&mdash;meaning we have less flexibility.<\/span><\/p>\n<p><span style=\"font-size: small\">A better design would have had <strong>Get-ComputerDetails<\/strong> produce only objects and to create a second command, perhaps called <strong>Format-MyPrettyDisplay<\/strong>, which handles the formatting. That way we could get our originally desired output:<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: small\">Get-ComputerDetails | Format-MyPrettyDisplay<\/span><\/p>\n<p><span style=\"font-size: small\">But we could also do this:&nbsp;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: small\">Get-ComputerDetails | Where OSBuildNumber &ndash;le 7600 |<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: small\">Sort ComputerName | ConvertTo-HTML | Out-File computers.html<\/span><\/p>\n<p><span style=\"font-size: small\">This would allow us to change our minds about using <strong style=\"font-size: 12px\">Format-MyPrettyDisplay<\/strong> from time-to-time, instead sending our data objects on to other commands to produce different displays, filter the data, source the data, create files, and so on.<\/span><\/p>\n<p><span style=\"font-size: small\">This blog discussed the basics of good Windows PowerShell tool design. A function should perform only one of the following actions:<\/span><\/p>\n<ul>\n<li><span style=\"font-size: small\">Retrieve data from someplace<\/span><\/li>\n<li><span style=\"font-size: small\">Process data<\/span><\/li>\n<li><span style=\"font-size: small\">Output data to some place<\/span><\/li>\n<li><span style=\"font-size: small\">Put data into a visual format meant for human consumption<\/span><\/li>\n<\/ul>\n<p><span style=\"font-size: small\">We talked about three different categories of functions, or tools: input, functional, and output.<\/span><\/p>\n<p><span style=\"font-size: small\">~Don and Jeffrey<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: small\"><strong>Here is the code for the discount offer today at <\/strong><a href=\"http:\/\/www.manning.com\/\" target=\"_blank\">www.manning.com<\/a>: <strong>scriptw7<\/strong><\/span><br \/><span style=\"font-size: small\"> Valid for 50% off <a href=\"http:\/\/www.manning.com\/jones4\/\" target=\"_blank\">Learn PowerShell Toolmaking in a Month of Lunches<\/a> and <a href=\"http:\/\/www.manning.com\/harryman\/\" target=\"_blank\">SharePoint 2010 Owner&#8217;s Manual<\/a> <\/span><br \/><span style=\"font-size: small\"> Offer valid from April 7, 2013 12:01 AM until April 8, midnight (EST)<\/span><\/p>\n<p><span style=\"font-size: small\">I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/span><\/p>\n<p><span style=\"font-size: small\"><strong>Ed Wilson, Microsoft Scripting Guy<\/strong><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft PowerShell MVPs, Don Jones and Jeffery Hicks, talk about a fundamental tool design consideration. Microsoft Scripting Guy, Ed Wilson, is here. This week we will not have our usual PowerTip. Instead we have excerpts from seven books from Manning Press. In addition, each blog will have a special code for 50% off the [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[64,56,65,3,4,61,45],"class_list":["post-3861","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-don-jones","tag-guest-blogger","tag-jeffery-hicks","tag-scripting-guy","tag-scripting-techniques","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft PowerShell MVPs, Don Jones and Jeffery Hicks, talk about a fundamental tool design consideration. Microsoft Scripting Guy, Ed Wilson, is here. This week we will not have our usual PowerTip. Instead we have excerpts from seven books from Manning Press. In addition, each blog will have a special code for 50% off the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3861","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=3861"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3861\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=3861"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=3861"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=3861"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}