For example:
tmp.ps1----
$Test = "Here"
$There = "There"
echo "TEST: $test"
echo "There: $there"
------------------------
Now tmp2.ps1-------------
echo "TEST: " $Test
.\tmp.ps1
echo "TEST: " $Test
echo "There: " $there
-------------
When I run tmp2.ps1, I get:
> .\tmp2.ps1
TEST:
TEST: Here
There: There
TEST:
There:
--------------------------
I'd like the values set in 'tmp' to be available in tmp2. How do I do this?
Thx,
tmp.ps1
-----------
$Test = "Here"
$There = "There"
---------------------
tmp2.ps1
------------
&D:\Posh\tmp.ps1
" These variables and values are from tmp:"
Write-Host "$Test & $There"
----------------------------
Nowwith your current directory set as D:\Posh do
>.\tmp2.ps1
You should get:-
These variables and values are from tmp:
Here & There
Essentially just using the 'Call' Operator '&' to include the tmp.ps1
Hope this helps,
Stuart
Both tmps.ps1 and tmp2.ps1 are in my "D:\Posh" directory.
tmp.ps1 looks like:-
$Test = "Here"
$There = "There"
tmp2.ps1 looks like:-
&D:\Posh\tmp.ps1
" These variables and values are from tmp"
Write-Host "$Test & $There"
Now from PS, in the D:\Posh directory ( or whatever you are using )
do:-
>.\tmp2.ps1
You should get:-
These variables and values are from tmp:
Here & There
Check out the 'Call' Operator and dot sourcing.
Hope this helps,
Stuart
tmp.ps1
------------------------------
$global:Test = "Here"
$global:There = "There"
------------------------------
This makes the variables available across the entire powershell
session.
Cheers,
Stuart
In addition to Kryten's answer, you can use the dotsource operator to
essentially run the script in the same scope.
You can think of the dotsource operator as injecting the script into
the current scope as if it were pasted in at that location. Normally
when you run a script, any variables and functions created inside the
script are created in the script's scope, and disappear with the
script as soon as it is done running. The dotsource operator runs the
script in the current scope.
The dotsource operator is a dot '.'.
To use it you put a dot and a space before the script. In this
example my script has a single variable, $scriptvar, that is set to
true inside scriptvar.ps1:
C:\Users\timjohnson\Documents> .\scriptvar.ps1
C:\Users\timjohnson\Documents> $scriptvar
C:\Users\timjohnson\Documents> . .\scriptvar.ps1
C:\Users\timjohnson\Documents> $scriptvar
True
One caveat: since it will run the script in the current scope you
can't run the script inside a script block or the imported variables
will disappear when the scriptblock is exited. In that case you'll
have to declare your variables as global.
Here's a script I came up with for importing scripts that I use, where
I try to solve the problem of having hardcoded script names, but
because I call the dotsource operator from inside the function I have
to declare all of my functions and variables that I want to import in
the global scope: http://tasteofpowershell.blogspot.com/2008/07/importing-scripts-as-libraries-part.html
I'd be interested to hear what other people have done.
Notet: If you're using PowerShell v2 CTP2 rather than v1 then you
should read up on creating modules, which is a new feature that
resolves most of these issues.
You might want to explain a solution like that, since variable
scoping, especially with the way PowerShell lets you do it, is a
difficult concept to get used to if you haven't dealt with it before.
When you assign a variable in PowerShell, by default the variable is
created in the current scope. If you are in a script block, then at
the end of the script block that variable will go "out of scope" and
be removed. Any script blocks or function calls after a variable is
declared, though, get access to the variable defined above.
The -scope option of Set-Variable allows you to set the scope of the
variable to a specific number of levels above the current scope. If
it is in a function, then it will set itself in the script's scope
that called it, and if it's in the script's highest scope then it will
be declared in the global scope.
The caveat with this method is that if you want to maintain that kind
of granularity then you have to know how many levels above the calling
statement you want the variable to be set to ahead of time. In
general it is a good idea to avoid declaring global variables as much
as possible because you increase your chances of having the same
variable name used twice, but this is not always practical.
BTW, if you do set the same variable twice then the innermost variable
will take precedence while it is in scope, and then you will revert to
the outer-scoped variable, since Powershell always starts with the
current scope and then works its way up when looking up a variable
name.
Sweet. Thanks. The control over scope is unprecedented in PowerShell
as far as I can tell, but the potential for confusion is unprecedented
as well.
> Sweet. Thanks. The control over scope is unprecedented in PowerShell
> as far as I can tell, but the potential for confusion is unprecedented
> as well.
The problem is, the solution being offered is waaay more complicated
than what you need. It's like the game of mousetrap.
All you had to do was dot-source the second script from the first,
which makes the second script execute in the first script's scope, so
any variables it defines are left behind when it's done.
For example:
## tmp1.ps1 ############
$Test = "Here"
$There = "There"
echo "TEST: $test"
echo "There: $there"
###########################
## tmp2.ps1 ############
echo "TEST: " $Test
# a dot, a space, then the path to the second script
. .\tmp1.ps1
echo "TEST: " $Test
echo "There: " $there
###########################
That's all. no need to mess with $global, or explicit scoping or any
of that.
Yes, as long as you dotsource it at the script: scope.
Actually that was going to be my next question. If I understood
properly your method just extracts the variables from the target
script.
If so thats an awesome technique. I didn't know you could do that! But
then I am still at the "I don't even know what I don't know" stage.
I'm going to have to play around with that a bit because I have a
script that generates hostnames to IP addresses and sends output to a
text file but it would be great to call that script and just yank out
the variables without that script "following through" so to speak.
That way other ppl could use it without mucking up my personal outfile
files.
Appreciated!
Stuart
I disagree, and I'm no authority, so take it with whatever grain of
salt you need. The original question was how to call a script from
within a script and still use the variables created by that script
once it's done running. Your solution jumped to the most complicated
solution possible to the question and made several assumptions about
the problem being solved without even explaining what you were doing.
It's not that the idea of exporting a single variable is complicated
or has no value, it's that you just showed an example of a technique
that comes with a lot of caveats as a solution to a problem with a
simple solution.
.\tmp.ps1
to this:
. .\tmp.ps1
The (.) tells PowerShell to invoke script tmp.ps1 in the current scope,
instead of creating a new subscope.
"pschmidt" <psch...@discussions.microsoft.com> wrote in message
news:E720E2CB-2A98-4DE6...@microsoft.com...
"Alex K. Angelopoulos" <aka(at)mvps.org> wrote in message
news:uZdDsxFA...@TK2MSFTNGP02.phx.gbl...
The particular example the . invocation operator works fine. But I
definitely can seem some uses for exporting or declaring different scopes in
my 'called' script.
So both are very useful - thanks. Excellent info.
Perry