Why would I want to call a function that exists in a separate script?
DR. 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 F2 ($a) {Write-Host -foregroundcolor yellow “Here it is: $a”;}
Save the following code as TestFunctions.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:
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:
F2 (“This is another test. “);
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.
« Download PowerShell 2.0 Community Technology Preview (CTP) | Home | How to retrieve a list of Computer Accounts from Active Directory »
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…
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.
Gracias me ha servido de mucho!!!
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)
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.
Ok, I do have a question after all.
Is it possible to call a dot source file from a UNC?
Hi
I wanted to know how to call powershell functions that I wrote asynchronously?
any ideas?
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}
}
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 0×41306. 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.
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
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