{"id":55043,"date":"2008-10-02T11:07:00","date_gmt":"2008-10-02T11:07:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/10\/02\/hey-scripting-guy-how-can-i-reuse-functions\/"},"modified":"2008-10-02T11:07:00","modified_gmt":"2008-10-02T11:07:00","slug":"hey-scripting-guy-how-can-i-reuse-functions","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-reuse-functions\/","title":{"rendered":"Hey, Scripting Guy! How Can I Reuse Functions?"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\" \/> <\/p>\n<p>Hey, Scripting Guy! I have a bunch of functions I wrote in PowerShell that I would like to use in other scripts. I am getting tired of cutting and pasting these things into various scripts over and over again. Surely there has got to be an easier way to do this! Have any ideas?<\/p>\n<p>&#8211; JB<\/p>\n<p><img decoding=\"async\" height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\" \/><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\" \/> <\/p>\n<p>Hi JB,<\/p>\n<p>Of course, I have an idea\u2026and don\u2019t call me Shirley. So you have written a bunch of functions and you would like to reuse them in other scripts. Code reuse is a great idea. It is what I call an environmental approach to scripting (shamelessly stolen from the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Waste_hierarchy\">waste hierarchy<\/a>): Reduce the amount of work, recycle your code, and reuse your functions. As you mentioned, the easiest way to do this is to simply copy and paste the function from one script into another script. Suppose you have a script that contains code that will perform a conversion from Celsius to Fahrenheit, and you wish to use the algorithm to create another script with different capabilities. You can simply write your script, and copy the code from your other script. If you did, you would come up with something that looks like this script (we\u2019ll call it <b>ConvertToFahrenheit.ps1<\/b>):&nbsp;): <\/p>\n<pre class=\"codeSample\">Param($Celsius)\nFunction ConvertToFahrenheit($Celsius)\n{\n \"$Celsius Celsius equals $((1.8 * $Celsius) + 32) Fahrenheit\"\n} #end ConvertToFahrenheit\nConvertToFahrenheit($Celsius)<\/pre>\n<p>There is nothing really wrong with this script. It does one thing, and it does it pretty well. To use the script, we supply a command-line parameter. The good thing is that we do not need to type the entire parameter name when calling the script. This is seen&nbsp;here: <\/p>\n<pre class=\"codeSample\">PS C:\\&gt; C:\\ScriptingGuys\\ConvertToFahrenheit.ps1 -c 24\n24 celsius equals 75.2 fahrenheit<\/pre>\n<p>So with this <a href=\"http:\/\/en.wikipedia.org\/wiki\/Bonzer\">bonzer<\/a> (I am learning Australian <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/australia2008\/dispatch1.mspx\">while I am down under <\/a>) script, why would we ever want to do anything else? Well, suppose you were a Microsoft Scripting Guy and you were hanging out in Australia for a month. You might need to be able to do more metric conversions than simply Celsius to Fahrenheit. You might actually want to write several different scripts that use one or more conversion functions that you might write. Now suppose you misspell the word &#8220;Celsius&#8221; in your function. If you then decide you wish to correct it, you would need to identify every place where the misspelled word occurs, and then correct it. Or suppose you decide you want temperature to be displayed only to two decimal points. Here again you would need to find all instances of the function and make the change, or else you would end up with many slightly different versions of the functions. <\/p>\n<p>What is the solution? One approach is to place all your functions in a single script. Maybe you make a script such as the one seen here (we\u2019ll call it <b>ConversionFunctions.ps1<\/b>):&nbsp;): <\/p>\n<pre class=\"codeSample\">Function ConvertToMeters($feet)\n{\n  \"$feet feet equals $($feet*.31) meters\"\n} #end ConvertToMeters\nFunction ConvertToFeet($meters)\n{\n \"$meters meters equals $($meters * 3.28) feet\"\n} #end ConvertToFeet\nFunction ConvertToFahrenheit($celsius)\n{\n \"$celsius celsius equals $((1.8 * $celsius) + 32 ) fahrenheit\"\n} #end ConvertToFahrenheit\nFunction ConvertTocelsius($fahrenheit)\n{\n \"$fahrenheit fahrenheit equals $( (($fahrenheit - 32)\/9)*5 ) celsius\"\n} #end ConvertTocelsius\nFunction ConvertToMiles($kilometer)\n{\n  \"$kilometer kilometers equals $( ($kilometer *.6211) ) miles\"\n} #end convertToMiles\nFunction ConvertToKilometers($miles)\n{\n  \"$miles miles equals $( ($miles * 1.61) ) kilometers\"\n} #end convertToKilometers<\/pre>\n<p>If we need to use one of the conversion functions, we would include it in the script by placing a period in front of the path to the script. When we include the script containing the conversion functions, we now have access to all the functions and can use them directly as if they were in the actual file itself. The <b>ConvertToFahrenheit_Include.ps1<\/b> script illustrates this technique. We are still using the command-line parameter <b>$celsius<\/b> to supply the temperature we wish to convert. We then use the period followed by the path to the script for the include file. Last, we call the function by name and supply it with the value that came into the script via the command line. The revised <b>ConvertToFahrenheit.ps1<\/b> script is seen here: <\/p>\n<p>You can see that the script is much cleaner and it is less cluttered. Because of the minimized clutter, the script is easier to read. And because it is easier to read, the script is easier to understand and will therefore be easier to maintain. There are, of course, two downsides to this equation. The first is that the two scripts are now married. A change in one script could affect a change in the other script. More importantly, however, is that both scripts now must travel together as both are now needed to have a single working script. This outside dependency can become rather difficult to troubleshoot if you are not expecting it or have not planned for it. <\/p>\n<p>One way we can make the script easier to troubleshoot is to use the <b>Test-Path<\/b> cmdlet to determine if the include file is present. If the include file is missing, we can generate a message to that effect. This will alert us to the missing file and simplify the troubleshooting scenario. As a best practice, I always recommend using the <b>Test-Path<\/b> cmdlet whenever you use the include file scenario. The revised <b>ConvertToFahrenheit_Include2.ps1<\/b> script illustrates this technique and is seen&nbsp;here: <\/p>\n<pre class=\"codeSample\">Param($Celsius)\n$includeFile = \"c:\\data\\scriptingGuys\\ConversionFunctions.ps1\"\nif(!(test-path -path $includeFile))\n  {\n   \"Unable to find $includeFile\"\n   Exit\n  }\n. $includeFile\nConvertToFahrenheit($Celsius) <\/pre>\n<p>As you can see, this begins to be a bit ridiculous. We have a nine line script to allow us to use a three line function. You have to make the call if you want to use the include file or not. When writing a more substantial script that uses an included file, the payoff in terms of simplicity and actual code length becomes more evident. In the <b>ConvertUseFunctions.ps1<\/b> script, we create a function named <b>ParseAction<\/b> that evaluates the action and value that is supplied from the command line. It then calls the appropriate function. The <b>ConvertUseFunctions.ps1<\/b> script is seen&nbsp;here: <\/p>\n<pre class=\"codeSample\">Param($action,$value,[switch]$help)\nFunction GetHelp()\n{\n  if($help)\n  {\n   \"choose conversion: M(eters), F(eet) C(elsius),Fa(renheit),Mi(les),K(ilometers) and value\"\n   \" Convert -a M -v 10 converts 10 meters to feet.\"\n  } #end if help\n} #end getHelp\nFunction GetInclude()\n{\n $includeFile = \"c:\\data\\scriptingGuys\\ConversionFunctions.ps1\"\n if(!(test-path -path $includeFile))\n   {\n    \"Unable to find $includeFile\"\n    Exit\n   }\n. $includeFile\n} #end GetInclude\nFunction ParseAction()\n{ \n switch ($action)\n {\n  \"M\" { ConvertToFeet($value) }\n  \"F\"  { ConvertToMeters($value) }\n  \"C\" { ConvertToFahrenheit($value) }\n  \"Fa\" { ConvertToCelsius($value) }\n  \"Mi\" { ConvertToKilometers($value) }\n  \"K\"  { ConvertToMiles($value) }\n  DEFAULT { \"Dude illegal value.\" ; GetHelp ; exit }\n } #end action\n} #end ParseAction\n# *** Entry Point ***\nIf($help) { GetHelp ; exit }\nif(!$action) { \"Missing action\" ; GetHelp ; exit }\nGetInclude\nParseAction<\/pre>\n<p>One thing to keep in mind is that we needed to make a change to the include file. Because we are loading the functions from within a function, the functions are scoped by default into that function. They are not available from a different function\u2014only from child items. To avoid the inheritance issue, we added a script tag to each function when we created it. This script tag is seen here: <\/p>\n<pre class=\"codeSample\">Function Script:ConvertToMeters($feet)\n{\n  \"$feet feet equals $($feet*.31) meters\"\n} #end ConvertToMeters<\/pre>\n<p>JB, I hope this helps to explain how to reuse code in your scripts. And remember that recycling is not just for the curbside.<\/p>\n<p><font class=\"Apple-style-span\" face=\"Verdana\" size=\"3\"><span class=\"Apple-style-span\"><b><b>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/b><\/b><\/span><\/font><\/p>\n<p><font class=\"Apple-style-span\" face=\"Verdana\" size=\"3\"><b><\/b><\/font><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hey, Scripting Guy! I have a bunch of functions I wrote in PowerShell that I would like to use in other scripts. I am getting tired of cutting and pasting these things into various scripts over and over again. Surely there has got to be an easier way to do this! Have any ideas? [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[69,51,2,3,4,45],"class_list":["post-55043","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-functions","tag-getting-started","tag-running","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Hey, Scripting Guy! I have a bunch of functions I wrote in PowerShell that I would like to use in other scripts. I am getting tired of cutting and pasting these things into various scripts over and over again. Surely there has got to be an easier way to do this! Have any ideas? [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55043","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\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=55043"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55043\/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=55043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=55043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=55043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}