如何在双引号字符串中使用对象的属性?

我有以下密码:

$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的值。
我的解决办法是将它复制到一个新变量中。

如何直接访问双引号字符串中对象的属性?

87570 次浏览

当您在双引号字符串中包含一个变量名时,它将被该变量的值替换:

$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 只在这种情况下扩展变量,仅此而已。为了强制计算更复杂的表达式,包括索引、属性甚至完整的计算,必须在子表达式操作符 $( )中包含这些内容,这会导致计算内部的表达式并将其嵌入到字符串中。

@ Joey 的回答是正确的,但是我想补充一点,为什么你需要用 $()来强制评估:

你的示例代码包含一个模棱两可的地方,它指出了为什么 PowerShell 的制造商可能选择仅仅限制变量引用的扩展,而不支持对属性的访问(顺便说一句: 字符串扩展是通过调用对象上的 ToString()方法来完成的,这可以解释一些“奇怪”的结果)。

您的示例包含在命令行的最后:

...\$LogFileName.ldf

如果默认情况下扩展了对象的属性,则上述属性将解析为

...\

由于 $LogFileName引用的对象不具有名为 ldf的属性,因此 $null(或空字符串)将被替换为变量。

@ 乔伊有个好答案。还有另一种方法。带字符串的 NET 外观。格式等效,我更喜欢在访问对象上的属性时使用:

关于汽车的事情:

$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

文档说明: Get-Help about_Quoting_Rules涵盖了字符串插值,但是,从 PSv5开始,没有深入讨论。

用 PowerShell 的 字符串扩展(双引号字符串中的字符串插值("...",又名 可扩展字符串) ,包括双引号 < em > here-string )的 务实的总结来补充 乔伊的回答很有帮助:

  • 只引用诸如 ABC0,ABC1(或 ABC2,...)和 $env:PATH(环境变量) 可以直接 < em > 嵌入到 "..."字符串中-也就是 只扩展了变量引用 < em > 本身,作为一个整体,不管下面是什么。

    • 例如,"$HOME.foo"扩展为类似于 C:\Users\jdoe.foo的东西,因为 .foo部分被解释为 真的-没有属性访问。

    • 从字符串中的后续字符转换为 消除变量名的歧义,例如,${foo}
      如果变量名后面跟着一个 :,这一点尤其重要,因为 PowerShell 会认为 $:之间的所有东西都是 范围说明符,通常会导致 失败的插值; 例如,"$HOME: where the heart is."中断,但是 "${HOME}: where the heart is."按预期工作。
      (或者,`-转义 :: "$HOME`: where the heart is.",但是只有当变量名后面的字符不会意外地与前面的 `形成一个 逃逸程序,例如 `b-参见概念 关于特殊人物帮助主题)。

    • 为了将 $"视为 字面意思,在它前面加上 越狱字符。 `(倒计时) ; 例如:
      "`$HOME's value: $HOME"

  • 对于其他任何东西,包括使用 数组下标和访问对象变量的 物业,您必须使用 将表达式封装在 $(...)子表达式运算符(例如,"PS version: $($PSVersionTable.PSVersion)""1st el.: $($someArray[0])")

    • 使用 $(...)甚至可以将 完整的指令的输出嵌入到双引号字符串中(例如,"Today is $((Get-Date).ToString('d')).")。
  • 插值结果不一定看起来与默认的输出格式 相同(例如,如果将变量/子表达式直接打印到控制台,就会看到这种情况,这涉及到默认的格式化程序; 请参见 Get-Help about_format.ps1xml) :

    • 集合 ,包括数组,通过 在元素的字符串表示形式之间放置一个 < em > 单个空格 转换为字符串(默认情况下,通过设置 偏好变量 < strong > $OFS 可以指定不同的分隔符,尽管这在实际中很少见) ,例如,"array: $(@(1, 2, 3))"产生 array: 1 2 3

    • 任何其他类型的实例(包括本身不是集合的集合元素)是 如果实例的类型通过调用 ABC2支持 ABC1接口 < sup > [1] ,< em > 或 < em > 或 来调用 < a href = “ https://msdn.microsoft.com/en-us/library/system.iformattable.tostring (v = vs. 110) .aspx”rel = “ nofollow noReferrer”> ABC0 方法,并且具有 < em > 不变区域性 ,那么通过调用 ABC2来支持 ABC1接口 < sup > [1] ,< em > 或 ,在大多数情况下,ABC2只调用底层。NET 类型的 .ToString()方法[2],它可能会或可能不会给出一个有意义的表示: 除非一个(非原语)类型特别覆盖了 .ToString()方法,否则你得到的只是完整的 IFormattable0(例如,"hashtable: $(@{ key = 'value' })"产生 hashtable: System.Collections.Hashtable)。

    • 对于 获得与 < em > 控制台 中相同的输出,如果需要,可以使用一个子表达式,在其中应用 管道到 < a href = “ https://Learn.microsoft.com/powershell/module/microsoft.powershell.tility/out-string”rel = “ nofollow noReferrer”> Out-String 并应用 .Trim()来删除任何前导和尾随的空行; 例如,
      "hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"收益率:

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

[1]这种可能令人惊讶的行为意味着,对于支持区分文化的表示的类型,$obj.ToString()产生一个适合 目前文化的表示,而 "$obj"(字符串插值)总是产生一个 文化不变量文化不变量表示-参见 这个答案

[2]值得注意的是:
•前面讨论过的 收藏品的字符串化(空格分隔的元素列表,而不是类似于 System.Object[]的东西)。
• hashtable-喜欢表示 [pscustomobject]实例(解释为 给你) ,而不是 空字符串

如果要在引号中使用属性,请按照下面的步骤操作。必须在括号外使用 $才能打印属性。

$($variable.property)

例如:

$uninstall= Get-WmiObject -ClassName Win32_Product |
Where-Object {$_.Name -like "Google Chrome"

产出:

IdentifyingNumber : {57CF5E58-9311-303D-9241-8CB73E340963}
Name              : Google Chrome
Vendor            : Google LLC
Version           : 95.0.4638.54
Caption           : Google Chrome

如果您只想要名称属性,那么按照以下步骤操作:

"$($uninstall.name) Found and triggered uninstall"

产出:

Google Chrome Found and triggered uninstall