2

I have a .ps1 file that I run from PowerShell, the code is as follows:

$strTables = ""
$tables | ForEach-Object{            
    $strTables += "-t $_ "  
}
# $strTables = -t fisrtTable -t secondTable
dotnet ef dbcontext scaffold $strConn Npgsql.EntityFrameworkCore.PostgreSQL --context MyModel $strTables -v -f

If I put the variable $strTable in the command it does not recognise the -t parameter (but the variable $strConn does work)

Unrecognized option '-t fisrtTable -t secondTable'

If I write the tables without the variable, it works.

dotnet ef dbcontext scaffold $strConn Npgsql.EntityFrameworkCore.PostgreSQL --context MyModel -t firstTable -t secondTable -v -f

I have too many tables to do this manually. Do you know how I can concatenate variable $strTables with the dotnet command?

Thanks in advance

4
  • This has nothing to with C#, .NET or Entity Framework, it's entirely PowerShell. You need to use Invoke-Expression if you want to execute a command line from a string. Commented Aug 2, 2022 at 13:31
  • stackoverflow.com/questions/6338015/… Commented Aug 2, 2022 at 13:31
  • I tried @davidg and it works too Commented Aug 3, 2022 at 7:00
  • @DavidG, while Invoke-Expression technically works, it is generally best avoided, as there are usually superior - and safer - alternatives. Indeed, constructing the arguments as individual elements of an array is the preferable solution here. Commented Dec 2, 2022 at 21:07

1 Answer 1

3

If you construct a string such as -t foo and pass it via a variable to an external program, it is passed as a single, double-quoted argument (that is, donet will literally see "-t foo" on its command line) - and therefore won't be recognized as parameter name-value combination.

  • You must pass -t and foo separately, as elements of an array instead.

  • When you use an array as an argument for an external program, PowerShell passes the array elements as individual, space-separated arguments:

# Create an array such as '-t', 'foo', '-t', 'bar', ...
$tableArgs = 
  $tables | ForEach-Object {            
    '-t', "$_"  
  }

# Note the use of $tableArgs as-is, which causes PowerShell to pass
# e.g. ... -t foo -t bar ... behind the scenes.
dotnet ef dbcontext scaffold $strConn Npgsql.EntityFrameworkCore.PostgreSQL --context MyModel $tableArgs -v -f

To provide a simpler example: The equivalent of foo -s -o "bar baz" file1 is:

$a = @('-s', '-o', 'bar baz', 'file1') # construct the array of arguments
foo $a  # or: foo @a

As the first code snippet implies, you're free to mix explicitly specified arguments with those provided via an array.


As an aside:

  • If the array containing the argument is stored in a variable, you may alternatively use splatting, i.e yo may pass @tableArgs (@ instead of $). However, given that with external programs and arrays this is the same as passing an array (variable) directly, there is no strict advantage in doing so, though you may prefer the @ sigil for conceptual clarity.

    • However, (explicit) splatting with @ is necessary in order to pass programmatically constructed arguments to PowerShell commands, where it is more commonly based on a hashtable whose keys identify the target parameters, which enables passing named arguments.
  • On a general note: Whether or not you pass arguments literally, via variables, or by way of an array, PowerShell's passing of arguments with embedded " chars. as well as passing the empty string as an argument to external programs is broken in Windows PowerShell and PowerShell (Core) 7 up to v7.2.x, and requires workarounds - see this answer for details.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.