【问题标题】:Powershell: enigmatic behavior of -like operatorPowershell:类似运算符的神秘行为
【发布时间】:2019-07-26 05:25:32
【问题描述】:

我们有一个保存服务器数据库的应用程序 - 服务器名称和其他相关信息的列表。有时我们需要以 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 实例中的“不可见”服务器名称添加到测试实例并导出数据库,脚本会毫无问题地找到该名称。

如果我将 -like 替换为 -match,问题就会消失。所以这不是 XML 文件生成器的问题(它是另一个生成 PSCustomObject 并通过 Export-CliXml 导出它的 PS 脚本)。服务器名称中的某些不可见或非 ANSI 符号也不是问题。我还手动检查了 XML 文件的内容。它很大(几十兆)而且很复杂,所以很难分析,但我没有发现任何明显的问题。 XML 结构看起来正确。

我不明白这种随机行为。它是否与 XML 文件大小有关? PS内存不足之类的?我们使用 Powershell v4。

【问题讨论】:

  • 试试:$FoundServer = ($ServerList | Where-Object {$_.Name -match $('{0}.*' -f [regex]::Escape($Servername))})
  • 没有足够的信息来诊断您的问题;你在做什么的描述和你的代码 sn-ps 没有解释行为。也许如果您举一个产生症状的服务器名称示例,我们可以提供帮助(它不必是真实的服务器名称,只要它产生症状即可)。
  • @Theo:好主意,但您应该锚定正则表达式 (^),将 . 转义为 \.,并使用 (...),而不是 $(...)(后者是低效且仅在需要嵌入多个语句时才需要)。
  • @mklement0 好点,但是,. 旨在用作“除换行符之外的任何字符”。在任何一种情况下,它都不会真正产生影响,因为* 使点在零次或多次出现时有效。
  • 大家好。关于 -like 和 -match 运算符,确实需要 -like。这是一项额外的安全措施,可确保脚本始终在服务器名称的开头查找指定的服务器名称。除其他外,脚本会自动从数据库中删除服务器名称,我想排除操作员在错误的服务器名称中间找到子字符串的情况。它可能导致删除错误的服务器。示例中的字符串连接实际上是在代码前面完成的,为了便于说明,我将其放在示例代码中。

标签: arrays string powershell match wildcard


【解决方案1】:

请注意,此答案不是解决方案,因为(在撰写本文时)没有足够的信息来诊断您的问题;但是,您-like-match 运算符的使用值得仔细检查。


$_.Name -match $ServerName+"*"(更简洁:$_.Name -match "$ServerName*"$_.Name -like "$ServerName*"相同:

  • -match 使用regular expressions(正则表达式),(也)匹配输入的部分,除非明确制定为在输入的开头 (^) 和/或结尾 ($) 匹配。

  • -like 使用wildcard expressions,它必须匹配输入作为一个整体

    李>

虽然正则表达式和通配符关系很远,但它们的语法和功能却是不同的;正则表达式要强大得多;在手头的情况下(注意匹配默认不区分大小写):

  • ... -like 'ServerXX*' 匹配 ServerXX 开头并后跟零个或多个 任意字符 (*) 的字符串。

    • 输入 'ServerXX''ServerXX.foo.bar''ServerXXY' 都会返回 $true
  • ... -match 'ServerXX*' 匹配包含子字符串ServerX 的字符串(仅一个 X!)输入中的任何位置,如果后跟零或更多 (*) X 字符,因为重复符号* 修改了前面的字符/子表达式。

    • 虽然输入 'ServerXX''ServerXX.foo.bar' 会返回 $true,但 'ServerX''fooServerXX' 也会返回 - 在这种情况下这是不希望的。

如果您的输入是 FQDN,请使用以下任一等效表达式:

... -like 'ServerXX.*'

... -match '^ServerXX\.'

如果服务器名称是通过变量提供的,例如$ServerName,使用"...",一个expandable string,在最简单的情况下:

... -like "$ServerName.*"

... -match "^$ServerName\."

这在 服务器名称 的情况下很好,因为它们不允许包含可能被错误地解释为正则表达式/通配符 元字符 的字符(带有特殊字符的字符)含义,如*)。

通常,最安全的方法是显式转义一个变量值,以确保其字面量使用,不过请注意regex 中比在通配符表达式中更可能需要这样做,因为 regex 具有更多元字符:

... -like ('{0}.*' -f [System.Management.Automation.WildcardPattern]::Escape($ServerName))


... -match ('^{0}\.' -f [regex]::Escape($ServerName))

使用带有-f单引号 模板字符串,format operator{0} 表示第一个 RHS 操作数)可以清楚地看出哪些部分是按字面意思使用的,哪些部分是拼接为 转义 变量值。

【讨论】:

  • 嗨 mklement0。谢谢,基本上我的问题是通过在表达式中使用 -match "^$ServerName" 解决的。我还要记住变量转义,我不知道这个功能。现在不需要,但总体上看起来很有用。搜索变量中的特殊符号也是我关心的问题。我仍然不理解 -like 运算符的不稳定行为,但是哦,好吧。不值得研究。整个脚本很长,并且严重依赖于使用特定于应用程序的 PS 调用,因此将其完整放在这里没有意义。如果您知道它是什么,它就是 Ivanti Protect。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-23
  • 2013-06-12
  • 2022-01-13
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多