Powershell:类似运算符的神秘行为
Powershell: enigmatic behavior of -like operator
我们有一个保存服务器数据库的应用程序 - 服务器名称和其他相关信息的列表。有时我们需要将信息导出为XML格式,以便通过Powershell脚本进行处理。 XML 文件中的服务器名称可以采用简单 ("ServerXX") 或 FQDN ("ServerXX.abc.com") 格式。该脚本搜索始终为简单格式的服务器名称,搜索结果应包含与搜索名称匹配的所有简单和完整服务器名称。
主要搜索运算符(稍微简化)如下所示:
$FoundServer = ($ServerList | Where {$_.Name -match $ServerName+"*"})
$ServerList 这里是字符串数组(服务器名称)。看起来很简单并且按预期工作。通常。
奇怪的是,有时脚本找不到某些 FQDN。例如,如果文件中的 FQDN 是 "ServerXX.abc.com",而我们正在搜索 "ServerXX",则找不到 FQDN。同时搜索其他名称按预期工作。在调试脚本的时候,可以看到{}里面的表达式就是字面上的"ServerXX.abc.com" -like "ServerXX*"
。一定是真的。但是得到的搜索结果是空的。更有趣的是,如果将搜索名称指定为 "ServerXX."、"ServerXX.a" 或 FQDN 中的其他字母,脚本会找到它。如果在没有域名的文件中指定相同的服务器名称(以简单形式),脚本会找到它。
好吧,更神秘的是,我们有两个已安装应用程序的实例,一个用于生产,另一个用于测试。测试版包含一个小得多的服务器数据库。如果我将 prod 实例中的 "invisible" 服务器名称添加到测试实例并导出数据库,脚本会毫无问题地找到该名称。
如果我将 -like 替换为 -match,问题就会消失。所以这不是 XML 文件生成器的问题(它是另一个 PS 脚本生成 PSCustomObject 并通过 Export-CliXml 导出它)。这也不是服务器名称中某些不可见或非 ANSI 符号的问题。我还手动检查了 XML 文件的内容。它很大(几十兆字节)而且很复杂,所以很难分析,但我没有发现任何可见的问题。 XML 结构看起来正确。
我不明白这种随机行为。它会以某种方式与 XML 文件大小有关吗? PS 或类似的内存不足?我们使用 Powershell v4.
请注意,此答案不是解决方案,因为(截至撰写本文时)没有足够的信息来诊断您的问题;但是,您 使用 -like
和 -match
运算符 值得仔细研究。
$_.Name -match $ServerName+"*"
(更简洁:$_.Name -match "$ServerName*"
)与不相同 $_.Name -like "$ServerName*"
:
-match
使用 regular expressions(正则表达式),(也)匹配 输入 的部分 ,除非明确制定匹配输入的开头 (^
) and/or 结尾 ($
)。
-like
使用 wildcard expressions,它必须 匹配整个输入 .
虽然正则表达式和通配符关系很远,但它们的 语法和功能不同;正则表达式更强大;在手头的情况下(请注意,默认情况下匹配不区分大小写):
... -like 'ServerXX*'
匹配 以 ServerXX
开头并后跟 零个或多个 任意字符(*
).
- 输入
'ServerXX'
、'ServerXX.foo.bar'
和 'ServerXXY'
都将 return $true
.
... -match 'ServerXX*'
匹配包含子字符串 ServerX
的字符串(只是 one X
!) 在输入的任何地方,如果后跟零个或多个(*
)X
个字符,因为重复符号*
修饰前面的 character/subexpression.
- 虽然输入
'ServerXX'
和 'ServerXX.foo.bar'
会 return $true
,但 'ServerX'
和 'fooServerXX'
也会如此 - 在这种情况下这是不希望的.
如果您输入的是 FQDN,请使用以下任一等效表达式:
... -like 'ServerXX.*'
... -match '^ServerXX\.'
如果服务器名称是通过 变量 提供的,例如$ServerName
,使用"..."
,一个expandable string,最简单的情况:
... -like "$ServerName.*"
... -match "^$ServerName\."
这在 服务器名称 的情况下很好,因为它们不允许包含可能被错误解释为正则表达式/通配符的字符 元字符(有特殊意义的字符,如*
)。
通常,最安全的方法是显式转义一个变量值以确保其文字 使用,但请注意在正则表达式 中比在通配符表达式[=112] 中更可能需要这样做=],因为正则表达式有更多的元字符:
... -like ('{0}.*' -f [System.Management.Automation.WildcardPattern]::Escape($ServerName))
... -match ('^{0}\.' -f [regex]::Escape($ServerName))
使用带有 -f
的 单引号 模板字符串,format operator({0}
表示第一个 RHS 操作数),使其成为很明显哪些部分按字面意思使用,哪些部分拼接为 escaped 变量值。
我们有一个保存服务器数据库的应用程序 - 服务器名称和其他相关信息的列表。有时我们需要将信息导出为XML格式,以便通过Powershell脚本进行处理。 XML 文件中的服务器名称可以采用简单 ("ServerXX") 或 FQDN ("ServerXX.abc.com") 格式。该脚本搜索始终为简单格式的服务器名称,搜索结果应包含与搜索名称匹配的所有简单和完整服务器名称。
主要搜索运算符(稍微简化)如下所示:
$FoundServer = ($ServerList | Where {$_.Name -match $ServerName+"*"})
$ServerList 这里是字符串数组(服务器名称)。看起来很简单并且按预期工作。通常。
奇怪的是,有时脚本找不到某些 FQDN。例如,如果文件中的 FQDN 是 "ServerXX.abc.com",而我们正在搜索 "ServerXX",则找不到 FQDN。同时搜索其他名称按预期工作。在调试脚本的时候,可以看到{}里面的表达式就是字面上的"ServerXX.abc.com" -like "ServerXX*"
。一定是真的。但是得到的搜索结果是空的。更有趣的是,如果将搜索名称指定为 "ServerXX."、"ServerXX.a" 或 FQDN 中的其他字母,脚本会找到它。如果在没有域名的文件中指定相同的服务器名称(以简单形式),脚本会找到它。
好吧,更神秘的是,我们有两个已安装应用程序的实例,一个用于生产,另一个用于测试。测试版包含一个小得多的服务器数据库。如果我将 prod 实例中的 "invisible" 服务器名称添加到测试实例并导出数据库,脚本会毫无问题地找到该名称。
如果我将 -like 替换为 -match,问题就会消失。所以这不是 XML 文件生成器的问题(它是另一个 PS 脚本生成 PSCustomObject 并通过 Export-CliXml 导出它)。这也不是服务器名称中某些不可见或非 ANSI 符号的问题。我还手动检查了 XML 文件的内容。它很大(几十兆字节)而且很复杂,所以很难分析,但我没有发现任何可见的问题。 XML 结构看起来正确。
我不明白这种随机行为。它会以某种方式与 XML 文件大小有关吗? PS 或类似的内存不足?我们使用 Powershell v4.
请注意,此答案不是解决方案,因为(截至撰写本文时)没有足够的信息来诊断您的问题;但是,您 使用 -like
和 -match
运算符 值得仔细研究。
$_.Name -match $ServerName+"*"
(更简洁:$_.Name -match "$ServerName*"
)与不相同 $_.Name -like "$ServerName*"
:
-match
使用 regular expressions(正则表达式),(也)匹配 输入 的部分 ,除非明确制定匹配输入的开头 (^
) and/or 结尾 ($
)。-like
使用 wildcard expressions,它必须 匹配整个输入 .
虽然正则表达式和通配符关系很远,但它们的 语法和功能不同;正则表达式更强大;在手头的情况下(请注意,默认情况下匹配不区分大小写):
... -like 'ServerXX*'
匹配 以ServerXX
开头并后跟 零个或多个 任意字符(*
).- 输入
'ServerXX'
、'ServerXX.foo.bar'
和'ServerXXY'
都将 return$true
.
- 输入
... -match 'ServerXX*'
匹配包含子字符串ServerX
的字符串(只是 oneX
!) 在输入的任何地方,如果后跟零个或多个(*
)X
个字符,因为重复符号*
修饰前面的 character/subexpression.- 虽然输入
'ServerXX'
和'ServerXX.foo.bar'
会 return$true
,但'ServerX'
和'fooServerXX'
也会如此 - 在这种情况下这是不希望的.
- 虽然输入
如果您输入的是 FQDN,请使用以下任一等效表达式:
... -like 'ServerXX.*'
... -match '^ServerXX\.'
如果服务器名称是通过 变量 提供的,例如$ServerName
,使用"..."
,一个expandable string,最简单的情况:
... -like "$ServerName.*"
... -match "^$ServerName\."
这在 服务器名称 的情况下很好,因为它们不允许包含可能被错误解释为正则表达式/通配符的字符 元字符(有特殊意义的字符,如*
)。
通常,最安全的方法是显式转义一个变量值以确保其文字 使用,但请注意在正则表达式 中比在通配符表达式[=112] 中更可能需要这样做=],因为正则表达式有更多的元字符:
... -like ('{0}.*' -f [System.Management.Automation.WildcardPattern]::Escape($ServerName))
... -match ('^{0}\.' -f [regex]::Escape($ServerName))
使用带有 -f
的 单引号 模板字符串,format operator({0}
表示第一个 RHS 操作数),使其成为很明显哪些部分按字面意思使用,哪些部分拼接为 escaped 变量值。