Como você pode usar a propriedade de um object em uma cadeia de aspas duplas?

Eu tenho o seguinte código:

$DatabaseSettings = @(); $NewDatabaseSetting = "" | select DatabaseName, DataFile, LogFile, LiveBackupPath; $NewDatabaseSetting.DatabaseName = "LiveEmployees_PD"; $NewDatabaseSetting.DataFile = "LiveEmployees_PD_Data"; $NewDatabaseSetting.LogFile = "LiveEmployees_PD_Log"; $NewDatabaseSetting.LiveBackupPath = '\\LiveServer\LiveEmployeesBackups'; $DatabaseSettings += $NewDatabaseSetting; 

Quando tento usar uma das propriedades em um comando execute string:

 & "$SQlBackupExePath\SQLBackupC.exe" -I $InstanceName -SQL ` "RESTORE DATABASE $DatabaseSettings[0].DatabaseName FROM DISK = '$tempPath\$LatestFullBackupFile' WITH NORECOVERY, REPLACE, MOVE '$DataFileName' TO '$DataFilegroupFolder\$DataFileName.mdf', MOVE '$LogFileName' TO '$LogFilegroupFolder\$LogFileName.ldf'" 

Ele tenta apenas usar o valor de $DatabaseSettings em vez do valor de $DatabaseSettings[0].DatabaseName , que não é válido.
Minha solução é tê-lo copiado para uma nova variável.

Como posso acessar a propriedade do object diretamente em uma sequência de aspas duplas?

Quando você colocar um nome de variável em uma cadeia de aspas duplas, ele será substituído pelo valor dessa variável:

 $foo = 2 "$foo" 

torna-se

 "2" 

Se você não quer que você tenha que usar aspas simples:

 $foo = 2 '$foo' 

No entanto, se você deseja acessar propriedades ou usar índices em variables ​​em uma cadeia de aspas duplas, inclua essa subexpressão em $() :

 $foo = 1,2,3 "$foo[1]" # yields "1 2 3[1]" "$($foo[1])" # yields "2" $bar = "abc" "$bar.Length" # yields "abc.Length" "$($bar.Length)" # yields "3" 

O Powershell apenas expande as variables ​​nesses casos, nada mais. Para forçar a avaliação de expressões mais complexas, incluindo índices, propriedades ou até mesmo cálculos completos, você tem que include aqueles no operador de subexpressão $( ) que faz com que a expressão dentro seja avaliada e incorporada na string.

@Joey tem a resposta correta, mas apenas para adicionar um pouco mais a respeito de por que você precisa forçar a avaliação com $() :

Seu código de exemplo contém uma ambigüidade que aponta para o motivo pelo qual os criadores do PowerShell escolheram limitar a expansão a meras referências de variables ​​e também não suportam o access a propriedades (como um aparte: a expansão de string é feita chamando o método ToString() no object, o que pode explicar alguns resultados “ímpares”).

Seu exemplo contido no final da linha de comando:

 ...\$LogFileName.ldf 

Se as propriedades dos objects fossem expandidas por padrão, o acima seria resolvido para

 ...\ 

como o object referenciado por $LogFileName não teria uma propriedade chamada ldf , $null (ou uma string vazia) seria substituída pela variável.

@Joey tem uma boa resposta. Existe uma outra maneira com uma aparência mais .NET com um equivalente String.Format, eu prefiro ao acessar propriedades em objects:

Coisas sobre um carro:

 $properties = @{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; } 

Crie um object:

 $car = New-Object -typename psobject -Property $properties 

Interpolar uma string:

 "The {0} car is a nice {1} that is {2}" -f $car.color, $car.type, $car.package 

Saídas:

 # The red car is a nice sedan that is fully loaded 

Nota da documentação: Get-Help about_Quoting_Rules cobre a interpolação de strings, mas, a partir do PSv5, não é aprofundada.

Para complementar a resposta útil de Joey com um resumo pragmático da expansão de strings do PowerShell (interpolação de strings em strings com aspas duplas , incluindo em strings aqui entre aspas duplas):

  • Somente referências como $foo , $global:foo (ou $script:foo , …) e $env:PATH (variables ​​de ambiente) são reconhecidas quando incorporadas diretamente em uma string "..." – ou seja, somente a própria referência de variável é expandida, independentemente do que se segue.

    • Para desambiguar um nome de variável dos caracteres subseqüentes na string, coloque-o em { e } ; por exemplo, ${foo} .
      Isso é especialmente importante se o nome da variável for seguido por:, como o PowerShell consideraria tudo entre o $ e o : um especificador de escopo , geralmente causando falha na interpolação; por exemplo, "$HOME: where the heart is." quebras, mas "${HOME}: where the heart is." funciona como pretendido.
      (Alternativamente, ` -escape the : "$HOME`: where the heart is." ).

    • Para tratar um $ ou um " como um literal , prefixe-o com escape char.` (Um backtick ); por exemplo:
      "`$HOME's value: `"$HOME`""

  • Para qualquer outra coisa, incluindo o uso de subscritos de matriz e acessar as propriedades de uma variável de object, você deve colocar a expressão em $(...) , o operador de subexpressão (por exemplo, "PS version: $($PSVersionTable.PSVersion)" ou "1st el.: $($someArray[0])" )

    • Usar $(...) permite até mesmo embutir a saída de linhas de comando inteiras em strings com aspas duplas (por exemplo, "Today is $((Get-Date).ToString('d'))." ).
  • Os resultados da interpolação não parecem necessariamente os mesmos do formato de saída padrão (o que você veria se imprimisse a variável / subexpressão diretamente no console, por exemplo, que envolve o formatador padrão; consulte Get-Help about_format.ps1xml ):

    • Coleções , incluindo arrays, são convertidas em strings colocando um único espaço entre as representações de string dos elementos (por padrão; um separador diferente pode ser especificado definindo $OFS ) Ex., "array: $(@(1, 2, 3))" array: 1 2 3

    • Instâncias de qualquer outro tipo (incluindo elementos de collections que não são collections) são estipuladas chamando o método IFormattable.ToString() com a cultura invariável , se o tipo da instância suportar a interface IFormattable [1] , ou chamando .psobject.ToString() , que na maioria dos casos simplesmente invoca o método .ToString() do tipo .NET subjacente [2] , que pode ou não dar uma representação significativa: a menos que um tipo (não primitivo) tenha especificamente substituído o .ToString() método, tudo o que você vai conseguir é o nome do tipo completo (por exemplo, "hashtable: $(@{ key = 'value' })" rendimentos hashtable: System.Collections.Hashtable ).

    • Para obter a mesma saída que no console , use uma subexpressão e .Trim() para Out-String e aplique .Trim() para remover qualquer linha vazia à esquerda e à direita, se desejado; por exemplo,
      "hashtable:`n$((@{ key = 'value' } | Out-String).Trim())" rendimentos:

       hashtable: Name Value ---- ----- key value 

[1] Esse comportamento talvez surpreendente significa que, para tipos que suportam representações sensíveis à cultura, $obj.ToString() produz uma representação apropriada da cultura atual , enquanto que "$obj" (interpolação de string) sempre resulta em uma invariante de cultura representação – veja esta minha resposta .

[2] Substituições notáveis:
* O anteriormente discutido stringification de collections (lista de elementos separados por espaços em vez de algo como System.Object[] ).
* A representação hashtable de instâncias [pscustomobject] (explicadas aqui ) em vez da string vazia .