{"id":242,"date":"2020-05-08T18:26:24","date_gmt":"2020-05-08T17:26:24","guid":{"rendered":"http:\/\/192.168.8.14\/?p=242"},"modified":"2020-05-08T18:26:24","modified_gmt":"2020-05-08T17:26:24","slug":"tutorial-functions","status":"publish","type":"post","link":"https:\/\/www.jasonstreet.com\/?p=242","title":{"rendered":"Tutorial Functions"},"content":{"rendered":"\n<p>Powershell, like just about every other programming\/scripting language has functions. These functions can be simple one liners or very complicated, depending on your needs.<\/p>\n\n\n\n<p>A very simple function is show below.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nfunction Do-PrintHelloWorld\n{\n    Write-Host &quot;Hello world!&quot; -ForegroundColor Green\n}\n<\/pre><\/div>\n\n\n<p>This function has a name and a code block. It has no input and will only output to the screen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I use functions.<\/h3>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>You can wrap up commonly used code to save space\/typing and improve the readability of your scripts.<\/li><li>Functions have read only access to the scripts variables. Don&#8217;t rely on this as a method to pass data to a function.<\/li><li>Data can be passed to functions as parameters. parameters can be:<ol><li>Made compulsory.<\/li><li>Have default values set.<\/li><li>Can be forced to a certain type (string, int, object etc)<\/li><li>Can validate the incoming data.<\/li><\/ol><\/li><li>Can return (pass back) specific data back to the calling script.<\/li><li>All variables in the function are deleted when the script exits. <\/li><li>Variables in a function are not accessible to the console or ISE, so can be hard to debug.<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Using functions.<\/h3>\n\n\n\n<p>Below is a slightly more complex function.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nfunction Do-PrintStuff ($line1, $Line2 =&quot;line2&quot;)\n{\n    Write-Host $Line1 -ForegroundColor Green\n    Write-Host $Line2 -ForegroundColor Green\n}\n<\/pre><\/div>\n\n\n<p>Passing data in to a function like this is perfectly valid but not recommended. It will very quickly become hard to read. Also notice the $Line2 variable being set to &#8220;line2&#8221;. If the user does not pass a value for $Line2 it will default to &#8220;line2&#8221;.<\/p>\n\n\n\n<p>The &#8220;correct&#8221; way to write the function is this.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nfunction Do-PrintStuff \n{\n   &#x5B;CmdletBinding()]\n    param(\n        &#x5B;Parameter(Mandatory = $true,ValueFromPipeline=$true)] &#x5B;string]$line1, \n        $Line2 = &quot;This is line 2&quot;,\n        &#x5B;Parameter(Mandatory=$false)]$Line3,\n        $Line4,\n        &#x5B;Parameter()]&#x5B;ValidateRange(1,10)]&#x5B;int]$Number,\n        &#x5B;Parameter()]&#x5B;ValidateSet(&quot;jase&quot;,&quot;bob&quot;)]&#x5B;string]$Name,\n        &#x5B;Parameter()]&#x5B;ValidateScript({test-path $_})]&#x5B;string]$Path\n    )\n    Process{\n        Write-Host $Line1 -ForegroundColor Green\n        Write-Host $Line2 -ForegroundColor Green\n        Write-Host $Line3 -ForegroundColor Green\n        Write-Host $Line4 -ForegroundColor Green\n        Write-Host $Number -ForegroundColor Green\n        Write-Host $Name -ForegroundColor Green\n        Write-Host $Path -ForegroundColor Green\n    }\n}\n<\/pre><\/div>\n\n\n<p>I now have a Parameter block.  <\/p>\n\n\n\n<p>Listed are common validations I do.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>$Line1 is mandatory (powershell will prompt if its not set) and set to a string type, can also be piped in.<\/li><li>$Line2 will default to &#8220;This is line 2&#8221; if not specified.<\/li><li>$Line3 is not mandatory and not checked.<\/li><li>$Line4 is not mandatory and not checked.<\/li><li>$Number must be an integer and be between 1 to 10 inclusive.<\/li><li>$Name must be a string and can only be &#8220;jase&#8221; or &#8220;bob&#8221; (and will tab complete)<\/li><li>$Path must be a string and be a valid path. The code {test-path $_} must evaluate to true.<\/li><\/ul>\n\n\n\n<p>If any of the parameter check fails you will get a helpful error and the function will not run.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"153\" src=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/function001-1-1024x153.png\" alt=\"\" class=\"wp-image-244\" srcset=\"https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function001-1-1024x153.png 1024w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function001-1-300x45.png 300w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function001-1-768x115.png 768w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function001-1-850x127.png 850w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function001-1.png 1036w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Function output with valid inputs.<\/figcaption><\/figure>\n\n\n\n<p>Below shows the error when the name and path parameters are invalid.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"159\" src=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/function002-1024x159.png\" alt=\"\" class=\"wp-image-245\" srcset=\"https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function002-1024x159.png 1024w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function002-300x47.png 300w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function002-768x119.png 768w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function002-850x132.png 850w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function002.png 1076w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>The error tells us the -name parameter is wrong.<\/figcaption><\/figure>\n\n\n\n<p>The error states the name parameter is invalid. the function has not checked the path parameter.<\/p>\n\n\n\n<p>Fixing the name parameter and leaving path incorrect gives us:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"144\" src=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/function003-1024x144.png\" alt=\"\" class=\"wp-image-246\" srcset=\"https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function003-1024x144.png 1024w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function003-300x42.png 300w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function003-768x108.png 768w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function003-850x120.png 850w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/function003.png 1086w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Error for invalid path parameter.<\/figcaption><\/figure>\n\n\n\n<p>Again, the error is quite clear as it tells us the parameter and value that failed the check.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Getting data out of a function.<\/h3>\n\n\n\n<p>Sometimes (most of the time) you will want the function to return something back to the script that called it and not output to the screen. To do that I use the return command.<\/p>\n\n\n\n<p>Below is a function I have used i servile scripts.<\/p>\n\n\n\n<p>I will take a test string and a number. If the length of the test string is less then the number, the function will add the required number of spaces and return a new string that is (number) charictors long. Good for column formatting.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\n&lt;#\n   The function will take a text string and pad the end with spaces to make it $MaxSpace in length.\n   if the test string is to long the function will truncate it down to $MaxSpace - 3 in length and add &quot;.. &quot;\n   $testStringofLength20 = Do-FuncPadSpace $testStringOfLength10 20\n#&gt;\nfunction Do-FuncPadSpace\n{\n    Param(\n        &#x5B;Parameter(Mandatory = $true)] &#x5B;string]$DisplayText,\n        &#x5B;Parameter(Mandatory = $true)] &#x5B;int]$MaxSpace\n    )\n\n    if ($DisplayText.length -le $MaxSpace)\n    {\n        # add spaces to text to make it the correct length\n        # I should do it with a loop but its not very readable (and didn&#039;t work)\n        $spacesToAdd = $MaxSpace - $DisplayText.length\n        if ($spacesToAdd -eq 0){}\n        if ($spacesToAdd -eq 1){$Spaces = &quot; &quot;}\n        if ($spacesToAdd -eq 2){$Spaces = &quot;  &quot;}\n        if ($spacesToAdd -eq 3){$Spaces = &quot;   &quot;}\n        if ($spacesToAdd -eq 4){$Spaces = &quot;    &quot;}\n        if ($spacesToAdd -eq 5){$Spaces = &quot;     &quot;}\n        if ($spacesToAdd -eq 6){$Spaces = &quot;      &quot;}\n        if ($spacesToAdd -eq 7){$Spaces = &quot;       &quot;}\n        if ($spacesToAdd -eq 8){$Spaces = &quot;        &quot;}\n        if ($spacesToAdd -eq 9){$Spaces = &quot;         &quot;}\n        if ($spacesToAdd -eq 10){$Spaces = &quot;          &quot;}\n        if ($spacesToAdd -eq 11){$Spaces = &quot;           &quot;}\n        if ($spacesToAdd -eq 12){$Spaces = &quot;            &quot;}\n        if ($spacesToAdd -eq 13){$Spaces = &quot;             &quot;}\n        if ($spacesToAdd -eq 14){$Spaces = &quot;              &quot;}\n        if ($spacesToAdd -eq 15){$Spaces = &quot;               &quot;}\n        if ($spacesToAdd -eq 16){$Spaces = &quot;                &quot;}\n        if ($spacesToAdd -eq 17){$Spaces = &quot;                 &quot;}\n        if ($spacesToAdd -eq 18){$Spaces = &quot;                  &quot;}\n        if ($spacesToAdd -eq 19){$Spaces = &quot;                   &quot;}\n        if ($spacesToAdd -eq 20){$Spaces = &quot;                    &quot;}\n        if ($spacesToAdd -eq 21){$Spaces = &quot;                     &quot;}\n        $Result = $DisplayText + $Spaces\n        return $Result\n    }else{\n        # text to long, error!\n        $Result = $DisplayText.Substring(0,$MaxSpace - 3) + &quot;.. &quot;\n        return $Result\n    }\n}\n<\/pre><\/div>\n\n\n<p>In the above function, both if &#8220;branches&#8221; result in a string variable called $Result being populated. Once populated both &#8220;branches&#8221; end with:<\/p>\n\n\n\n<p>return $Result<\/p>\n\n\n\n<p>return $Result will end processing of the function and return whats after. in this case the $result variable.<\/p>\n\n\n\n<p>I did not technically need the return command. I could have just had $Result on the line on its own. there is no code to be run after these lines so the function would exit anyway. But I like easy to read code so I always use the return command.<\/p>\n\n\n\n<p>Calling the function would work like this.<\/p>\n\n\n\n<p>$PaddedOutString = Do-FuncPadSpace -DisplayText $TestString -MaxSpace 20<\/p>\n\n\n\n<p>That&#8217;s a quick look at functions.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Powershell, like just about every other programming\/scripting language has functions. These functions can be simple one liners or very complicated, depending on your needs. A very simple function is show below. This function has a name and a code block. It has no input and will only output to the screen. Why should I use&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[27],"tags":[17,13,22],"class_list":["post-242","post","type-post","status-publish","format-standard","hentry","category-tutorial","tag-function","tag-powershell","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/242","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=242"}],"version-history":[{"count":2,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/242\/revisions"}],"predecessor-version":[{"id":248,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/242\/revisions\/248"}],"wp:attachment":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=242"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=242"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=242"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}