解析文件中的多行并替换

时间:2015-05-06 14:43:39

标签: parsing powershell multiline

我需要读取内容如下所示的文件:

Computer Location = afp.local/EANG
Description = RED_TXT
Device Name = EANG04W
Domain Name = afp.local
Full Name = Admintech
Hardware Monitoring Type = ASIC2
Last Blocked Application Scan Date = 1420558125
Last Custom Definition Scan Date = 1348087114
Last Hardware Scan Date = 1420533869
Last Policy Sync Date = 1420533623
Last Software Scan Date = 1420533924
Last Update Scan Date = 1420558125
Last Vulnerability Scan Date = 1420558125
LDAP Location = **CN=EANG04W**,OU=EANG,DC=afp,DC=local
Login Name = ADMINTECH
Main Board OEM Name = Dell Inc.
Number of Files = 384091
Primary Owner = **CN= LOUHICHI anoir**,OU=EANG,DC=afp,DC=localenter code here

我需要将CN=$value替换为CN=Compagny,其中$value是在CN=之后和,之前重新审核的内容。

1 个答案:

答案 0 :(得分:0)

好的,所以你真的应该更新你的问题而不是在评论中发布代码,因为它真的很难读。这就是我的想法:

$file = 'D:\sources\scripts\2.txt' 
$content = Get-Content $file | foreach ($line in $content) { 
    if ($line.Contains('CN=')) { 
        $variable = $line.Split(',').Split('=')[2] 
        $variable1 = $variable -replace $variable, "Compagny" 
    } Set-Content -path $file 
}

这确实有一些语法错误。第一行很棒,你定义了路径。然后出错了......你对Get-Content的调用很好,它将获取文件的内容,并将它们发送到管道。

你直接将它传递给ForEach循环,但这是错误的。你真正想要的是一个ForEach-Object循环(这可能令人困惑,因为在这样的管道中使用它时可以简化为ForEach)。 ForEach-Object循环不声明内部变量(例如($line in $content)),而是脚本块使用自动变量$_。所以你的循环需要变成:

Get-Content $file | ForEach { <do stuff> } | Set-Content

接下来让我们看看那个循环。您使用If语句来查看该行是否包含“CN =”,可理解且功能正常。如果你这样做,那么在逗号上分割行,然后再在等号上,选择第二条记录。嗯,你可以在分割一个字符串的时候创建一个字符串数组,并且你已经将字符串拆分了两次,但是只指定要为第二次拆分使用的数组的哪个记录。这可能是个问题。无论如何,您将该子字符串分配给$variable,然后继续用“company”替换整个内容并将该输出存储到$variable1。所以这里有几个问题。在逗号上拆分字符串后,您将拥有以下字符串数组:

"LDAP Location = **CN=EANG04W**"
"OU=EANG"
"DC=afp"
"DC=local"

这是一个包含4个字符串对象的数组。那么你试着在等号上拆分至少其中一个(因为你没有指定哪一个)。您现在有一个包含4个数组对象的数组,其中每个对象都有2个字符串对象:

("LDAP Location", "**CN", "EANG04W**")  
("OU", "EANG")  
("DC","afp")  
("DC","local")  

此时指定第三条记录(PowerShell中的数组从记录0开始,因此[2]指定第三条记录)。但是你没有在第一个数组中指定哪条记录,所以它只会抛出错误。让我们说你实际上选择了你真正想要的东西,我猜这将是“EANG04W”。 (顺便说一下,那将是$_.Split(",")[0].Split("=")[1])。然后,您将其分配给$Variable,然后继续将所有内容替换为“Company”,因此在PowerShell扩展变量之后,它将如下所示:

$variable1 = "EANG04W" -replace "EANG04W", "company"

好的,您刚刚成功将“company”分配给变量。你的If语句在那里结束。您永远不会从If语句中输出任何内容,因此Set-Content无需设置任何内容。此外,它会为每个传递给ForEach语句的每一行设置任何内容,每次都重写该文件,但幸运的是,脚本不起作用,因此它不会删除您的文件。另外,由于您尝试管道设置内容,管道末尾没有输出,您已经完全没有为$content分配任何内容。

所以让我们试着解决它,好吗?第一行?效果很好!没变。现在,我们没有在变量中保存任何内容,我们只想更新文件的内容,因此不需要$Content =。我们会继续前进,不是吗?我们将Get-Content导入ForEach循环,就像您尝试过的那样。一旦进入ForEach循环,我们将会做一些不同的事情。 -replace方法执行RegEx匹配。我们可以在这里利用它。我们将替换您对每行感兴趣的文本,如果找不到,则不会进行替换,并将每一行传递到管道上。对于ForEach

的内部,这看起来像这样
$_ -replace "(<=CN\=).*?(?=,)", "Company"

RegEx匹配的细分可以在这里看到:https://regex101.com/r/gH6hP2/1
但是,我们只是说它会在它之前找到“CN =”的文本,然后转到它之后的第一个逗号。在您的示例中,它包含两个尾随星号,但它不会触及前导星号。这是你的意图吗?这将成为示例文件的最后一行:

Primary Owner = **CN=Company,OU=EANG,DC=afp,DC=localenter code here

好吧,如果那是预期的,那么我们就有了胜利者。现在我们关闭ForEach循环,并将输出传递给Set-Content,我们都已经完成了!就个人而言,我强烈建议输出到一个新文件,以防你以后出于某种原因需要引用原始文件,这就是我要做的。

$file = 'D:\sources\scripts\2.txt'
$newfile = Join-Path (split-path $file) -ChildPath ('Updated-'+(split-path $file -Leaf))
Get-Content $file | ForEach{$_ -replace "(?<=CN\=).*?(?=,)", "Company"} | Set-Content $newfile

好的,就是这样。该代码将生成D:\ sources \ scripts \ Updated-2.txt,其中包含以下内容:

Computer Location = afp.local/EANG
Description = RED_TXT
Device Name = EANG04W
Domain Name = afp.local
Full Name = Admintech
Hardware Monitoring Type = ASIC2
Last Blocked Application Scan Date = 1420558125
Last Custom Definition Scan Date = 1348087114
Last Hardware Scan Date = 1420533869
Last Policy Sync Date = 1420533623
Last Software Scan Date = 1420533924
Last Update Scan Date = 1420558125
Last Vulnerability Scan Date = 1420558125
LDAP Location = **CN=Company,OU=EANG,DC=afp,DC=local
Login Name = ADMINTECH
Main Board OEM Name = Dell Inc.
Number of Files = 384091
Primary Owner = **CN=Company,OU=EANG,DC=afp,DC=localenter code here