header
header Register : : Login header
header
divider
menuleft
menuright
submenu
left

[August 25th, 2008] Check the home page regarding PowerShell related news from a brand new sponsor: Idera

Subject: v1 Powershell and invoke-expression
Prev Next
You are not authorized to post a reply.

Author Messages
DDaigleUser is Offline
New Member
New Member
Posts:1

07/09/2008 8:30 AM  

I am trying to do a simple thing.

Construct a command line including the executable and then run it using measure-command.

Issues are the following

1)  Path to executable has spaces

2)  Several options are required with spaces between them

3)  some of the parameters 'may' require quoted arguments

the example i show is here:

'C:\Program Files\Microsoft\Exchange Server\Bin\eseutil.exe' /d  "I:\Exchange Store\SG4 DB3\Store SG4 DB3.edb" /t "I:\defrag\Store SG4 DB3.edb"

I have had a devil of time construct this command so that the SG# and the DB# where are parameters given to the script can be incorporated as the command line is constructed.

When i finally run the command its is: 

$cmdTime  = Measure-Command {invoke-expression $strRun}

 NOTE:  The current error I get is:

You must provide a value expression on the right-hand side of the '/' operator.
At line 38, position 0
$cmdTime = Measure-Command {invoke-expression $strRun}

 

EBGreenUser is Offline
New Member
New Member
Posts:18

07/09/2008 10:25 AM  

What do you see if you just Write-Host the command variable?

EBGreenUser is Offline
New Member
New Member
Posts:18

07/09/2008 10:28 AM  

You also might want to try:

 

$run = '"C:\Program Files\Microsoft\Exchange Server\Bin\eseutil.exe" /d  "I:\Exchange Store\SG4 DB3\Store SG4 DB3.edb" /t "I:\defrag\Store SG4 DB3.edb"'

halr9000User is Offline
CLI Addict
CLI Addict
Posts:245


07/09/2008 2:48 PM  
Another tshooting tool is echoargs.exe which is included with the PowerShell Community Extensions (PSCX).

As far as your command goes, try something like this:

$basecmd = "C:\Program Files\Microsoft\Exchange Server\Bin\eseutil.exe"
$cmd = $basecmd + "/d `"I:\Exchange Store\SG4 DB3\Store SG4 DB3.edb`" /t `"I:\defrag\Store SG4 DB3.edb`""

Good luck...this is the type of problem you'll have again I'm afraid. :)

