PowerShell正则表达式从文件名中提取SID

时间:2017-09-11 10:25:57

标签: arrays regex powershell

我有一个数组$ vhdlist,其内容类似于以下文件名:

UVHD-S-1-5-21-8746256374-654813465-374012747-4533.vhdx
UVHD-S-1-5-21-8746256374-654813465-374012747-6175.vhdx
UVHD-S-1-5-21-8746256374-654813465-374012747-8147.vhdx
UVHD-template.vhdx

我想使用正则表达式,并留下一个只包含文件名的SID部分的数组。

我使用以下内容:

$sids = foreach ($file in $vhdlist) 
{
[regex]::split($file, '^UVHD-(?:([(\d)(\w)-]+)).vhdx$')
}

这有两个问题:在结果数组中,每个SID有3个空行;和"模板"文件名匹配(输出中的结果行只是"模板")。如何获得一组SID作为输出,而不包括"模板"线?

1 个答案:

答案 0 :(得分:3)

您似乎希望过滤列表到包含SID的文件名。使用Where-Object完成过滤(简称where);你不需要循环。

对于这个简单的情况,SID可以被描述为" S-,然后是一堆数字和短划线" 。这使我们的文件名为^UVHD-S-[\d-]*\.vhdx$

结合我们得到:

$vhdlist | where { $_ -Match "^UVHD-S-[\d-]*\.vhdx$" }

如果您确实没有字符串数组,但实际上是一组文件,请直接使用它们。

dir C:\some\folder | where { $_.Name -Match "^UVHD-S-[\d-]*\.vhdx$" }

或者,您甚至可以将其简单化为:

dir C:\some\folder\UVHD-S-*.vhdx

修改

从字符串列表中提取SID可以被视为组合的转换(对于每个元素,提取SID)和过滤器(删除不匹配)操作

PowerShell的ForEach-Object cmdlet(简称foreach)与其他语言中的map()类似。它接受每个输入元素并返回一个新值。实际上,它将输入元素列表转换为输出元素。与-replace运算符一起,您可以通过这种方式提取SID。

$vhdlist | foreach { $_ -replace ^(?:UVHD-(S-[\d-]*)\.vhdx|.*)$,"`$1" } | where { $_ -gt "" }

.NET语言的正则表达式反向引用是$1$是PowerShell字符串中的特殊字符,因此除非没有歧义,否则需要对其进行转义。反引号是PS转义字符。你也可以逃避正则表达式中的$,但是没有必要。

作为最后一步,我们使用where删除空字符串(即不匹配)。这样做意味着我们只需要应用一次正则表达式,而不是在首先过滤并替换第二次时应用两次。

PowerShell运算符也可以直接处理列表。所以甚至可以缩短上述内容:

$vhdlist -replace "^UVHD-(S-[\d-]*)\.vhdx$","`$1" | where { $_ -gt "" }

较短版本仅适用于在调用.ToString()时生成正确内容的实际字符串或对象的列表。

正则表达式细分:

^                       # start-of-string anchor
(?:                     # begin non-capturing group (either...)
  UVHD-                 #   'UVHD-'
  (                     #   begin group 1
    S-[\d-]*            #     'S-' and however many digits and dashes
  )                     #   end group 1
  \.vhdx                #   '.vhdx'
  |                     #    ...or...
  .*                    #   anything else
)                       # end non-capturing group
$                       # end-of-string anchor