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

发布于 2024-07-26 21:06:37 字数 968 浏览 4 评论 0原文

我有以下代码:

$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,无效。
我的解决方法是将其复制到一个新变量中。

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

I have the following code:

$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;

When I try to use one of the properties in a string execute command:

& "$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'"

It tries to just use the value of $DatabaseSettings rather than the value of $DatabaseSettings[0].DatabaseName, which is not valid.
My workaround is to have it copied into a new variable.

How can I access the object's property directly in a double-quoted string?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

乞讨 2024-08-02 21:06:38

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

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

When you enclose a variable name in a double-quoted string it will be replaced by that variable's value:

$foo = 2
"$foo"

becomes

"2"

If you don't want that you have to use single quotes:

$foo = 2
'$foo'

However, if you want to access properties, or use indexes on variables in a double-quoted string, you have to enclose that subexpression in $():

$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 only expands variables in those cases, nothing more. To force evaluation of more complex expressions, including indexes, properties or even complete calculations, you have to enclose those in the subexpression operator $( ) which causes the expression inside to be evaluated and embedded in the string.

美男兮 2024-08-02 21:06:38

文档说明:获取有关_Quoting_Rules的帮助 涵盖了字符串插值,但是,从 PSv5 开始,并不深入。

补充 Joey 的有用答案包含 PowerShell 的字符串扩展实用摘要双引号字符串中的字符串插值 (". ..",又名可扩展字符串),包括双引号此处字符串):

  • 仅引用,例如$foo、< code>$global:foo (或 $script:foo, ...)和 $env:PATH (环境变量)可以直接嵌入到“...”字符串中 - 也就是说,仅将变量引用作为一个整体本身 已展开,无论接下来的内容如何。

    • 例如,"$HOME.foo" 扩展为类似 C:\Users\jdoe.foo 的内容,因为 .foo code> 部分被解释为字面上 - 不是解释为属性访问。

    • 消除变量名称与字符串中后续字符的歧义将其括在 {}; 例如,${foo}
      如果变量名称后跟 :,这一点尤其重要,否则 PowerShell 会将 $: 之间的所有内容视为 范围说明符,通常会导致插值失败; 例如,“$HOME:心脏所在的位置。” 会损坏,但 “${HOME}:心脏所在的位置。” 按预期工作。
      (或者,`-转义“$HOME`:心脏所在的位置。”,但这仅在以下字符时有效变量名称不会意外地与前面的 ` 形成转义序列,例如 `b - 请参阅概念性 about_Special_Characters 帮助主题)。


    • 要将 $" 视为文字,请在其前面添加转义字符。`反引号);例如:
      “`$HOME 的值:$HOME”


  • 对于其他任何内容,包括使用数组下标和访问对象变量的属性,您必须将表达式括在 $(...) 中,子表达式运算符(例如,“PS版本:$($PSVersionTable .PSVersion)""第 1 个:$($someArray[0])")

    • 使用 $(...) 甚至允许您将整个命令的输出嵌入双引号字符串中(例如,"Today is $( (Get-Date).ToString('d')).")。
  • 插值结果不一定与默认输出格式相同(例如,如果将变量/子表达式直接打印到控制台,您会看到什么,这涉及默认格式化程序; 请参阅 获取帮助 about_format .ps1xml):

    • 集合(包括数组)通过在元素的字符串表示形式之间放置一个单个空格来转换为字符串(通过默认值;可以通过设置 偏好变量$OFS,尽管这在实践中很少见)例如,"array: $(@(1, 2, 3) )" 产生数组:1 2 3

    • 任何其他类型的实例(包括本身不是集合​​的集合元素)通过调用IFormattable.ToString()具有不变区域性方法,如果实例的类型支持IFormattable接口[1] > 通过调用 .psobject.ToString(),在大多数情况下,它只是调用底层 .NET 类型的 .ToString() 方法[2] ,它可能会也可能不会给出有意义的表示:除非(非原始)类型专门重写了 .ToString() 方法,否则您将得到的只是完整的 类型名称(例如,“hashtable:$(@{ key = 'value'})”产生hashtable:System.Collections.Hashtable)。< /p>

    • 获得与控制台中相同的输出,请使用一个子表达式,在其中通过管道传输到 Out-String 并应用 。如果需要,Trim() 删除任何前导和尾随空行; 例如,
      “哈希表:`n$((@{ key = 'value' } | Out-String).Trim())” 产量:

       哈希表:                                                                                                                                                                           
            名称 值                                                                                                                                                
            ---- -----                                                                                                                                                
            核心价值       
        

[1] 这种可能令人惊讶的行为意味着,对于支持文化敏感表示的类型,$obj.ToString() 生成当前适合文化的表示,而 "$obj" (字符串插值)始终会导致文化不变表示 - 请参阅此答案

[2] 值得注意的覆盖:
• 前面讨论的集合的字符串化(以空格分隔的元素列表,而不是类似System.Object[])。
[pscustomobject] 实例的类似于哈希表的表示形式(此处进行了解释) 而不是空字符串

Documentation note: Get-Help about_Quoting_Rules covers string interpolation, but, as of PSv5, not in-depth.

