When my shell starts, I load an external script that has a few functions I use to test things. Something like:
# Include Service Test Tools
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
. $scriptPath\SvcTest.ps1
In SvcTest.ps1
, I have two functions:
function isURI ([string] $address)
{
($address -as [System.URI]).AbsoluteURI -ne $null
}
As well as:
function Test-Service ([string] $url)
{
if (-Not (isURI($url)))
{
Write-Host "Invalid URL: $url"
return
}
# Blah blah blah, implementation not important
}
The isURI
function is basically just a utility function that allows Test-Service
and perhaps other functions validate URIs. However, when I start my shell, I see that isURI
is a function loaded globally. I can even type isURI http://www.google.com
from the command line and get back True
.
My Question: Is there a way to make isURI
private, so that only functions within SvcTest.ps1
can use it, while still allowing Test-Service
to be global? Basically, I'm looking for a way to use property encapsulation within PowerShell scripts.
The dot sourcing feature lets you run a script in the current scope instead of in the script scope. When you run a script that is dot sourced, the commands in the script run as though you had typed them at the command prompt.
A module manifest is a PowerShell data file ( . psd1 ) that describes the contents of a module and determines how a module is processed. The manifest file is a text file that contains a hash table of keys and values.
If you want to execute a function from another PowerShell script file, you can “dot-source” the file. The “.” is a special operator in PowerShell that can load another PowerShell script file en import all code in it.
In fact, if you call a .ps1 file, by default any functions and variables declared within it are scoped privately within the script (this is referred to as "script scope"). Since you're seeing both functions defined globally, I infer that you're dot-sourcing SvcTest.ps1, i.e. invoking it like this
PS> . <path>\SvcTest.ps1
rather than calling it like this
PS> <path>\SvcTest.ps1
You have two options.
1. If your private function is only used by one other function in the script, you can declare the private function within the body of the function that uses it, and invoke the script by dot-sourcing it:
function Test-Service ([string] $url)
{
function isURI ([string] $address)
{
($address -as [System.URI]).AbsoluteURI -ne $null
}
if (-Not (isURI($url)))
{
Write-Host "Invalid URL: $url"
return
}
# Blah blah blah, implementation not important
}
2. If the private function is needed by more than one other function within the script (or even if not, this is an alternative to the above), explicitly declare global scope for any functions that you want defined globally, and then call the script rather than dot-sourcing it:
function isURI ([string] $address)
{
($address -as [System.URI]).AbsoluteURI -ne $null
}
function global:Test-Service ([string] $url)
{
if (-Not (isURI($url)))
{
Write-Host "Invalid URL: $url"
return
}
# Blah blah blah, implementation not important
}
In either case, Test-Service will be defined in the global scope, and isURI will be restricted to the script scope.
.
has been added to the path (which is not the case by default). So, it's typical in PowerShell when invoking scripts in the working directory to precede the script name with .\
. Don't confuse the .
representing the working directory with the dot-sourcing operator. This calls a script:
PS> .\SvcTest.ps1
This dot-sources it:
PS> . .\SvcTest.ps1
It sounds to me like you're asking for functionality that's available by creating a module.
Modules let you encapsulate code and export only desired aliases and/or functions. A module manifest is not strictly required; if you don't use a manifest, you can use Export-ModuleMember
to specify what members you want exported from the module.
See the help about_Modules
about topic for more information.
If you want to use a private scope for your function, it is done like this in Powershell.
function Private:isURI ([string] $address)
{
($address -as [System.URI]).AbsoluteURI -ne $null
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With