Why would I want to call a function that exists in a separate script?

By Jesse Hamrick • January 9th, 2008

Tom MoreauDR. Tom Moreau posed the following question, “Is there a way to call a function that resides in a separate script, along the lines of Perl’s use statement? I don’t want to have to load each function script manually into the current PS session.”

I said sure, take a look at my article on organizing script code and calling functions using dot sourcing.

Tom’s response, “That’s close to what I’d like. Ideally, I’d like to refer to the script name just once and then refer to the functions therein as required. I’m wondering what to do if I have a .PS1 script that contains multiple functions and I want to execute a specific function within that PS1 script.”

What a great idea. To have a PowerShell script that contains multiple functions in which specific functions could be called from other scripts. How do we do this?

Tom came up with the answer and is gracious enough to share with the rest of us. The best way to explain it is to show some examples. First we will create a .ps1 script file that contains the functions we are going to use:

Save the following code as Functions.ps1

function F1 ($a) {Write-Host “Here it is: $a”;}
function F2 ($a) {Write-Host -foregroundcolor yellow “Here it is: $a”;}

Save the following code as TestFunctions.ps1

. C:\MyScripts\Functions.ps1

F1 (“This is a test. “);
F2 (“This is another test. “);

Before running the TestFunctions.ps1 script, note that the script is using dot source to access the Functions.ps1 script file. I’ve used the full path for the location of Functions.ps1. If both scripts are located in the same folder you can shorten your path statement as follows:

. .\Functions.ps1
Function Results

Results

Running the TestFunctions.ps1 script should yield these results:

As expected the TestFunctions.ps1 script ran both the F1 and F2 functions defined in the Functions.ps1 script. Here is where it gets interesting. Let’s say we only want to run the F2 function, we just need to modify the code in the TestFunctions.ps1 script:

. C:\MyScripts\Functions.ps1

F2 (“This is another test. “);

Function Results Modified

Results

Run the TestFunctions.ps1 script again. Does your output look like this?

When I ran these examples provided by Tom, my only thought was “how sick is that!”

Here are some benefits:

  • I can store multiple functions in a single script file and call specific functions when needed. Great way to build and use your code library.
  • I can call functions that I’ve used in other scripts without having to re-write them in a current session.

Again, a big thanks to Tom Moreau for sharing and expanding our knowledge on the possibilities of PowerShell.

Email This Post To A Friend Email This Post To A Friend

Be Sociable, Share!

Comments

Be careful with those parentheses. You don’t use parens to provide parameters to functions or cmdlets, only methods. Parens in the examples above are actually sub-expressions. Luckily, the sub-expression was just a string so it ended up doing what you had planned. Here’s how you can prove that it’s a sub-expression:

F1 (“test”) # output of the sub-expression is the string “test”
F1 ( 2+5 ) # output is the INT 7.
F1 ( dir ) # that would get incredibly messy

Unless you need sub-expressions, it’s best to leave off the parens. The below would just send the corresponding strings to the function.

F1 “test”
F1 “2+5”
F1 “dir”

This doesn’t work…

I could not get the example to work either. I continually get the error is not recognized as a cmdlet, function, operable program or script file.

Any thoughts or ideas? This would be a great tool if I could get it to work.

I tested the code and it is still working.
The reason you are getting “Not Recognized as a Cmdlet, Function…” error is because you are attempting to run the script by just calling the name. Example – PS C:\MySripts>testFunctions.ps1. You need to use dot-notation to run scripts in PowerShell. This is how your command line should look (without the quotes):
“PS C:\MyScripts>.\testFunctions.ps1”
Note the differences between both.
Hope that helps…

By Iain Spirit on August 21st, 2008 at 8:10 am

Scripts work fine.
Really enjoying going through this, time to move on from DOS. Can’t wait for the later chapters!

Hi,
I too am getting the error is not recognized as a cmdlet, function, operable program or script

BUT the system is complaining about the call to the “functions” file when we use the ..\ functions.ps1. It works fine with the . and the fully qualified name but doesnt seem to like the relative path notation
ANy ideas?

Hi,
Ok,i solved the problem.. when not qualifying the full path the line is actually

.(space).\functions.ps1

I was reading it as .. (two dots in succession )

– thanks

What if I wanted a function that returned a value so that I could pass it to another function? Can you show how I would do that?

If you wanted to take it one step further for a Functions library, you could put the file in the PSHome dir (usually “C:\WINDOWS\system32\WindowsPowerShell\v1.0” or look at $PSHome) and then you would only have to use “. Functions.ps1” w/o the quotes, of course, and don’t forget the space after the ‘.’ Hope that helps.

It broke up my example…it would be
“. Functions.ps1” (w/o the quotes)

Yesm hte “. .” thing was stoping me to call the functions. Putting it this way will keep the context open and the functions will remain visible.
Thanks Benjy!

and thatnks for trying to explain to the author.

By phghost on May 8th, 2009 at 2:08 pm

Gracias me ha servido de mucho!!!

By Chris Allen on July 24th, 2009 at 7:18 am

I would like to use dot sourcing to pull from a list of functions, but I would also like to be able to run the script with external parameters. Normally, functions have to be declared at the top of the script as does your Param() statement. These seem to compete with each other. The one that is at the top wins, the other is either ignored or produces an error.