To complement Joey's helpful answer with a pragmatic summary of PowerShell's string expansion (string interpolation in double-quoted strings ("...", a.k.a. expandable strings), including in double-quoted here-strings):

  • Only references such as $foo, $global:foo (or $script:foo, ...) and $env:PATH (environment variables) can directly be embedded in a "..." string - that is, only the variable reference itself, as a whole is expanded, irrespective of what follows.

    • E.g., "$HOME.foo" expands to something like C:\Users\jdoe.foo, because the .foo part was interpreted literally - not as a property access.

    • To disambiguate a variable name from subsequent characters in the string, enclose it in { and }; e.g., ${foo}.
      This is especially important if the variable name is followed by a :, as PowerShell would otherwise consider everything between the $ and the : a scope specifier, typically causing the interpolation to fail; e.g., "$HOME: where the heart is." breaks, but "${HOME}: where the heart is." works as intended.
      (Alternatively, `-escape the :: "$HOME`: where the heart is.", but that only works if the character following the variable name wouldn't then accidentally form an escape sequence with a preceding `, such as `b - see the conceptual about_Special_Characters help topic).

    • To treat a $ or a " as a literal, prefix it with escape char. ` (a backtick); e.g.:
      "`$HOME's value: $HOME"

  • For anything else, including using array subscripts and accessing an object variable's properties, you must enclose the expression in $(...), the subexpression operator (e.g., "PS version: $($PSVersionTable.PSVersion)" or "1st el.: $($someArray[0])")

    • Using $(...) even allows you to embed the output from entire commands in double-quoted strings (e.g., "Today is $((Get-Date).ToString('d')).").
  • Interpolation results don't necessarily look the same as the default output format (what you'd see if you printed the variable / subexpression directly to the console, for instance, which involves the default formatter; see Get-Help about_format.ps1xml):

    • Collections, including arrays, are converted to strings by placing a single space between the string representations of the elements (by default; a different separator can be specified by setting preference variable $OFS, though that is rarely seen in practice) E.g., "array: $(@(1, 2, 3))" yields array: 1 2 3

    • Instances of any other type (including elements of collections that aren't themselves collections) are stringified by either calling the IFormattable.ToString() method with the invariant culture, if the instance's type supports the IFormattable interface[1], or by calling .psobject.ToString(), which in most cases simply invokes the underlying .NET type's .ToString() method[2], which may or may not give a meaningful representation: unless a (non-primitive) type has specifically overridden the .ToString() method, all you'll get is the full type name (e.g., "hashtable: $(@{ key = 'value' })" yields hashtable: System.Collections.Hashtable).

    • To get the same output as in the console, use a subexpression in which you pipe to Out-String and apply .Trim() to remove any leading and trailing empty lines, if desired; e.g.,
      "hashtable:`n$((@{ key = 'value' } | Out-String).Trim())" yields:

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

[1] This perhaps surprising behavior means that, for types that support culture-sensitive representations, $obj.ToString() yields a current-culture-appropriate representation, whereas "$obj" (string interpolation) always results in a culture-invariant representation - see this answer.

[2] Notable overrides:
• The previously discussed stringification of collections (space-separated list of elements rather than something like System.Object[]).
• The hashtable-like representation of [pscustomobject] instances (explained here) rather than the empty string.

蘑菇王子 2024-08-02 21:06:38

@Joey 有正确的答案,但只是添加一点关于为什么需要使用 $() 强制评估的信息:

您的示例代码包含歧义,这表明了为什么 PowerShell 的制造商可能会这样做选择将扩展限制为仅变量引用,并且也不支持对属性的访问(顺便说一句:字符串扩展是通过调用对象上的 ToString() 方法来完成的,这可以解释一些“奇怪的” “ 结果)。

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

...\$LogFileName.ldf

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

...\

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

@Joey has the correct answer, but just to add a bit more as to why you need to force the evaluation with $():

Your example code contains an ambiguity that points to why the makers of PowerShell may have chosen to limit expansion to mere variable references and not support access to properties as well (as an aside: string expansion is done by calling the ToString() method on the object, which can explain some "odd" results).

Your example contained at the very end of the command line:

...\$LogFileName.ldf

If properties of objects were expanded by default, the above would resolve to

...\

since the object referenced by $LogFileName would not have a property called ldf, $null (or an empty string) would be substituted for the variable.

迷雾森÷林ヴ 2024-08-02 21:06:38

@Joey 有一个很好的答案。 还有另一种更 .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

@Joey has a good answer. There is another way with a more .NET look with a String.Format equivalent, I prefer it when accessing properties on objects:

Things about a car:

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

Create an object:

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

Interpolate a string:

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

Outputs:

# The red car is a nice sedan that is fully loaded
二手情话 2024-08-02 21:06:38

如果您想使用引号内的属性,请按照以下步骤操作。 您必须在括号外使用 $ 来打印属性。

$($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

If you want to use properties within quotes follow as below. You have to use $ outside of the bracket to print property.

$($variable.property)

Example:

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

Output:

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

If you want only name property then do as below:

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

Output:

Google Chrome Found and triggered uninstall
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文