在powershell中,我希望Ioop两次通过一个文本文件,但在第二个循环中我希望从第一个循环结束

时间:2016-03-08 01:47:36

标签: powershell powershell-v2.0 powershell-v3.0

我有一个要处理的文本文件。文本文件包含一些配置数据和一些网络命令。我想在一些日志文件中运行所有这些网络命令并重定向输出。
    在启动文本文件时,有一些配置信息,如文件名和文件位置。这可用于命名日志文件和日志文件的位置。这些行以一些特殊字符开头,例如'<#:'。只是要知道该行的其余部分是关于文件的配置数据而不是要执行的命令。
现在,在我想开始执行网络命令之前(从一些特殊字符开始,比如'<:'),首先我要读取有关文件的所有配置信息,即文件名,位置,覆盖然后我可以运行所有命令并将输出转储到日志文件中。
我使用get-content迭代器遍历整个文本文件。

问题:有没有办法再次从特定行开始循环文件?
这样我就可以先处理配置信息(循环直到我第一次遇到要执行的命令,记住这个行号),创建日志文件,然后继续运行命令并将输出重定向到日志文件(从最后记住的行号循环)。 配置文件看起来像:

<#Result_File_Name:dump1.txt
<#Result_File_Location:C:\powershell
<:ping www.google.com
<:ipconfig
<:traceroute www.google.com
<:netsh interface ip show config

我的powerhsell脚本如下:

$content = Get-Content C:\powershell\config.txt
foreach ($line in $content)
{
if($line.StartsWith("<#Result_File_Name:")) #every time i am doing this, even for command line
{
    $result_file_arr = $line.split(":")
    $result_file_name = $result_file_arr[1]
    Write-Host $result_file_name
}
#if($line.StartsWith("<#Result_File_Location:"))#every time i am doing this, even for command line
#{
#   $result_file_arr = $line.split(":")
#   $result_file_name = $result_file_arr[1]
#}
if( $conf_read_over =1)
{
    break;
}
if ($line.StartsWith("<:")) #In this if block, i need to run all commands
{
    $items = $line.split("<:")
    #$items[0]
    #invoke-expression $items[2] > $result_file_name
    invoke-expression $items[2] > $result_file_name
}
}

2 个答案:

答案 0 :(得分:1)

如果所有配置信息都以<#开头,则只需先单独处理。一旦完成,您可以假设其余的是命令吗?

# Collect config lines and process
$config = $content | Where-Object{$_.StartsWith('<#')} | ForEach-Object{
        $_.Trim("<#") -replace "\\","\\" -replace "^(.*?):(.*)" , '$1 = $2'
} | ConvertFrom-StringData

# Process all the lines that are command lines. 
$content | Where-Object{!$_.StartsWith('<#') -and ![string]::IsNullOrEmpty($_)} | ForEach-Object{
   Invoke-Expression $_.trimstart("<:")
}

我在配置部分有点过分了。我所做的是将其转换为hashtable。现在,您将获得配置选项,因为它们位于文件中,可作为对象访问。

$config

Name                           Value                                                                                                                                                         
----                           -----                                                                                                                                                         
Result_File_Name               dump1.txt                                                                                                                                                     
Result_File_Location           C:\powershell  

代码的小型重新配置(缺少某些部分)如下所示。您很可能需要根据自己的需要调整它。

# Collect config lines and process
$config = ($content | Where-Object{$_.StartsWith('<#')} | ForEach-Object{
        $_.Trim("<#") -replace "\\","\\" -replace "^(.*?):(.*)" , '$1 = $2'
} | Out-String) | ConvertFrom-StringData

# Process all the lines that are command lines. 
$content | Where-Object{!$_.StartsWith('<#') -and ![string]::IsNullOrEmpty($_)} | ForEach-Object{
   Invoke-Expression $_.trimstart("<:") | Add-Content -Path $config.Result_File_Name 
}

答案 1 :(得分:0)

根据您的评论,您仍然对您的重启循环逻辑感到好奇,这是原始问题的一部分。我将此添加为单独的答案。我仍然更喜欢我的另一种方法。

# Use a flag to determine if we have already restarted. Assume False
$restarted = $false
$restartIndexPoint = 4
$restartIndex = 2

for($contentIndex = 0; $contentIndex -lt $content.Length; $contentIndex++){
    Write-Host ("Line#{0} : {1}" -f $contentIndex, $content[$contentIndex])

    # Check to see if we are on the $restartIndexPoint for the first time
    if(!$restarted -and $contentIndex -eq $restartIndexPoint){
        # Set the flag so this does not get repeated. 
        $restarted = $true

        # Reset the index to repeat some steps over again.
        $contentIndex = $restartIndex
    }
}

请记住,在设置数字时,数组索引为0。例如,第20行是字符串数组中的元素19。

在循环中我们运行检查。如果它通过,我们将当前索引更改为更早的内容。 write-host只会打印行,以便您可以看到&#34;重新启动&#34;一部分。我们需要设置一个标志,以便我们不会运行无限循环。