Automating the world one-liner at a time…
I fixed a bug in Start-Demo (Script attached) that is worth exploring. The heart of Start-Demo is to get a line from file, display it and then run it showing the output. To do this I used Invoke-Expression (For simplicity sakes, I'm going to show you the code assuming that the line to execute is $LINE – the actual code is a bit more complicated)
Invoke-Expression $($LINE + " | out-host")
We want to run the command and pipe it's results to out-host. This "mostly" works. I noticed the failure as I started to do more complicated demos. I particular, I wanted to execute the following 2 lines:
$y = Get-Process$y | where {$_.handles –ge 500} |sort handles
When I ran the first command, it output the processes and it didn't assign anything to $y (can you guess why?). What was actually getting executed was:
$y = Get-Process | Out-Host
"Out-Host" took precedence over the "=" so the objects were getting printed on the host and nothing came out of the pipeline so $y was set to $NULL. S
From there I realized that I should run this in a script block and then pipe the results to "out-host". So I changed the code to be:
Invoke-Expression $("&{ " + $LINE + "} | out-host")
What do you think? Should that work or not?
Well, the first like worked a treat. It ran but did not output the process objects. Success right? Wrong! The second command didn't work. What happens is that when you run code inside &{}, it creates a new SCOPE for variables and runs the command in that scope. So when you run:
&{$y = Get-Process} | out-host
It runs Get-Process, assigns the objects to a local variable $Y and then exits the scope – which throws away the local variable. So then when you try to run
$y | where {$_.handles –ge 500} |sort handles
$y is null so you are out of luck. With a lesser language, you'd be hosed right now but with PowerShell, we thought of these things (even if I forgot it when I wrote this script!). So how does PowerShell help? (You'll want to put your seatbelts on for this….) You can dot-source scriptblocks!
Yup. Just as you can run a script or dot-source a script, you can run a scriptblock or dot-source it. When you run (either of these), it creates a new variable scope, executes the code, and throws away the variable scope eliminating any of the variables that were used. When you dot-source these, it runs in the current scope so any changes to variables persist after the code executes. So what is the syntax for dot-sourcing a scriptblock?
.{}
Of course.
PS> .{$y = Get-Process} | out-hostPS> .{$y |where {$_.handles -ge 500} |sort handles} | out-hostHandles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName------- ------ ----- ----- ----- ------ -- -----------510 14 18460 11640 89 10.67 940 svchost571 18 12020 13152 98 7.81 3824 taskeng641 26 35008 42644 176 117.69 2968 wmplayer648 11 5832 20856 188 28.31 512 csrss659 0 0 4592 9 4 System659 26 29248 44148 212 45.89 1900 explorer661 27 29812 25984 172 4.27 4268 iexplore674 6 1708 4240 88 4.53 456 csrss724 14 13284 15232 95 11.38 2416 CcmExec726 14 47232 37604 213 15.48 4020 powershell751 18 81692 81848 196 440.50 1044 svchost765 32 11680 15452 98 34.89 1180 svchost778 4 3024 3020 40 0.05 504 psxss1026 29 19456 16192 124 36.36 1376 svchost1047 33 47800 41620 293 42.59 2664 communicator1371 14 63896 29548 229 145.56 2184 SearchIndexer1433 19 7136 5060 57 25.31 588 lsass1796 52 159108 96184 441 158.30 4620 iexplore1890 50 37040 38284 157 127.00 1060 svchost5661 83 159676 149736 781 370.58 1128 OUTLOOK
So the correct code in the script should have been:
Invoke-Expression $(".{ " + $LINE + "} | out-host")
Enjoy!
Jeffrey Snover [MSFT]Windows PowerShell/MMC ArchitectVisit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShellVisit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx
PingBack from http://www.leedesmond.com/weblog/?p=115
Thank you that's exactly what i needed;
I am parsing a SQL file for database build automation which contains some Powershell function calls to include other sql - sources into the main-script ...
Parsing was not the problem - but executing the powershell function was not possible because the environment was re-initialized - something like a child environment of a korn-shell;
/Karl