【问题标题】:find string from a group of files从一组文件中查找字符串
【发布时间】:2018-01-19 18:02:34
【问题描述】:

我有一组 txt 文件包含类似这样的字符串:

Windows 7 专业服务包 1 产品型号:***** 从“合规检查产品”媒体安装。 产品 ID:0000-0000-0000 匹配 CD 密钥数据 CD密钥:xxxxx-xxxxx-xxxxx-xxxxx-xxxxx 计算机名称:COMP001 注册所有者:ABC 注册机构: 微软办公专业版 2003 产品编号:00000-00000-00000-00000 CD密钥:xxxxx-xxxxx-xxxxx-xxxxx-xxxxx

我怎样才能一次选择所有办公室钥匙并保存到另一个文件中?

我的代码:

$content = Get-ChildItem -Path 'S:\New folder' -Recurse |
           where Name -like "b*" |
           select name
Get-Content $content

我得到一个文件名列表,但它不会为 Get-Content 运行。

【问题讨论】:

  • SO 不是其他人为您编写代码的地方。到目前为止,您尝试了什么(显示您的代码),您需要帮助解决什么特定问题(在您的代码中)?正则表达式是解决此类问题的常用方法。
  • 请编辑您的问题以显示代码。在 cmets 中读取代码很糟糕

标签: powershell


【解决方案1】:

您发布的代码不起作用,因为$content 包含一个自定义对象列表,其中一个属性 (name) 仅包含没有路径的文件名。由于您显然没有列出当前工作目录中的文件,而是列出了其他文件夹 (S:\New Folder),因此如果您希望能够读取这些文件,则需要这些文件的完整路径(属性 FullName)。此外,该属性不会自动扩展。您必须在枚举文件时展开它:

$content = Get-ChildItem -Path 'S:\New folder' -Recurse |
           Where-Object { $_.Name -like "b*" } |
           Select-Object -Expand FullName
Get-Content $content

或将值传递给Get-Content时:

$content = Get-ChildItem -Path 'S:\New folder' -Recurse |
           Where-Object { $_.Name -like "b*" } |
           Select-Object FullName
Get-Content $content.FullName

除此之外,您拥有的任何代码都不会尝试提取您正在寻找的数据。假设您文件中的许可证信息块始终由 2 个或多个连续换行符分隔,您可以在连续换行符处拆分文件内容并使用如下正则表达式提取信息:

Get-ChildItem -Path 'S:\New folder' -Recurse | Where-Object {
    -not $_.PSIsContainer -and
    $_.Name -like "b*"
} | ForEach-Object {
    # split content of each file into individual license information fragments
    (Get-Content $_.FullName | Out-String) -split '(\r?\n){2,}' | Where-Object {
        # filter for fragments that contain the string "Microsoft Office" and
        # match the line beginning with "CD Key: " in those fragments
        $_ -like '*Microsoft Office*' -and
        $_ -match '(?m)(?<=^CD Key: ).*'
    } | ForEach-Object {
        # remove leading/trailing whitespace from the extracted key
        $matches[0].Trim()
    }
} | Set-Content 'C:\output.txt'

(\r?\n){2,} 是匹配 2 个或更多连续换行符的正则表达式(Windows 和 Unix 样式)。

(?m)(?&lt;=^CD Key: ).* 是一个正则表达式,它匹配以字符串 CD Key: 开头的行并返回该字符串之后的其余行。 (?&lt;=...) 是所谓的正向后向断言,用于匹配模式而不将其包含在返回值中。 (?m) 是一个正则表达式选项,它允许 ^ 匹配多行字符串中的行首,而不仅仅是字符串的开头。

【讨论】:

    【解决方案2】:

    试试这样的:

    Get-ChildItem "c:\temp" -file -filter "*.txt" | 
        %{select-string -Path $_.FullName -Pattern "CD Key:" } | select line | export-csv "c:\temp\found.csv" -notype
    

    【讨论】:

    • 谢谢 Esperento57。我可以将txt文件的标题保存在每个文件的前面吗,因为那是计算机名称。所以它很冷就像:计算机名--cd key
    【解决方案3】:

    如果你想要计算机信息,你可以这样做(-context 之前取 N 行,之后取 M 行示例 -context 3, 2 取 3 之前和 2 之后):

    Get-ChildItem "c:\temp" -file -filter "*.txt" | 
        %{select-string -Path $_.FullName -Pattern "CD Key:" -context 6,0  } | where {$_.Context.PreContext[0] -like 'Computer Name:*'} |
            select Line, @{Name="Computer";E={($_.Context.PreContext[0] -split ':')[1] }} | export-csv "c:\temp\found.csv" -notype
    

    【讨论】:

      【解决方案4】:

      或者经典:

      Get-ChildItem "c:\temp" -file -filter "*.txt" | foreach{
      
      $CurrenFile=$_.FullName
      
      #split current file rows to 2 column with ':' like delimiter
      $KeysValues=get-content $CurrenFile | ConvertFrom-String -Delimiter ":"  -PropertyNames Key, Value
      
      #if file contains CD Key, its good file
      if ($KeysValues -ne $null -and $KeysValues[2].Key -eq 'CD Key')
      {
          #build object with asked values
          $Object=[pscustomobject]@{
      
          File=$CurrenFile
          ComputerName=$KeysValues[3].Value
          OfficeKey=$KeysValues[7].Value
          }
      
          #send objet to standard output
          $Object
      }
      
      } | export-csv "c:\temp\found.csv" -notype
      

      【讨论】:

        猜你喜欢
        • 2014-01-17
        • 2023-03-27
        • 2020-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多