Community Director, PowerShellCommunity.org
Co-host, PowerScripting Podcast (http://powerscripting.net)
Author, TechProsaic (http://halr9000.com)
PoshoholicUser is Offline
New Member
New Member
Posts:16

07/14/2008 2:42 PM  

I have a few pointers that might help you out with what you're trying to do here.

First and foremost, if you are trying to execute an application in PowerShell using a full path and that path has a space in it, you must use the call operator.  To show you what I mean, compare the results of this:

    'C:\Program Files\Microsoft\Exchange Server\Bin\eseutil.exe'

with this:

    & 'C:\Program Files\Microsoft\Exchange Server\Bin\eseutil.exe'

In the first case, PowerShell just outputs the string you gave it.  Why?  Because anything in quotes is treated as a string.  In the second case, PowerShell actually knows that your string you've entered is a path to a command you're trying to execute.  That's the purpose of the call operator in this case: to instruct PowerShell that the subsequent string is actually the path to an application you want to execute.

The same thing holds true for any path you have entered in quotes.  If you want to execute the string path as if it is an application, you need the call operator.  The error you are getting is simply trying to point out that fact, even if the error is not very clear.  Look at this:

    'Hello' /d 'Goodbye'

It will give you the same error.  PowerShell sees the first token is a string, then it finds the / operator and when it looks for a valid expression on the right of the / operator it can't find it, so it raises an error saying so.  Compare that error with the one that shows up from this command:

    'Hello' / 'Goodbye'

This will raise an error saying that strings don't support the division operator.  Maybe if PowerShell checked to see if the object on the left supported the operator and raised this error before it looked on the right hand side for a valid operand expression it would have helped you understand what is going on here.

Now, about how you're trying to build out your expression.  People instinctively gravitate towards regular strings when they want to build out commands.  It's probably the case because they think if they're trying to build a string command they need to use a string.  The problem with doing this is that you have to escape quotation marks sometimes, insert newline characters, etc, depending on what you're trying to do.  And if you're using a cool PowerShell script editor like PowerGUI, you lose the syntax highlighting and intellisense for anything you put in your string, making it easier to introduce typos and other formatting errors that would otherwise be obvious with the proper code highlighting in place.

Given that is the case, what's the alternative?  Well, there are actually two alternatives: here-strings and script blocks.  Here-strings are great when you really want to be able to see the command you are building as a string without worrying about escaping a bunch of quotes and the like.  Script blocks are great when you want to execute a command or script with certain parameters dynamically and you don't want to make a named function for it, or when you want to take an existing command or script and convert it into a string.  A script block is essentially an unnamed function.  It can accept named parameters just like a function can, and it can be output in string format if you want to see it in string format.

Armed with those alternatives, let's take a closer look at your script.  You indicated that you're trying to build out a command that uses dynamic SG numbers and DB numbers and it seems that you're trying to measure the performance of that command by using the Measure-Command cmdlet.  Here's the sort of approach I recommend you take with this using script blocks and here-strings instead of regular strings:

$scriptBlock = {
    param(
        [int]$SgNumber = $(throw 'SgNumber is a required parameter!'),
        [int]$DbNumber = $(throw 'DbNumber is a required parameter!'),
        [Switch]$OutputCommandOnly
    )
    if ($OutputCommandOnly) {
        @"
& 'C:\Program Files\Microsoft\Exchange Server\Bin\eseutil.exe' /d "I:\Exchange Store\SG$SgNumber DB$DbNumber\Store SG$SgNumber DB$DbNumber.edb" /t "I:\defrag\Store SG$SgNumber DB$DbNumber.edb"
"@
    } else {
        & 'C:\Program Files\Microsoft\Exchange Server\Bin\eseutil.exe' /d "I:\Exchange Store\SG$SgNumber DB$DbNumber\Store SG$SgNumber DB$DbNumber.edb" /t "I:\defrag\Store SG$SgNumber DB$DbNumber.edb"
    }
}

# View the commands we will run first

& $scriptBlock 1 2 -OutputCommandOnly
& $scriptBlock 3 4 -OutputCommandOnly
& $scriptBlock 5 6 -OutputCommandOnly
& $scriptBlock 7 8 -OutputCommandOnly
& $scriptBlock 9 10 -OutputCommandOnly

# Now run the commands and measure their times

$cmdTime1 = Measure-Command {& $scriptBlock 1 2}
$cmdTime2 = Measure-Command {& $scriptBlock 3 4}
$cmdTime3 = Measure-Command {& $scriptBlock 5 6}
$cmdTime4 = Measure-Command {& $scriptBlock 7 8}
$cmdTime5 = Measure-Command {& $scriptBlock 9 10}

Give that script a look and let us know how you get along.

--
Kirk Munro [MVP]
Poshoholic
http://poshoholic.com

glnsizeUser is Offline
Shell Enthusiast
Shell Enthusiast
Posts:60

07/14/2008 6:15 PM  

@poshoholic

BRAVO!   Very well put, I thought I understood it, but I never connected & was short for call... That makes SO MUCH SENSE!

~Glenn

 

You are not authorized to post a reply.
Forums > Using PowerShell > General PowerShell > v1 Powershell and invoke-expression



ActiveForums 3.7
right
   
footer Sponsored by Quest Software • SAPIEN Technologies • ShellTools, LLC • Microsoft Windows Server 2008 footer
footer