Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Include another script, keep variables in included script?

41 views
Skip to first unread message

pschmidt

unread,
Aug 15, 2008, 5:24:05 PM8/15/08
to

I want to run or include a PS script from within another PS script. But
want the values set in the 2nd one to be available in the first one.

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,


Kryten

unread,
Aug 15, 2008, 7:40:33 PM8/15/08
to
This is just one possible way:-
(Both scripts are in my 'D:\Posh' directory.

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


Kryten

unread,
Aug 15, 2008, 7:46:43 PM8/15/08
to
Hi,
One way..

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

Kryten

unread,
Aug 15, 2008, 7:54:57 PM8/15/08
to
Hi,
One more thing I didn't mention is scope. In the
previous example, for what you are trying to do I think the
variables in tmp.ps1 will need to be defined with a global scope.
Like so:-

tmp.ps1
------------------------------
$global:Test = "Here"
$global:There = "There"
------------------------------

This makes the variables available across the entire powershell
session.

Cheers,
Stuart

Kryten

unread,
Aug 15, 2008, 7:58:05 PM8/15/08
to
Sorry about the double post.
I thought Googlegroups was playing up as my first reply didn't appear
and I thought it had gone missing so I posted again. Doh!

tojo2000

unread,
Aug 15, 2008, 9:29:28 PM8/15/08
to
On Aug 15, 2:24 pm, pschmidt <pschm...@discussions.microsoft.com>
wrote:

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.

Kiron

unread,
Aug 15, 2008, 11:18:56 PM8/15/08
to
You can export the variables to tmp2's scope:

-< tmp.ps1 >-
param ([string[]]$exportVariable)

$Test = "Here"
$There = "There"

echo "TEST: $test"
echo "There: $there"

if ($exportVariable) {
foreach ($var in $exportVariable) {
set-variable $var (get-variable $var).value -scope 1
}
}
-< tmp.ps1 >-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
-< tmp2.ps1 >-
# $test echo "TEST: $Test"

# assuming both scripts are in same Dir
$cmd = join-path (split-path $myInvocation.myCommand.path) tmp.ps1
& $cmd -ex test, there

echo "TEST: $Test"
echo "There: $there"
-< tmp2.ps1 >-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
.\tmp2

--
Kiron

tojo2000

unread,
Aug 15, 2008, 11:51:40 PM8/15/08
to

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.

Kiron

unread,
Aug 16, 2008, 12:36:12 AM8/16/08
to
Hi tojo,
In tmp.ps1 -- when the param -ExportVariable is not null -- Set-Variable sets variables in the Parent (1) scope, i.e. tmp2.ps1's scope when tmp.ps1 is called from tmp2.ps1, because the If statement does not create a child scope, so Set-Variable is not resetting the Local (0) scope variables. If instead of setting the new/exported variable in an 'Then' block you use a function/scriptblock to set it, the scope of the exported variable's scope would have to be the Grandparent's (2) because a Function/scriptblock does create a new scope.

function ev ([string[]]$vns) {
foreach ($vn in $vns) {
sv $vn ((gv $vn -s 1).value * 3) -s 2
}
}

& {
& {
$v1 = 1
if ($v1 -eq 1) {sv v1 2 -s 1}
write-host `$v1 is $v1 in the Local scope
}
write-host `$v1 is $v1 in the Parent scope
}

# no $v1 in the Global scope
$v1

& {
& {
$v1 = 1
if ($v1 -eq 1) {ev v1}
write-host `$v1 is $v1 in the Local scope
}
write-host `$v1 is $v1 in the Parent scope
}

# no $v1 in the Global scope
$v1

Jeffrey Snover explains it here:
http://blogs.msdn.com/powershell/archive/2007/04/14/controlling-the-scope-of-variables.aspx

--
Kiron

tojo2000

unread,
Aug 16, 2008, 4:54:30 AM8/16/08
to
> Jeffrey Snover explains it here:http://blogs.msdn.com/powershell/archive/2007/04/14/controlling-the-s...
>
> --
> Kiron

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.

Joel (Jaykul) Bennett

unread,
Aug 16, 2008, 11:22:17 AM8/16/08
to
On Aug 16, 4:54 am, tojo2000 <tojo2...@gmail.com> wrote:

> 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.

tojo2000

unread,
Aug 16, 2008, 1:02:59 PM8/16/08
to
On Aug 16, 8:22 am, "Joel (Jaykul) Bennett" <Jay...@huddledmasses.org>
wrote:

Yes, as long as you dotsource it at the script: scope.

Kiron

unread,
Aug 17, 2008, 3:36:38 AM8/17/08
to
Just because the code police may find the idea of importing specific variables --instead of importing every variable and define every function-- from the called script 'waaay more complicated', doesn't mean it isn't useful, and as long as someone 'gets' the concept and applies the technique, the purpose of sharing and demonstrating the power of PowerShell has been achieved.

--
Kiron

Kryten

unread,
Aug 17, 2008, 4:06:04 AM8/17/08
to
Hi Kiron,

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


tojo2000

unread,
Aug 17, 2008, 4:40:47 AM8/17/08
to

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.

Kiron

unread,
Aug 17, 2008, 5:51:14 AM8/17/08
to
> I disagree, and I'm no authority
My sarcastic reply was not to you tojo, and I'm not trying to confuse anyone, just sharing what PowerShell's versatility I know of that could be useful.

--
Kiron

Alex K. Angelopoulos at

unread,
Aug 17, 2008, 7:28:47 AM8/17/08
to
If you use the "." invocation operator instead of &, you can do this
directly. Simply change this line in tmp2:

.\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 at

unread,
Aug 17, 2008, 7:35:59 AM8/17/08
to
Never mind; I didn't read the sub-thread that Tojo started before posting
this. ; )

"Alex K. Angelopoulos" <aka(at)mvps.org> wrote in message
news:uZdDsxFA...@TK2MSFTNGP02.phx.gbl...

pschmidt

unread,
Aug 18, 2008, 12:19:00 PM8/18/08
to

Excellent info - thanks.

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

Kiron

unread,
Aug 18, 2008, 2:48:33 PM8/18/08
to
> Excellent info - thanks.

You're welcome Perry. There is also a similar way to call a function defined in a script without executing the entire script, or having to dot-source the script to define it in the caller's scope; the called function is not defined in the caller's scope either, it just executes in the called script's scope.
This sort of thing is available in v2 CTP2 through Modules. But if you, or anyone else, would like to do this in v1, I'll be glad to share it.

--
Kiron

chris...@gmail.com

unread,
Jun 28, 2016, 7:45:52 PM6/28/16
to
Use Linux. It works better for scripting, and about everything else.

Jürgen Exner

unread,
Jun 28, 2016, 8:59:07 PM6/28/16
to
On Tue, 28 Jun 2016 16:45:51 -0700 (PDT), chris...@gmail.com wrote in
microsoft.public.windows.powershell:

>On Friday, August 15, 2008 at 4:24:05 PM UTC-5, pschmidt wrote:
^^^^^^^^^^^^^^^
>> I want to run or include a PS script from within another PS script. But
[...]
>Use [...]

Do you honestly believe pschmidt has been waiting patiently all those 8
years for your reply?

At least your posting was helpful in one regard: you confirmed my
prejudices against Googliots once more.

jue
0 new messages