用于替换文件中的文本并将其保存的功能

时间:2020-06-16 13:13:17

标签: powershell

我是新编程人员,我正在尝试改进脚本的以下代码,我正考虑制作一个函数来对其进行改进,但我不知道从哪里开始或它是否是最佳选择。

$replaceText01 = (Get-Content -path $copyFileLocation -Raw) -replace '"INSTANCENAME="TEST""',$NUEVAINESTANCIA

Set-Content $copyFileLocation $replaceText01

$replaceText02 = (Get-Content -path $copyFileLocation -Raw) -replace '"INSTANCEID="TEST""',$NUEVAINESTANCIAID

Set-Content $copyFileLocation $replaceText02

$replaceText03 = (Get-Content -path $copyFileLocation -Raw) -replace "NT Service\SQLAgent#TEST", $CUENTAAGTN

Set-Content $copyFileLocation $replaceText03

$replaceText04 = (Get-Content -path $copyFileLocation -Raw) -replace "NT Service\MSSQL#TEST", $CUENTASQLSER

Set-Content $copyFileLocation $replaceText04

$user = "$env:UserDomain\$env:USERNAME"

write-host $user

$replaceText = (Get-Content -path $copyFileLocation -Raw) -replace "##MyUser##", $user

Set-Content $copyFileLocation $replaceText

3 个答案:

答案 0 :(得分:1)

首先,我可能会尝试仅读取一次文件。然后,由于您正在执行许多类似的操作,因此我将所有与操作有关的数据放入一个数组中,然后遍历这些数据。

在这段代码中,我首先读取了文件。然后,我定义了所有应该替换的字符串以及应该替换它们的字符串。然后,我使用循环来遍历数据,以便我们不会一直重复相同的代码。

$data = Get-Content -Path $copyFileLocation -Raw

$replacements = @(
    @('"INSTANCENAME="TEST""', $NUEVAINESTANCIA),
    @('"INSTANCEID="TEST""', $NUEVAINESTANCIAID),
    @("NT Service\SQLAgent#TEST", $CUENTAAGTN),
    @("NT Service\MSSQL#TEST", $CUENTASQLSER),
    @("##MyUser##", "$env:UserDomain\$env:USERNAME")
)

$replacements | ForEach-Object {
    $data = $data.Replace($_[0], $_[1])
}

Set-Content -Path $copyFileLocation -Value $data

如果您使用管道而不是将数据分配给变量,也有可能使它更短

$data = Get-Content -Path $copyFileLocation -Raw

@(
    @('"INSTANCENAME="TEST""', $NUEVAINESTANCIA),
    @('"INSTANCEID="TEST""', $NUEVAINESTANCIAID),
    @("NT Service\SQLAgent#TEST", $CUENTAAGTN),
    @("NT Service\MSSQL#TEST", $CUENTASQLSER),
    @("##MyUser##", "$env:UserDomain\$env:USERNAME")
) | ForEach-Object {
    $data = $data.Replace($_[0], $_[1])
}

Set-Content -Path $copyFileLocation -Value $data

编辑:错过了您在询问如何使其成为函数的问题。

通过查看您的操作,我假设您正在修改SQL无人值守安装文件,并已如此命名。

这里的一个好主意是使大多数参数成为强制性的,因此可以确保用户至少指定了所有必需的参数。也许您以后想指定MyUser,因此这是具有默认值的参数的理想选择。

Function Set-SQLInstallFileVariables {
    Param(
        [Parameter(Mandatory)][string]$FilePath,
        [Parameter(Mandatory)][string]$NUEVAINESTANCIA,
        [Parameter(Mandatory)][string]$NUEVAINESTANCIAID,
        [Parameter(Mandatory)][string]$CUENTAAGTN,
        [Parameter(Mandatory)][string]$CUENTASQLSER,
        [string]$MyUser = "$env:UserDomain\$env:USERNAME"
    )

    $data = Get-Content -Path $FilePath -Raw

    @(
        @('"INSTANCENAME="TEST""', $NUEVAINESTANCIA),
        @('"INSTANCEID="TEST""', $NUEVAINESTANCIAID),
        @("NT Service\SQLAgent#TEST", $CUENTAAGTN),
        @("NT Service\MSSQL#TEST", $CUENTASQLSER),
        @("##MyUser##", $MyUser)
    ) | ForEach-Object {
        $data = $data.Replace($_[0], $_[1])
    }

    Set-Content -Path $copyFileLocation -Value $data
}

