Powershell主机文件编辑

时间:2016-01-27 20:16:11

标签: perl powershell host

伙计我在将Perl脚本转换为PowerShell时遇到了一些问题,我需要一些帮助。在我们机器的主机文件中,我们阻止了所有测试环境的URL。在我的PERL脚本中,根据选择的环境,它将注释掉所选环境的行以允许访问并阻止其他环境,以便测试人员不会错误地在错误的环境中执行操作。

我需要帮助转换为powershell

以下是我在PERL中的内容:

sub editHosts {
print "Editing hosts file...\n";
my $file = 'C:\\Windows\\System32\\Drivers\\etc\\hosts';
my $data = readFile($file);
my @lines = split /\n/, $data;
my $row = '1';
open (FILE, ">$file") or die "Cannot open $file\n";
foreach my $line (@lines) {
    if ($line =~ m/$web/) { 
        print FILE '#'."$line\n"; }
    else {
        if ($row > '21') {
            $line =~ s/^\#*127\.0\.0\.1/127\.0\.0\.1/;
            $line =~ s/[#;].*$//s; }
        print FILE "$line\n"; }
    $row++;
}
close(FILE);
}

以下是我在Powershell中尝试过的内容:

foreach ($line in get-content "C:\windows\system32\drivers\etc\hosts") {
if ($line -contains $web) {
$line + "#"
}

我尝试过包含set-content的变体,包括以前在主机文件中的内容等等。

任何帮助将不胜感激!

谢谢, 格兰特

4 个答案:

答案 0 :(得分:2)

-contains是一个“set”运算符,而不是子字符串运算符。试试.Contains()或者像。

答案 1 :(得分:2)

这将注释掉与变量$word匹配的行,同时从不匹配项中删除#(标题除外):

function Edit-Hosts ([string]$Web, $File = "C:\windows\system32\drivers\etc\hosts") {
    #If file exists and $web is not empty/whitespace
    if((Test-Path -Path $file -PathType Leaf) -and $web.Trim()) {
        $row = 1

        (Get-Content -Path $file) | ForEach-Object {
            if($_ -like "*$web*") {
                #Matched PROD, comment out line
                "#$($_)"
            } else { 
                #No match. If past header = remove comment
                if($row -gt 21) { $_ -replace '^#' } else { $_ }
            }
            $row++
        } | Set-Content -Path $file

    } else {
        Write-Error -Category InvalidArgument -Message "'$file' doesn't exist or Web-parameter is empty"
    }
}

用法:

Edit-Hosts -Web "PROD"

答案 2 :(得分:0)

对于Frode F.的答案,这是一个类似的答案,但我还没有评论加上我的2c值,所以必须提供替代答案。

在这个示例中,看起来像是从perl移动到PowerShell的其中一个问题是,当我们使用Get-Content获取文件的内容时,它是一个“离线”副本,即没有进行任何编辑直接到文件本身。一种方法是将新内容编译到整个文件,然后将其写回磁盘。

我认为perl中的print FILE "some text\n";构造可能与PowerShell中的"some text" | Out-File $filename -Encoding ascii -Append类似,尽管你会使用后者(1)逐行写入新的/空文件或(2)接受您附加现有内容。

关于编辑主机文件的另外两件事:

  • 请务必确保您的主机文件是ASCII编码的;我已经为一个关键的企业应用程序(5万+用户)造成了重大中断... ...
  • 您可能需要记住通过右键单击并选择以管理员身份运行来运行PowerShell / PowerShell ISE,否则您可能无法修改该文件。

无论如何,这是使用Out-File的上一个答案的版本:

$FileName = "C:\windows\system32\drivers\etc\hosts"
$web = "PROD"

# Get "offline" copy of file contents
$FileContent = Get-Content $FileName

# The following creates an empty file and returns a file
# object (type [System.IO.FileInfo])

$EmptyFile = New-Item -Path $FileName -ItemType File -Force

foreach($Line in $FileContent) {
  if($Line -match "$web") {
    "# $Line" | Out-File $EmptyFile -Append -Encoding ascii
  } else {
    "$Line" | Out-File $EmptyFile -Append -Encoding ascii
  }
}

修改

  1. ($Line -match "$web")获取 $ web 变量中的任何内容,并将其视为正则表达式。在我的示例中,我假设您只是想匹配一个简单的文本字符串,但您可能正在尝试匹配IP地址等。您有几个选项:
    • 请改用($Line -like "*$web*")
    • 将$ web中的内容转换为转义正则表达式,即字面上匹配的正则表达式。使用($Line -match [Regex]::Escape($web))执行此操作。
  2. 如果该行 $ web 匹配,您还想从主机文件第21行的任何行中删除注释。在perl中,您使用了 s 替换运算符; PowerShell等效项为-replace
  3. 所以......这是foreach循环的更新版本:

    $LineCount = 1
    
    foreach($Line in $FileContent) {
      if($Line -match [Regex]::Escape($web) {
        # ADD comment to any matched line
        $Line = "#" + $Line
      } elseif($LineCount -gt 21) {
        # Uncomment the other lines
        $Line = $Line -replace '^[# ]+',''
      }
    
      # Remove 'stacked up' comment characters, if any
      $Line = $Line -replace '[#]+','#'
    
      $Line | Out-File $EmptyFile -Append -Encoding ascii
    
      $LineCount++
    }
    

    更多信息

答案 3 :(得分:0)

如果您想验证其中的内容然后添加条目,则可以使用以下内容,该内容旨在以交互方式运行,并返回您在变量中指定的所有现有条目:

注意:“ t是powershell”在'Tab'命令的脚本方法中。

$hostscontent

# Script to Verify and Add Host File Entries

$hostfile = gc 'C:\Windows\System32\drivers\etc\hosts'
$hostscontent1 = $hostfile | select-string "autodiscover.XXX.co.uk"
$hostscontent2 = $hostfile | select-string "webmail.XXX.co.uk"
$1 = "XX.XX.XXX.XX`tautodiscover.XXX.co.uk"
$2 = "webmail.XXX.co.uk"




# Replace this machines path with a path to your list of machines e.g. $machines = gc \\machine\machines.txt
$machines = gc 'c:\mytestmachine.txt'
ForEach ($machine in $machines) {

                                If ($hostscontent1 -ne $null) { 
                                Start-Sleep -Seconds 1
                                Write-Host "$machine Already has Entry $1" -ForegroundColor Green

} Else { 
        Write-Host "Adding Entry $1 for $machine" -ForegroundColor Green
        Start-Sleep -Seconds 1
        Add-Content -Path C:\Windows\System32\drivers\etc\hosts -Value "XX.XX.XXX.XX`tautodiscover.XXX.co.uk" -Force

}

                                If ($hostscontent2 -ne $null) {
                                Start-Sleep -Seconds 1
                                Write-Host "$machine Already has Entry $2" -ForegroundColor Green

} Else {
        Write-Host "Adding Entry $2 for $machine" -ForegroundColor Green
        Start-Sleep -Seconds 1
        Add-Content -Path C:\Windows\System32\drivers\etc\hosts -Value "XX.XX.XXX.XX`twebmail.XXX.co.uk" -Force

}
    }