Как вы можете использовать свойство объекта в строке в двойных кавычках?
У меня есть следующий код:
$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;
Когда я пытаюсь использовать одно из свойств в строке выполнения команды:
& "$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'"
Он пытается просто использовать значение $DatabaseSettings
а не ценность $DatabaseSettings[0].DatabaseName
, который не действителен.
Мой обходной путь - скопировать его в новую переменную.
Как я могу получить доступ к свойству объекта напрямую в строке в двойных кавычках?
5 ответов
Когда вы заключаете имя переменной в строку в двойных кавычках, она будет заменена значением этой переменной:
$foo = 2
"$foo"
становится
"2"
Если вы не хотите, чтобы вы использовали одинарные кавычки:
$foo = 2
'$foo'
Однако, если вы хотите получить доступ к свойствам или использовать индексы для переменных в строке в двойных кавычках, вы должны заключить это подвыражение в $()
:
$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"
Powershell только расширяет переменные в этих случаях, не более того. Для принудительной оценки более сложных выражений, включая индексы, свойства или даже полные вычисления, вы должны заключить их в оператор подвыражения. $( )
что вызывает выражение внутри, чтобы быть оцененным и встроенным в строку.
Документация примечание: Get-Help about_Quoting_Rules
охватывает интерполяцию строк, но, начиная с PSv5, не является углубленным.
Чтобы дополнить полезный ответ Джои прагматической сводкой о раскрытии строк в PowerShell (интерполяция строк в строках в двойных кавычках, в том числе в строках в двойных кавычках):
Только ссылки, такие как
$foo
,$global:foo
(или же$script:foo
, ...) а также$env:PATH
(переменные окружения) распознаются при непосредственном внедрении в"..."
строка - то есть раскрывается только сама ссылка на переменную, независимо от того, что следует.Чтобы устранить неоднозначность имени переменной из последующих символов в строке, заключите его в
{
а также}
; например,${foo}
,
Это особенно важно, если за именем переменной следует:
в противном случае PowerShell будет рассматривать все между$
и:
спецификатор области действия, обычно вызывающий сбой интерполяции; например,"$HOME: where the heart is."
ломается, но"${HOME}: where the heart is."
работает как задумано.
(В качестве альтернативы,`
-создание:
:"$HOME`: where the heart is."
).Лечить
$
или"
как буквальный, префикс это с escape-символом.`
(обратный удар); например:"`$HOME's value: `"$HOME`""
Для чего-либо еще, включая использование индексов массива и доступ к свойствам объектной переменной, вы должны заключить выражение в
$(...)
оператор подвыражения (например,"PS version: $($PSVersionTable.PSVersion)"
или же"1st el.: $($someArray[0])"
)- С помощью
$(...)
даже позволяет встраивать вывод из целых командных строк в строки в двойных кавычках (например,"Today is $((Get-Date).ToString('d'))."
).
- С помощью
Результаты интерполяции не обязательно выглядят так же, как и выходной формат по умолчанию (что вы увидите, если вы распечатаете переменную / подвыражение, например, непосредственно в консоли, к которой относится форматтер по умолчанию; см.
Get-Help about_format.ps1xml
):Коллекции, включая массивы, преобразуются в строки, помещая один пробел между строковыми представлениями элементов (по умолчанию; другой разделитель можно указать, установив
$OFS
) Например,"array: $(@(1, 2, 3))"
доходностьarray: 1 2 3
Экземпляры любого другого типа (включая элементы коллекций, которые не являются самими коллекциями) подвергаются строковому определению путем вызова
IFormattable.ToString()
метод с инвариантной культурой, если тип экземпляра поддерживаетIFormattable
интерфейс [1] или по телефону.psobject.ToString()
, который в большинстве случаев просто вызывает базовый тип.NET.ToString()
метод [2], который может давать или не давать значимое представление: если (не примитивный) тип специально не переопределил.ToString()
метод, все, что вы получите, это полное имя типа (например,"hashtable: $(@{ key = 'value' })"
доходностьhashtable: System.Collections.Hashtable
).Чтобы получить тот же вывод, что и в консоли, используйте подвыражение и канал для
Out-String
и применить.Trim()
при необходимости удалить любые начальные и конечные пустые строки; например,"hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"
выходы:hashtable: Name Value ---- ----- key value
[1] Это, возможно, удивительное поведение означает, что для типов, которые поддерживают представления, чувствительные к культуре, $obj.ToString()
дает текущее представление, соответствующее культуре, тогда как "$obj"
(интерполяция строк) всегда приводит к представлению, инвариантному к культуре - см. мой ответ.
[2] Известные переопределения:
* Обсуждаемая ранее последовательность строк (разделенный пробелами список элементов, а не нечто подобное System.Object[]
).
* Представление, похожее на хеш-таблицу [pscustomobject]
экземпляры (объясненные здесь), а не пустая строка.
У @Joey есть правильный ответ, но просто добавим еще немного, почему вам нужно форсировать оценку с помощью $()
:
Ваш пример кода содержит неоднозначность, которая указывает на то, почему создатели PowerShell, возможно, решили ограничить расширение только ссылками на переменные, а также не поддерживать доступ к свойствам (например, расширение строки выполняется путем вызова ToString()
метод на объекте, который может объяснить некоторые "странные" результаты).
Ваш пример содержится в самом конце командной строки:
...\$LogFileName.ldf
Если свойства объектов были расширены по умолчанию, приведенное выше разрешит
...\
поскольку объект, на который ссылается $LogFileName
не будет иметь свойство под названием ldf
, $null
(или пустая строка) будет заменена на переменную.
У @Джей хороший ответ. Есть еще один способ с более внешним видом.NET с эквивалентом String.Format, я предпочитаю его при доступе к свойствам объектов:
Вещи об автомобиле:
$properties = @{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; }
Создать объект:
$car = New-Object -typename psobject -Property $properties
Интерполировать строку:
"The {0} car is a nice {1} that is {2}" -f $car.color, $car.type, $car.package
Выходы:
# The red car is a nice sedan that is fully loaded
Просто: -> Если вы хотите использовать свойства в кавычках, сделайте следующее:
$($variable.property) - Вы должны использовать $ вне скобки для печати свойства.
Пример: $ uninstall = Get-WmiObject -ClassName Win32_Product | Where-Object {$_. Имя - например, "Google Chrome"
Выход: IdentifyingNumber: {57CF5E58-9311-303D-9241-8CB73E340963} Имя: Google Chrome Производитель: Google LLC Версия: 95.0.4638.54 Подпись: Google Chrome
-> Если вам нужно только свойство name, сделайте следующее:
"$($uninstall.name) обнаружен и инициировал удаление"
Результат: обнаружен Google Chrome и запущено удаление.
Надеюсь, вы поняли !!!