解析文件中的多行并替换

parse multilines from a file and replace

我需要读取一个文件,内容如下:

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= 之后和 , 之前检索到的内容。

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

$file = 'D:\sources\scripts.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 语句的每一行设置任何内容,每次都重新编写文件,但幸运的是,脚本对您不起作用,因此它不会删除您的文件。另外,由于您试图通过管道传输到 Set-Content,因此管道末端没有输出,您绝对没有向 $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.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