So, If I wanted to pass a parameter into a script (I.E. .\test.ps1 -lanid dude123) how would I be able to use that and still dot source my functions?

. C:\MyScripts\Functions.ps1
Param($lanid)

By Chris Allen on July 24th, 2009 at 7:27 am

Never mind. I figured it out. With dot sourcing, the functions do not have to be absolute top of the script.

As a test, I created the function file below with a simple get-mailbox shortcut called getMB.

Then created a script called test.ps1 which looks as follows:

Param($lanid)
. C:\MYScripts\Functions.ps1
getmb $lanid

Putting the Param before the dot source call works perfectly. I ran .\Test -lanid dude123 and it returned the proper results.

By Chris Allen on July 24th, 2009 at 10:13 am

Ok, I do have a question after all.

Is it possible to call a dot source file from a UNC?

By Mostafa Mokhtar on October 14th, 2009 at 6:12 pm

Hi

I wanted to know how to call powershell functions that I wrote asynchronously?
any ideas?

By Marc Trotter on March 13th, 2010 at 10:56 am

Is there a way to loop through subfolders and call a script named run.ps1 from below each folder. I’m fairly new to powershell and can’t get this to work. As presently written it simply treats the file as a literal string, not really what I’m after.

I want to place a script and all supporting files in a subfolder and then loop through each subfolder and call run.ps1. This is what I presently do with CMD files, that way when I no longer need a module we just delete the folder. Similarly if I need to add a module I just drop in a new folder. I don’t want to edit the calling script, if I can avoid it.

Here’s what I have:

$list = Get-ChildItem C:\APPS\SCRIPTS -exclude maintenance.ps1 | Sort-Object Name

foreach ($i in $list)
{
Write-Host “Processing ” $i”…”
$sScript = [STRING]$i + “\run.ps1”
# this line works
.{c:\apps\scripts00_Critical\run.ps1}
# this line doesn’t work
.{$sScript}
}

By Eric Duncan on April 9th, 2010 at 10:44 am

This is great but I have an issue: Using the example above, the first script (which has the function) also launches a new powershell.exe instance, the second script in the new instance does not seem to be able to call the function in the first script. Is there a way around this?

Eric,
If you want functions available to every instance of Powershell.exe, I think you would have to put them your profile files or dot source them in your profile files. Type
help profile
in Powershell to learn about the profile files.

Hi Jesse!

I am currently reorganizing my scripts to your function approach.
I just want to know if you can tell me where to insert the

Start-SPAssignment -Global
Stop-SPAssignment -Global

commands. As of before, I placed the start right at the beginning of each of my scripts and the stop at the very end. Where do I place them in a .ps1 file filled with functions? Is it in each functions beginning and end or just at the beginning and end of the .ps1 file, thereby maybe encapsulating all functions?

with kind regards,
Andy

When i use the . method to include a script with functions all works fine until I run it with task scheduler (Server 2008 R2). All scripts then end with a 0x41306. Before I used the . to incldude functions the tasks worked fine. Running them directly is fine too.

That’s how I include my functions
. \\servername\scripts$\library.ps1

Do you have any idea how I can get this to work with the task scheduler?

Cheers
Joachim

Hey, I wonder can I use this on StrageyDesk from TD Ameritrade.
I am trying to build a libuary of routeens and functions and call them with out putting all in the editor.

I am trying to call another script responsible to send a mail. however, when I put ‘send email logic’ inside a function
it is not working or more precisely it is running but not receiving the email. when the send email logic is not in a function (just written in the script), it is actually working. here is the code

not working code
function send($from,$to)
{
try
{
$messageParameters = @{
smtpServer = “smtphost”
From = $from
To = $to
Subject = ”You Submitted a Job”
Body = ”You Job Chain is submitted successfully”
}
Send-MailMessage @messageParameters -BodyAsHtml
}
catch
{
write-host “======================================================================” -ForegroundColor green
write-host ‘sending email is failed’ -ForegroundColor green
write-host “======================================================================” -ForegroundColor green
}
}

and the working code is

try
{
$messageParameters = @{
smtpServer = “smtphost”
From = $from
To = $to
Subject = ”You Submitted a Job”
Body = ”You Job Chain is submitted successfully”
}
Send-MailMessage @messageParameters -BodyAsHtml
}
catch
{
write-host “======================================================================” -ForegroundColor green
write-host ‘sending email is failed’ -ForegroundColor green
write-host “======================================================================” -ForegroundColor green
}

I’m not sure if anyone is still reading this thread, but another option is to include your favorite functions as global functions in the profile file. This way the functions are always available within the PS environment and do not need to be sourced in each script. Of course, this should only be done for those functions to which you frequently need access.

To find the profile file, check the value of $profile.

Add your functions with the global desgination:

Function Global:myFunction($var1,$var2){
#Do something here
Return $result
}

Import-Module also allows to do this.

By Howardhemtil on May 29th, 2012 at 5:18 pm

hi there tommy if your still around this is there contact
and some info , they have a wealth of knowledge ,tell them Howardsy give you there number

By martinabinaford on August 5th, 2012 at 4:24 pm

you ok paul i shouldnt give it out but here is there link
and details, they have 20% discount now,just say miss binaford said you would sort him out

 

Leave a Comment

« | Home | »