英文:
PowerShell: Referencing a property with spaces
问题
我正在尝试创建一个脚本,用于检查注册表键/值。如果值是特定版本,将输出。如果值不是该版本,然后创建一个新值。我遇到的问题是属性分为两个单词。
键是 hklm:software\dg
值名称是 "Agent version"
值数据是 7.8.5.005
我尝试过下面的脚本,但我不太熟悉如何正确检查 "Agent version" 值的版本,因为它分为两个单词。该脚本总是创建新的测试值。我尝试过双引号、单引号、大括号包围 "Agent version"。似乎什么都不起作用。如果有更简单的方法来做这个,我愿意听取建议。提前感谢!
$val = Get-ItemProperty -Path hklm:software\dg
if($val.'Agent version' -eq '7.8.5.005') {
Write-Host "Agent is current" -ForegroundColor Green
}
else {
New-ItemProperty -Path hklm:software\dg -Name "Test" -Value 0
}
英文:
I am trying to create a script that will check a registry key/value. If the value is a certain version, write an output. If the value is not that version, then create a new value. The problem I am coming across is the property is split into two words.
The key is hklm:software\dg
The value name is "Agent version"
The value data is 7.8.5.005
I have tried the script below but I'm just not familiar with how to properly check the version of the value "Agent version" since it is split into two words. The script always creates the new test value. I have tried double quotes, single quotes, curly brackets around agent version. Nothing seems to work. If there is an easier way to do this, I am all ears. Thanks in advance!
$val = Get-ItemProperty -Path hklm:software\dg
if($val.'agent version' -eq 7.8.5.005) {
Write-Host Agent is current -ForegroundColor Green
}
else {
New-ItemProperty -Path hklm:software\dg -Name "Test" -value 0
}
答案1
得分: 2
<!-- language-all: sh -->
在问题的出色评论基础上继续构建:
**tl;dr**
将 `$val.'agent version' -eq 7.8.5.005` 替换为:
注意 [version] 强制转换和 RHS 操作数周围的 '...'。
由于 LHS 使用了 [version],在 '7.8.5.5' 之前它也是不必要的
[version] $val.'agent version' -eq '7.8.5.5' # 注意:0 填充不相关
一般来说,要构造字面上的 `[version]` 实例,你必须从一个 _字符串_ 进行强制转换:
[version] '7.8.5.5' # '...' 是必需的
---
针对你的帖子标题隐含的 _一般_ 问题:
* **将包含 *特殊字符*,比如 *空格* 的(字面上的)属性名用 `'...'` 包围确实是正确的解决方法**(在属性名 _本身_ 包含 `'` 实例的极少数情况下,_双重_ 使用它们(`''`))。
* 至于 PowerShell 认为属性名(标识符)中哪些字符是 *特殊字符*,请参见 [此答案](https://stackoverflow.com/a/65268127/45375)。
---
至于 **你尝试过的**:
* **Windows 注册表 *没有* 直接表示 _版本号_ 的数据类型** - 用一个 _字符串_ 值 (`REG_SZ`) 来表示版本号,并且通过 [`Get-ItemProperty`](https://learn.microsoft.com/powershell/module/microsoft.powershell.management/get-itemproperty) 或者 - 直接检索注册表 _值_ - 通过 [`Get-ItemPropertyValue`](https://learn.microsoft.com/powershell/module/microsoft.powershell.management/get-itempropertyvalue) 将其转换为 .NET `[string]` 实例。
* **同样地,PowerShell 也没有用于版本号的字面表示法**,但是 **你可以将 _字符串_ 强制转换为 `[version]`** 以构造 [`System.Version`](https://learn.microsoft.com/en-US/dotnet/api/System.Version) 实例。
* 正如 [zett42](https://stackoverflow.com/users/7571258/zett42) 指出的,未加引号的 `7.8.5.005` 字面上的值实际上会被解析为 `$null`,因为它被解析为 `[double]` 实例 `7.8`,你试图在其中访问 (隐式字符串化的) `[double]` 实例 `5.005` _作为属性_,显然这个属性并不存在。
* 你可以通过将这些表达式括在 [脚本块](https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_Script_Blocks) (`{ ... }`) 中,然后深入探讨该脚本块的 [`.Ast` 属性](https://learn.microsoft.com/en-US/dotnet/api/System.Management.Automation.Language.ScriptBlockAst) 来深入了解 PowerShell 是如何解析这些表达式的 - 请注意 `5.005` 被列为 `Member` 访问:
PS> { 7.8.5.005 }.Ast.EndBlock.Statements.PipelineElements.Expression
Expression : 7.8
Member : 5.005
Static : False
NullConditional : False
StaticType : System.Object
Extent : 7.8.5.005
Parent : 7.8.5.005
**只有 `[version]` 实例有 _有意义的版本号比较_**。
由于在比较操作的 _左操作数_ (如 `-eq` 中) 使用类型 `[version]` 就足以比较版本号,你可以采取捷径,使用 _字符串字面值_ 作为 RHS,就像顶部所示。
英文:
<!-- language-all: sh -->
Building on the great comments on the question:
tl;dr
Replace $val.'agent version' -eq 7.8.5.005
with:
# Note the [version] cast, and the '...' around the RHS operand.
# Because the LHS uses [version], it isn't also needed before '7.8.5.5'
[version] $val.'agent version' -eq '7.8.5.5' # Note: 0-padding is irrelevant
In general, to construct a literal [version]
instance, you must cast from a string:
[version] '7.8.5.5' # '...' required
To address the general question implied by your post's title:
-
Enclosing a (literal) property name containing special characters such as spaces in
'...'
is indeed the right solution (in the unlikely event that the name itself contains'
instances, double them (''
)).- As for which characters PowerShell considers special in a property name (identifier), see this answer.
As for what you tried:
-
The Windows registry has no data type that directly represents a version number - a string value (
REG_SZ
) is used to represent version numbers, and that translates into a .NET[string]
instance viaGet-ItemProperty
or - to retrieve a registry value directly - viaGet-ItemPropertyValue
. -
Similarly, PowerShell also has no literal notation for version numbers, but you can cast a string to
[version]
in order to construct aSystem.Version
instance.-
As zett42 notes, the unquoted
7.8.5.005
literal effectively evaluates to$null
, because it is parsed as[double]
instance7.8
on which you're trying to access the (implicitly stringified)[double]
instance5.005
as a property, which obviously doesn't exist. -
You can gain insights into how PowerShell parses such expressions by enclosing them in a script block (
{ ... }
), and drilling down into that script block's.Ast
property - note how5.005
is listed as aMember
access:PS> { 7.8.5.005 }.Ast.EndBlock.Statements.PipelineElements.Expression Expression : 7.8 Member : 5.005 Static : False NullConditional : False StaticType : System.Object Extent : 7.8.5.005 Parent : 7.8.5.005
-
Only [version]
instances compare meaningfully as version numbers.
Since it is sufficient for the LHS of a comparison operation, such as with -eq
, to be of type [version]
in order to compare version numbers, you can take a shortcut and use a string literal as the RHS, as shown at the top.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论