2017-07-06 91 views
1

我是Powershell脚本编写的新手,但我觉得我忽略了一个简单的答案,希望有些人能够提供帮助。通过Powershell抓取一个txt文件的特定部分

我公司通过映射网络打印机中间部分导出来自我们所有计算机的文件。它看起来是这样的:

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

我被要求做的是复制只是映射网络打印机到一个新的文本文件。

我尝试使用选择字符串与上下文参数,但我无法知道有多少网络打印机,所以我不能猜测。

我也尝试使用下面的代码,我在此网站上发现,但它没有返回值:

$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 

我基本上要开始在“映射网络打印机”的搜索,并在下一行结束它“------”

任何帮助将不胜感激。

回答

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)匝上都 ULTI线和小号英格尔行选项:

    • m意味着^$匹配每个行的开始和结束而不是整个输入字符串。
    • s意味着元字符.\n字符匹配也是如此,从而使诸如.*一个表达式可以用于匹配跨行
  • \r?\n匹配一个换行符,CRLF和LF变种。

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

  • 注意,正则表达式的整个输入字符串匹配,然后与感兴趣刚子(范围),在第一次(也是唯一一个)捕获组($1)抓获替换它。

假设$file包含:

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

以上的产率:

NetworkAddress\HP425DN [DEFAULT PRINTER] 
NetworkAddress\HP426DN 
0

您可以使用Select-StringWhere-Object查找带有\的单词。采取这一更进一步,你可以寻找只是server\printer值与这样的正则表达式:

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

注意,这使得假设服务器名称和打印机只能使用AZ和0-9,你可能需要寻找如果这不是一个有效的假设,那么更多的字符。

这里将使用Where-Object来过滤行的例子与\

Get-Content 'C:\Users\User1\Documents\Config.txt' | Where-Object {$_ -like '*\*'} 
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 
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 
相关问题