{"id":235,"date":"2018-02-15T09:15:16","date_gmt":"2018-02-15T17:15:16","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/koryt\/?p=235"},"modified":"2020-04-29T10:04:36","modified_gmt":"2020-04-29T17:04:36","slug":"powershell-for-programmers-how-to-write-a-function-the-right-way","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/powershell-for-programmers-how-to-write-a-function-the-right-way\/","title":{"rendered":"PowerShell for Programmers: How to write a function the right way"},"content":{"rendered":"<p><span style=\"font-size: 12pt;\">Just like I mentioned in my <a href=\"https:\/\/blogs.msdn.microsoft.com\/koryt\/2018\/01\/04\/powershell-for-programmers-basic-syntax-cmdlets\/\" target=\"_blank\" rel=\"noopener noreferrer\">first post<\/a>, PowerShell supports a lot of stuff that makes it pretty easy to dive in and get stuff running. The following two examples are supported in PowerShell, but <strong><em>not<\/em><\/strong> something you should really be doing for any reusable tool set.<\/span><\/p>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:2947c922-174d-4543-985c-007ae4b6f059\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:ps decode:true \"><span style=\"font-size: 12pt;\">Function MyFunction ($P1, $P2)\r\n{\r\nWrite-host $p1 -foregroundcolor cyan\r\nWrite-host $p2 -foregroundcolor Magenta\r\n}\r\n\r\nMyFunction -P1 \"hello\" -p2 \"world\"\r\n\r\nFunction MyFunction\r\n{\r\nWrite-host $args[0] -foregroundcolor cyan\r\nWrite-host $args[1] -foregroundcolor Magenta\r\n}\r\n\r\nMyFunction \"hello\" \"world\"<\/span><\/pre>\n<p><span style=\"font-size: 12pt;\">Putting your parameters (arguments) next to the function name in parenthesis is pretty standard in most languages, but in PowerShell it will limit your functionality. Similarly, $args will stop working for you if you add some of those more useful features, but I\u2019ll show you a way to mimic the functionality on your own later.<\/span><\/p>\n<\/div>\n<p><span style=\"font-size: 12pt;\">So, how should you be writing your functions? With the param() keyword:<\/span><\/p>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:9bb2de8d-872f-48b9-8c21-9ff2a652daff\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:ps decode:true \"><span style=\"font-size: 12pt;\">Function MyFunction\r\n{\r\nparam($P1, $P2)\r\nWrite-host $p1 -foregroundcolor cyan\r\nWrite-host $p2 -foregroundcolor Magenta\r\n}<\/span><\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p><span style=\"font-size: 12pt;\">For super basic stuff, this won&#8217;t make a big difference, but for adding attributes (such as common parameters, mandatory parameters, etc) we need to use the later version. <\/span><\/p>\n<p><span style=\"font-size: 12pt;\"><strong>Get in the habit of using param() every time<\/strong>.<\/span><\/p>\n<blockquote><p><span style=\"font-size: 12pt;\">\u201cWait, shouldn\u2019t they already be mandatory?\u201d<\/span><\/p><\/blockquote>\n<p><span style=\"font-size: 12pt;\">Not in PowerShell. Let\u2019s take a look at the syntax:<\/span><\/p>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:92d53a88-9cc5-4f47-918e-fa521ff1c292\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:ps decode:true \"><span style=\"font-size: 12pt;\">get-command myfunction -Syntax<\/span><\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:cf668e8f-5d02-4772-952b-311b16b425c6\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:default decode:true\"><span style=\"font-size: 12pt;\">Myfunction [[-p1] &lt;object&gt;] [[-p2] &lt;object&gt;]<\/span><\/pre>\n<\/div>\n<p><span style=\"font-size: 12pt;\">Unlike most languages, by default everything is:<\/span><\/p>\n<ol>\n<li><span style=\"font-size: 12pt;\">optional<\/span><\/li>\n<li><span style=\"font-size: 12pt;\">positional<\/span><\/li>\n<li><span style=\"font-size: 12pt;\">assigned the generic object type<\/span><\/li>\n<\/ol>\n<p><span style=\"font-size: 12pt;\">I\u2019ll walk you through how we can change some of that stuff and get functions more like what we are used to, and I\u2019ll follow up in a later post with more details on what we can do with <u>advanced functions<\/u>. <\/span><\/p>\n<h3><span style=\"font-size: 12pt;\">Strong Typing<\/span><\/h3>\n<p><span style=\"font-size: 12pt;\">Strongly typing parameters will assign them a data type other than object in the syntax, and provide the same auto-conversion or erroring we saw in the variables section. <\/span><\/p>\n<pre class=\"lang:ps decode:true \"><span style=\"font-size: 12pt;\">Function Myfunction2\r\n{\r\nparam([int]$p1, [int]$p2)\r\n\"p1 is $p1\"\r\n\"p2 is $p2\"\r\n}\r\n\r\nget-command myfunction -Syntax\r\n\r\nMyfunction2 5.5 2.5\r\n\r\nMyfunction2 \"fred\" 4<\/span><\/pre>\n<p>&nbsp;<\/p>\n<h3><span style=\"font-size: 12pt;\">Default Values<\/span><\/h3>\n<div class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\"><span style=\"font-size: 12pt;\">Assigning default values for parameter is easy in PowerShell. If you want something to essentially be mandatory, but have a default value if nothing else is specified we can assign it right in the param() statement.<\/span><\/div>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:e1e1ddf1-aa81-43b4-ae2e-565e6a94ac33\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<p>&nbsp;<\/p>\n<pre class=\"lang:ps decode:true\"><span style=\"font-size: 12pt;\">Function Myfunction3\r\n{\r\nparam([int]$p1=2, [int]$p2=5)\r\n\"p1 is $p1\"\r\n\"p2 is $p2\"\r\n}\r\n\r\nMyfunction3 1 2\r\nMyfunction3 -p2 2\r\nMyfunction3<\/span><\/pre>\n<\/div>\n<h3><\/h3>\n<h3 class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\"><span style=\"font-size: 12pt;\">Mandatory Parameters<\/span><\/h3>\n<div><\/div>\n<div class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\"><span style=\"font-size: 12pt;\">If you want \u201cnormal\u201d mandatory parameters, we can accomplish this through .NET attributes. We\u2019ll learn about some more attributes later, but if things being optional is frustrating you right now, here is how to flag it as mandatory. Notice in PowerShell the mandatory flags will prompt the user when using it interactively instead of just failing. We\u2019ll just make $p1 mandatory here:<\/span><\/div>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:bac1e504-7b96-489a-ad01-f2ff8005d520\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<p>&nbsp;<\/p>\n<pre class=\"lang:ps decode:true \"><span style=\"font-size: 12pt;\">Function Myfunction4\r\n{\r\nparam([parameter(Mandatory)][int]$p1,\r\n[int]$p2=5)\r\n\"p1 is $p1\"\r\n\"p2 is $p2\"\r\n}\r\n\r\nGet-command myfunction4 -syntax\r\n\r\nMyfunction4 1 2\r\nMyfunction4 -p2 2\r\nMyfunction4<\/span><\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p><span style=\"font-size: 12pt;\">Well that\u2019s all for now, hopefully this helps you get going on your PowerShell journey and clear up why functions might look and behave a bit differently than you\u2019re used to. In my next post I\u2019ll show some more attributes we can use to build out these advanced functions and have them behave like cmdlets. <\/span><\/p>\n<p><span style=\"font-size: 12pt;\">For the main series post, check back <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/powershell-for-programmers-a-quick-start-guide\/\">here.<\/a><\/span><\/p>\n<p><span style=\"font-size: 12pt;\">If you find this helpful don&#8217;t forget to rate, comment and share \ud83d\ude42<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Just like I mentioned in my first post, PowerShell supports a lot of stuff that makes it pretty easy to dive in and get stuff running. The following two examples are supported in PowerShell, but not something you should really be doing for any reusable tool set. Function MyFunction ($P1, $P2) { Write-host $p1 -foregroundcolor [&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],"class_list":["post-235","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","category-powershell_for_programmers","tag-kory-thacher","tag-koryt"],"acf":[],"blog_post_summary":"<p>Just like I mentioned in my first post, PowerShell supports a lot of stuff that makes it pretty easy to dive in and get stuff running. The following two examples are supported in PowerShell, but not something you should really be doing for any reusable tool set. Function MyFunction ($P1, $P2) { Write-host $p1 -foregroundcolor [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/235","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=235"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/235\/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=235"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=235"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=235"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}