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

mklement0
  • 382,024
  • 64
  • 607
  • 775
abelarda
  • 45
  • 1
  • 6
  • 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. – DavidG Aug 02 '22 at 13:31
  • https://stackoverflow.com/questions/6338015/how-do-you-execute-an-arbitrary-native-command-from-a-string – DavidG Aug 02 '22 at 13:31
  • I tried @davidg and it works too – abelarda Aug 03 '22 at 07:00
  • @DavidG, while `Invoke-Expression` technically works, it is generally [best avoided](https://stackoverflow.com/a/51252636/45375), as there are usually superior - and safer - alternatives. Indeed, constructing the arguments as individual elements of an _array_ is the preferable solution here. – mklement0 Dec 02 '22 at 21:07

1 Answers1

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'; 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 advantage in doing so.

  • However, splatting 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.

mklement0
  • 382,024
  • 64
  • 607
  • 775