{"id":981,"date":"2023-05-02T06:57:27","date_gmt":"2023-05-02T13:57:27","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/powershell-community\/?p=981"},"modified":"2023-05-03T06:15:12","modified_gmt":"2023-05-03T13:15:12","slug":"designing-powershell-for-end-users","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell-community\/designing-powershell-for-end-users\/","title":{"rendered":"Designing PowerShell For End Users"},"content":{"rendered":"<p>PowerShell, being built on .NET and object-oriented in nature, is a <em>fantastic<\/em> language for developing tooling that you can deliver to your end users. These may be fellow technologists, or they could also be non-technical users within your organization. This could also be a tool you wish to share with the community, either via your own GitHub or by publishing to the PowerShell Gallery.<\/p>\n<h2>What Are You Doing?<\/h2>\n<p>When setting out with the task of developing a tool you should, as a first step, stop and think. Think about what problem your tool is trying to solve. This could be a number of things<\/p>\n<ul>\n<li>Creating data<\/li>\n<li>Collating data<\/li>\n<li>Interacting with a system or systems<\/li>\n<\/ul>\n<p>The sky is the limit here, but your first thing is to determine what it is that you are trying to accomplish.<\/p>\n<h2>What Should You Call It?<\/h2>\n<p>Your second step should be to consider your tool&#8217;s name. Whether this is a single function, or a series of functions that form a new module, you should consider the following:<\/p>\n<ul>\n<li>Use <a href=\"https:\/\/learn.microsoft.com\/powershell\/scripting\/developer\/cmdlet\/approved-verbs-for-windows-powershell-commands\">approved verbs<\/a> for Functions. You can run <code>Get-Verb<\/code> in your console to quickly get a list! <em>Tip<\/em>: Use <code>Get-Verb | Sort-Object<\/code> to make this easier to parse!<\/li>\n<li>Use a coherent noun. Be as specific as possible. Using a great combination of verb\/noun syntax provides clarity to what your tool does.<\/li>\n<\/ul>\n<h2>Designing Parameters<\/h2>\n<p>This step <em>could<\/em> take some time, and a little trial and error. You want your tool to be flexible, but you don&#8217;t want your parameter names to be so difficult such that they are hard to use\/remember. Succinct is better here. If you need to add some flexibility to your tool, consider using <a href=\"https:\/\/learn.microsoft.com\/powershell\/module\/microsoft.powershell.core\/about\/about_parameter_sets\">ParameterSets<\/a>. These will give your end users a few different ways to use your tool, if that is or becomes necessary in the future.<\/p>\n<h3>Applying Guardrails<\/h3>\n<p>Guardrails, in this context, refers to the application of restrictions upon your parameters. These prevent your end users from passing incorrect input to the tool you&#8217;ve provided them. Given that PowerShell is built on .NET, there is a <em>ton<\/em> of flexibility and strength in the guardrails you can employ.<\/p>\n<p>I&#8217;ll touch on just a few of my favorites, but this is by far not an exhaustive list.<\/p>\n<h4>1&#46; ValidateSet<\/h4>\n<p>Let&#8217;s look at an example first:<\/p>\n<pre><code class=\"language-powershell\">[CmdletBinding()]\nParam(\n    [Parameter()]\n    [ValidateSet('Cat','Dog','Fish','Bird')]\n    [String]\n    $Animal\n)<\/code><\/pre>\n<p>If you notice above, we&#8217;ve defined a non-mandatory parameter that is of type <code>[String]<\/code>. This is a guardrail because any other type causes an error to be thrown. We have added further restrictions (guardrails) on this parameter by employing a <code>[ValidateSet()]<\/code> attribute, which limits the valid input to <em>only<\/em> those items that are a member of the set. Provide <code>Horse<\/code> to the animal parameter and, even though it is a string, it produces an error because it&#8217;s not a member of the approved set of inputs.<\/p>\n<h4>2&#46; ValidateRange<\/h4>\n<p>We&#8217;ll start with another example:<\/p>\n<pre><code class=\"language-powershell\">[CmdletBinding()]\nParam(\n    [Parameter()]\n    [ValidateRange(2005,2023)]\n    [Int]\n    $Year\n)<\/code><\/pre>\n<p>In this example we have defined a <code>Year<\/code> parameter that is an <code>[Int]<\/code>, meaning only numbers are valid input. We&#8217;ve applied guardrails via <code>[ValidateRange()]<\/code>, which limits the input to between 2005 and 2023. Any number outside of that range produces an error.<\/p>\n<h4>3&#46; ValidateScript<\/h4>\n<p>The <code>[ValidateScript()]<\/code> attribute is extremely powerful. It allows you to run arbitrary PowerShell code in a script block to check the input of a given parameter. Let&#8217;s check out a <em>very<\/em> simple example:<\/p>\n<pre><code class=\"language-powershell\">[CmdletBinding()] \nParam( \n    [Parameter()]\n    [ValidateScript({ Test-Path $_ })]\n    [String]\n    $InputFile\n)<\/code><\/pre>\n<p>By using <code>Test-Path $_<\/code> in the Scriptblock of our <code>[ValidateScript()]<\/code> attribute we are instructing PowerShell to confirm that the input we have provided to the parameter actually exists (<em>Notice the addition of <code>{}<\/code> here<\/em>). This helps by putting guardrails around human error in the form of typos.<\/p>\n<h2>Wrapping It Up<\/h2>\n<p>As previously stated, adding guardrails to your tools using these methods (and countless others not mentioned) <em>demonstrably<\/em> increases the usability and adoption of your tools.<\/p>\n<p>So take a step back, think about your tool&#8217;s design <em>first<\/em>, and then start writing the code. I think you&#8217;ll find that it is a much more enjoyable experience, from creation to adoption.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This posts explains taking user experience into account when designing PowerShell tools<\/p>\n","protected":false},"author":117969,"featured_media":77,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[13],"tags":[84,3,85,86],"class_list":["post-981","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","tag-design","tag-powershell","tag-toolmaking","tag-user-experience"],"acf":[],"blog_post_summary":"<p>This posts explains taking user experience into account when designing PowerShell tools<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/posts\/981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/users\/117969"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/comments?post=981"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/posts\/981\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/media\/77"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/media?parent=981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/categories?post=981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/tags?post=981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}