答案 1 :(得分:0)

首先要注意的是,每次替换时都要反复读写文件,这不是很有效。 这是不需要的。一旦读取,内容就在字符串变量中,并且可以在写回文件之前在内存中进行多次操作。

一种方法是使用包含搜索和替换字符串的字符串数组。 为了使它正常工作,两个数组必须具有相同数量的元素。

$inputFile  = 'D:\Test\TheFile.txt'          # your input file path here ($copyFileLocation)
$outputFile = 'D:\Test\TheReplacedFile.txt'  # for safety create a new file instead of overwriting the original

$searchStrings  = '"INSTANCENAME="TEST""','"INSTANCEID="TEST""',"NT Service\SQLAgent#TEST","NT Service\MSSQL#TEST","##MyUser##"
$replaceStrings = $NUEVAINESTANCIA, $NUEVAINESTANCIAID, $CUENTAAGTN, $CUENTASQLSER, "$env:UserDomain\$env:USERNAME"

# get the current content of the file
$content = Get-Content -path $copyFileLocation -Raw

# loop over the search and replace strings to do all replacements
for ($i = 0; $i -lt $searchStrings.Count; $i++) {
    $content = $content -replace [regex]::Escape($searchStrings[$i]), $replaceString[$i]
}

# finally, write the updated content to a (new) file
$content | Set-Content -Path $copyFileLocation

另一种方法是使用同时存储搜索字符串和替换字符串的Hashtable

$inputFile  = 'D:\Test\TheFile.txt'          # your input file path here ($copyFileLocation)
$outputFile = 'D:\Test\TheReplacedFile.txt'  # for safety create a new file instead of overwriting the original

$hash = @{
    '"INSTANCENAME="TEST""'    = $NUEVAINESTANCIA
    '"INSTANCEID="TEST""'      = $NUEVAINESTANCIAID
    "NT Service\SQLAgent#TEST" = $CUENTAAGTN
    "NT Service\MSSQL#TEST"    = $CUENTASQLSER
    "##MyUser##"               = "$env:UserDomain\$env:USERNAME"
}

# get the current content of the file
$content = Get-Content -path $copyFileLocation -Raw

# loop over the items in the hashtable to do all replacements
$hash.GetEnumerator() | ForEach-Object {
    # the `$_` is an automatic variable you get within a ForEach-Object{}
    # It represents a single item on each iteration.
    $content = $content -replace [regex]::Escape($_.Key), $_.Value
}

# finally, write the updated content to a (new) file
$content | Set-Content -Path $copyFileLocation

在两种情况下,我们都使用-replace,这是不区分大小写的正则表达式替换。因为您的搜索字符串包含在正则表达式中有特殊含义的字符(#\),所以我们需要使用[regex]::Escape()

对其进行转义。

希望有帮助

答案 2 :(得分:0)

这是我的尝试。它并不意味着要精益。而是要真正弄清楚它在做什么,同时又要充满功能(太多),并阻止您多次获取内容。

看到其他人回答后,他们的代码更好。希望我的代码易于阅读,并为您提供有关使用管道和函数的更好的主意:)

    Function Replace1 {Process{$_ -replace '"INSTANCENAME="TEST""',$NUEVAINESTANCIA}}
    Function Replace2 {Process{$_ -replace '"INSTANCEID="TEST""',$NUEVAINESTANCIAID}}
    Function Replace3 {Process{$_ -replace "NT Service\SQLAgent#TEST", $CUENTAAGTN}}
    Function Replace4 {Process{$_ -replace "NT Service\MSSQL#TEST", $CUENTASQLSER}}
    Function Replace6 {Process{$_ -replace "##MyUser##", $user}}

    $user = "$env:UserDomain\$env:USERNAME"

    Write-Host $user

    Get-Content -path $copyFileLocation | Replace1 | Replace2 | Replace3 | Replace4 | Replace5 | Replace6 | Set-Content -path $copyFileLocation