通过Powershell抓取txt文件的特定部分

时间:2017-07-06 21:14:33

标签: powershell

我是Powershell脚本编写的新手,但我觉得我忽略了一个简单的答案,希望你们中的一些人可以提供帮助。

我的公司从我们所有的计算机中导出文件,其中一部分位于Mapped Network Printers的中间。它看起来像这样:

-------------------------------------------------------------------------
Mapped Network Printers:
NetworkAddress\HP425DN    [DEFAULT PRINTER]
-------------------------------------------------------------------------
Local Printers: 

我被要求做的是将Mapped Network Printers复制到新的文本文件中。

我尝试使用带有上下文参数的Select-String,但我无法知道有多少网络打印机,所以我无法猜测。

我也尝试使用我在本网站上找到的以下代码,但它没有返回任何内容:

$MapPrint  = gc C:\Users\User1\Documents\Config.txt

$from =  ($MapPrint | Select-String -pattern "Mapped Network Printers:" | 
Select-Object LineNumber).LineNumber
$to =  ($MapPrint  | Select-String -pattern "-------------------------------
--------------------------------------------" | Select-Object 
LineNumber).LineNumber

$i = 0
$array = @()
foreach ($line in $MapPrint)
{
foreach-object { $i++ }
    if (($i -gt $from) -and ($i -lt $to))
    {
    $array += $line      
    }
}
$array

我基本上想在“Mapped Network Printers”开始搜索并在“------”的下一行结束它

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:0)

您可以使用Select-StringWhere-Object来查找\的字词。更进一步,您可以使用RegEx查找server\printer值,如下所示:

Get-Content C:\Users\User1\Documents\Config.txt -Raw |
    Select-String '[A-Z0-9]+\\[A-Z0-9]+' -AllMatches |
    ForEach-Object {$_.Matches.Value}

请注意,这假设服务器名称和打印机仅使用A-Z和0-9,如果这不是一个有效的假设,您可能需要查找更多字符。

以下是使用Where-Object过滤\

行的示例
Get-Content 'C:\Users\User1\Documents\Config.txt' | Where-Object {$_ -like '*\*'}

答案 1 :(得分:0)

$Doc= "C:\temp\test.txt"
$Doc_end ="C:\temp\testfiltered.txt"
$reader = [System.IO.File]::OpenText($Doc)

$cdata=""
while($null -ne ($line = $reader.ReadLine())) 
    {

        if ($line -like ('---*') )     {$Read = 0 }

        if ($Read -eq 1) {$cdata+= $line +  "`r`n"}

        if ($line -like ('Mapped Network Printers:*')) {$Read = 1}


    }


$cdata | Out-File $Doc_end -Force

答案 2 :(得分:0)

您可以使用foreach-object命令和一些其他测试条件执行您尝试的操作。只需在遇到Mapped Network Printers:行时设置标记,然后在下一行-like "---*"上终止输出就可以了,例如

## positional parameters
param(
    [Parameter(Mandatory=$true)][string]$infile
)
$beginprn = 0

get-content $infile | foreach-object {
    # terminate condition
    if ([int]$beginprn -eq 1 -and $_ -like "---*") {
        break
    }
    # output Mapped printers
    if ([int]$beginprn -eq 1) {
        write-host $_
    }
    # begin condition
    if ($_ -eq "Mapped Network Printers:") {
        $beginprn = 1
    }
}

示例输入文件

-------------------------------------------------------------------------
Mapped Network Printers:
NetworkAddress\HP425DN    [DEFAULT PRINTER]
NetworkAddress\HP4100N
-------------------------------------------------------------------------
Local Printers:

示例使用/输出

PS> parseprn.ps1 .\tmp\prnfile.txt
NetworkAddress\HP425DN    [DEFAULT PRINTER]
NetworkAddress\HP4100N

答案 3 :(得分:0)

Select-String没有根据内容提取范围行的功能。

最简单的方法是将文件作为一个整体读取并使用-replace运算符通过正则表达式(正则表达式)提取范围:

$file = 'C:\Users\User1\Documents\Config.txt'
$regex = '(?sm).*^Mapped Network Printers:\r?\n(.*?)\r?\n---------------------.*'
(Get-Content -Raw $file) -replace $regex, '$1'

读取输入文件作为一个整体可能会出现问题,文件太大而无法放入内存中,但这可能不是您的担忧。
从好的方面来说,这种方法比处理循环中的行要快得多。

  • Get-Content -Raw(PSv3 +)将输入文件整体读取

  • 内联正则表达式选项(?sm)同时启用 m 最后一行和 s 单行选项:

    • m表示^$匹配每个的开头和结尾,而不是整个输入字符串。
    • s表示元字符.也匹配\n个字符,因此.*等表达式可用于匹配跨行
  • \r?\n匹配单个换行符,包括CRLF和LF变种。

  • (.*?)是捕获组(非贪婪地)捕获边界线之间的所有内容。

  • 请注意,正则表达式匹配整个输入字符串,然后将其替换为仅在第一个(也是唯一的)捕获组中捕获的感兴趣的子字符串(范围)({{ 1}})。

假设$1包含:

$file

以上产量:

-------------------------------------------------------------------------
Mapped Network Printers:
NetworkAddress\HP425DN    [DEFAULT PRINTER]
NetworkAddress\HP426DN
-------------------------------------------------------------------------
Local Printers: