{"id":405,"date":"2018-05-15T05:30:26","date_gmt":"2018-05-15T13:30:26","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/koryt\/?p=405"},"modified":"2020-04-29T10:25:48","modified_gmt":"2020-04-29T17:25:48","slug":"doing-more-with-functions-verbose-logging-risk-mitigation-and-parameter-sets","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/doing-more-with-functions-verbose-logging-risk-mitigation-and-parameter-sets\/","title":{"rendered":"Doing more with functions: Verbose logging, Risk mitigation, and Parameter Sets"},"content":{"rendered":"<p>Welcome back to PowerShell for Programmers, this week I&#8217;m trying gitGist again for the code blocks. Let me know what you think about it vs the normal syntax highlighter I use \ud83d\ude42<\/p>\n<p>As we&#8217;ve seen in the other posts about functions, attributes are a really cool thing to extend the features we have available to ourselves and for our users. This post is going to deal with an attribute for the function itself as well as ones for the individual parameters. This will let us make our functions behave more like any other cmdlet, by giving us access to the common parameters that users are used to seeing.<\/p>\n<h2>Common Parameters<\/h2>\n<p>Common parameters are available on every single cmdlet. This means that users who are going to consume your functions are used to seeing them. If you&#8217;re just coming into PowerShell and unfamiliar with them, take a look <a href=\"https:\/\/docs.microsoft.com\/en-us\/powershell\/module\/microsoft.powershell.core\/about\/about_commonparameters?view=powershell-6\">here<\/a>. We can get access to these on our code by adding the attribute [cmdletbinding()] at the top of our functions of scripts (before the param keyword).<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/d356dfedba50933f3f2d90a4c3e0474b.js\"><\/script><\/p>\n<p>If we take a look at the syntax or just use the intellisense we can see they have been added:<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-86476\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2018\/05\/commonparam.png\" alt=\"\" width=\"865\" height=\"568\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2018\/05\/commonparam.png 865w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2018\/05\/commonparam-300x197.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2018\/05\/commonparam-768x504.png 768w\" sizes=\"(max-width: 865px) 100vw, 865px\" \/><\/p>\n<p>Note that our custom parameters will <em>always<\/em> come before the common ones, so we know that once we see -verbose there won&#8217;t be any more stuff we created.<\/p>\n<p>While they are there, they might not actually <em>do<\/em> anything yet. The common parameters are all about overriding some default behaviors of powershell. For example, -verbose or -debug will just make those streams visible for that command. If we have write-verbose lines in our function then -verbose will show those lines:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/fddb629255f4d8e7bae0ab0c38f03aee.js\"><\/script><\/p>\n<p>Error action is going to work for us for everything in our code, including custom error messages:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/747419fd29f80056009e30925917932a.js\"><\/script><\/p>\n<p>It can be really nice to get this kind of functionality into your tool sets before you distribute them to others, whether they are on your team, in your company or a broader online audience.<\/p>\n<h2>Risk Mitigation<\/h2>\n<p>The [cmdletbinding()] attribute can also enable a bunch of different flags inside of it. Two really common ones are:<\/p>\n<ul>\n<li>&#8220;SupportsShouldProcess&#8221; which gives us the Risk Mitigation parameters -whatif and -confirm. These are similar to the common parameters, but they aren&#8217;t on everything, they are just on a lot of stuff.<\/li>\n<li>&#8220;ConfirmImpact&#8221; which tells PowerShell how dangerous your code is and whether or not it should default a confirmation prompt, or just show it when using -confirm<\/li>\n<\/ul>\n<p>To leverage these, we are also going to use a built in variable called <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.management.automation.pscmdlet?view=powershellsdk-1.1.0\">$PSCmdlet<\/a>, which contains a bunch of useful metadata and methods for doing interesting things to our functions that we want to be cmdlets.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/e774f0d52e3d8e9572ea1d9558f9edd4.js\"><\/script><\/p>\n<p>I&#8217;ve gone and added risk mitigation, but as you can see it isn&#8217;t doing anything effective yet:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/e774f0d52e3d8e9572ea1d9558f9edd4.js\"><\/script><\/p>\n<p>What we can do is wrap our &#8220;action code&#8221; in an if statement. The action code is whatever you want -whatif to block from happening. For example, most of your code is probably grabbing and looking at data to make decisions, and you still probably want that to happen so you can give a meaningful &#8220;whatif:&#8221; message, but instead of deleting\/changing data you might want to wrap that up for the -whatif to block.<\/p>\n<blockquote><p>Ok, but how to I determine whether or not the if statement runs?<\/p><\/blockquote>\n<p>Great question! That&#8217;s where $PScmdlet comes in. One of the methods it has is called &#8220;ShouldProcess&#8221;, it returns a bool, and it has a bunch of overloads you can see on the docs page. If the user puts -whatif, ShouldProcess will return false. If they put -confirm and hit no in the box it will also return false. Additionally ShouldProcess is what generates the &#8220;Whatif:&#8221; and confirmation box messages. The most common overload is this one:<\/p>\n<pre class=\"lang:c# decode:true\">public bool ShouldProcess (string target, string action);<\/pre>\n<p>Let&#8217;s see that in action with PowerShell:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/e1c0281af379642ff7062a81d53e745f.js\"><\/script><\/p>\n<p>Finally, let&#8217;s flag our code as dangerous. ConfirmImpact can be &#8220;Low&#8221;, &#8220;Medium&#8221;, or &#8220;High&#8221;.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/f6c85f607a974c04e2657e6d669df893.js\"><\/script><\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-86478\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2018\/05\/confirmbox.png\" alt=\"\" width=\"326\" height=\"115\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2018\/05\/confirmbox.png 326w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2018\/05\/confirmbox-300x106.png 300w\" sizes=\"(max-width: 326px) 100vw, 326px\" \/><\/p>\n<p>Notice how it will pop up any time you call it, regardless of if you typed -confirm. This is actually controlled with a setting variable $ConfirmPreference if you ever want to change it. You can also override it inline with -confirm:$false<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/b966b04e19a1cdae671ac5d5eb42f8ff.js\"><\/script><\/p>\n<h2>Parameter Sets<\/h2>\n<p>Using parameter sets can really let you extend your toolset. Think of Parameter Sets as overloads for your function. Instead of declaring them all separately like you might in C#, we have to build them all together in PowerShell. A good example might be if you had a function to do the same work on different objects, so the only part that might change is fetching the objects:<\/p>\n<ul>\n<li>Stop-process is a good place to see this as it only has 3 parameter sets. One that takes in process IDs, one that takes in process names and one that takes in process objects. All of these scenarios will use the same action code, but fetch the process data differently.<\/li>\n<li>If you had code for AD users and computers you could offer a -computer set that fetches a computer and a -user set that fetches a user, but then the code that acts on the data could remain the same.<\/li>\n<\/ul>\n<p>To do this, we go back to our friend the [parameter()] attribute. We can specify the set we want each parameter in, and we can have it be mandatory or optional for each set we specify. If you do not specify a set, then it will be in <em>all<\/em> sets.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/125d40db136c4926a121395f26be9f95.js\"><\/script><\/p>\n<p>Notice now we can use either set, but we can&#8217;t use parameters from different sets together.<\/p>\n<blockquote><p>But how can I make sure I only run the code I want for each set?<\/p><\/blockquote>\n<p>We will leverage $PScmdlet again, some of the meta data it holds includes which parameter set we used:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/813703f7eca5b292cfc9e93c5f4c2221.js\"><\/script><\/p>\n<p>Finally, if someone tries to use our parameters positionally we might run into some issues due to the sets. We can let Power Shell know which one to use as the default with\u00a0 [cmdletbinding()] like this:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Sambardo\/ec3393e0435ccf496f5ba315792ae7f7.js\"><\/script><\/p>\n<pre class=\"lang:default decode:true\">cmdlet MyFunction at command pipeline position 1\r\nSupply values for the following parameters:\r\nProcess:<\/pre>\n<p>Well that\u2019s all for now, hopefully this helps you as you start to build out tools in PowerShell that you want to add that professional shine to!<\/p>\n<p>For the main series post, check back\u00a0<a href=\"https:\/\/devblogs.microsoft.com\/scripting\/powershell-for-programmers-a-quick-start-guide\/\">here.<\/a><\/p>\n<p>If you find this helpful don&#8217;t forget to rate, comment and share\u00a0\ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Welcome back to PowerShell for Programmers, this week I&#8217;m trying gitGist again for the code blocks. Let me know what you think about it vs the normal syntax highlighter I use \ud83d\ude42 As we&#8217;ve seen in the other posts about functions, attributes are a really cool thing to extend the features we have available to [&hellip;]<\/p>\n","protected":false},"author":7300,"featured_media":87096,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1738,2126],"tags":[2221,2125,377],"class_list":["post-405","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","category-powershell_for_programmers","tag-kory-thacher","tag-koryt","tag-powershell"],"acf":[],"blog_post_summary":"<p>Welcome back to PowerShell for Programmers, this week I&#8217;m trying gitGist again for the code blocks. Let me know what you think about it vs the normal syntax highlighter I use \ud83d\ude42 As we&#8217;ve seen in the other posts about functions, attributes are a really cool thing to extend the features we have available to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/405","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\/7300"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=405"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/405\/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=405"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=405"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=405"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}