Powershell:类似运算符的神秘行为

时间:2019-03-04 20:28:16

标签: arrays string powershell match wildcard

我们有一个保留服务器数据库的应用程序-服务器名称和其他相关信息的列表。有时,我们需要以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中的其他字母,则脚本会找到它。如果在没有域名的文件中指定了相同的服务器名称(以简单形式),则脚本将找到它。

嗯,甚至更令人费解的是,我们有两个已安装应用程序的实例,一个实例用于生产,另一个实例用于测试。测试之一包含一个较小的服务器数据库。如果我将生产实例中的“不可见”服务器名称添加到测试实例中并导出数据库,脚本将找到该名称而不会出现任何问题。

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

我不了解这种随机行为。它可以某种方式与XML文件大小相关吗? PS内存不足或类似问题?我们使用Powershell v4。

1 个答案:

答案 0 :(得分:1)

请注意,这个答案不是 解决方案,因为(截至撰写本文时)没有足够的信息来诊断您的问题;但是,您使用-like-match运算符应该受到一些审查。


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

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

  • -like使用wildcard expressions ,它必须与输入整体 相匹配。

尽管正则表达式和通配符关系密切,但它们的语法和功能却有所不同;正则表达式功能更强大; (例如,匹配默认情况下不区分大小写):

  • ... -like 'ServerXX*'匹配以 ServerXX开头的字符串,后跟零个或多个任意字符({{1} }。

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

    • 尽管输入*'ServerXX'将返回'ServerXX.foo.bar',而$true'ServerX'也将返回–在这种情况下是不希望的。

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

'fooServerXX'

如果服务器名称是通过变量 提供的,例如... -like 'ServerXX.*' ... -match '^ServerXX\.' ,在最简单的情况下,使用expandable string $ServerName

"..."

这对于服务器名称很好,因为不允许它们包含可能被误认为正则表达式/通配符元字符(具有特殊字符的字符)的字符。含义,例如... -like "$ServerName.*" ... -match "^$ServerName\."

通常,最安全的方法是显式转义 变量值以确保其 literal 使用,请注意,与正则表达式相比,在 regex 需要这样做的可能性更大,因为正则表达式具有更多的元字符:

*

使用带有... -like ('{0}.*' -f [System.Management.Automation.WildcardPattern]::Escape($ServerName)) ... -match ('^{0}\.' -f [regex]::Escape($ServerName)) 单引号模板字符串,format operator-f代表第一个RHS操作数),可以清楚地看出使用了哪些部分从字面上看,以及哪些部分作为转义的变量值进行拼接。