bonafide
bonafide

Reputation: 368

How to parse text file from PowerShell to loop through

I have a text file with the following:

acl Safe_ports port 443
acl Safe_ports port 22

acl AzureDomains dstdomain .microsoft.com
acl AzureDomains dstdomain .azure.com

I want to be able to parse through this text file to get the ports and dstdomains into an array to be fed into a command in this format "$val1,$val2,$val3" or an array of comma delimited values of $ports or $urls as needed.

Example - $NetRule1 = New-AzFirewallNetworkRule -Name $name -Protocol TCP -SourceAddress * -DestinationAddress * -DestinationPort "$val1,$val2,$val3" or "$ports".

Currently, it is looping through my command but my current implementation overrides the previous value which is not the goal.

Sample:

$lines = Get-Content $file | Where-Object { $_ -notmatch '^\s+$' } 
foreach ($line in $lines) {
    $fields = $line -split '\s+'
    $rulename = $fields[1]
    $acltype = $fields[2]
    $rules = $fields[3..4]
    #$app = $field[4]
    #$hosts = $fields[1..3]

    foreach ($rule in $rules) {

        if ($acltype -match "port") {
            $port = $rule
        }
        elseif ($acltype -match "dstdomain") {
            $url = $rule
        }
    }
}

I welcome a more effective way of doing this

Upvotes: 0

Views: 2153

Answers (3)

Esperento57
Esperento57

Reputation: 17492

For import with csv (given into previous comment) :

#importation data
$Content=import-csv "c:\temp\file.csv" -d ","

#selection columns
$Ports=$Content | where ACLType -eq 'port'
$Urls=$Content | where ACLType -eq 'dstdomain'

#format result
$Ports.Rule -join ","
$Urls.Rule -join ","

Upvotes: 1

Esperento57
Esperento57

Reputation: 17492

$ports=@()
$urls=@()

Get-Content "c:\temp\test.txt" | Where { $_ -like  '* port *' -or $_ -like  '* dstdomain *' } | %{

  $Split=$_ -split ' ', 4

  if ($_ -like  '* port *')
  {
     $ports+=$Split[3] 
  }
  else
  {
     $urls+=$Split[3]  
  }

}

$ports -join ","
$urls -join ","

Upvotes: 0

AdminOfThings
AdminOfThings

Reputation: 25031

If we stick with your original approach, we can use one foreach loop and output custom objects with the data you require. From the output, we can manipulate the text.

$lines = Get-Content $file | Where-Object { $_ -notmatch '^\s*$' } 
$out = foreach ($line in $lines) {
    $fields = $line -split '\s+'
    [pscustomobject]@{
        'RuleName' = $fields[1]
    'ACLType' = $fields[2]
    'Rule' = $fields[3]
    }
}

$ports = $out.where{$_.ACLType -eq "port"}.Rule
$urls = $out.where{$_.ACLType -eq "dstdomain"}.Rule

There is no need to create a comma-separated string since your command is expecting an array on the -DestinationPort parameter. You can see the additional approach below for a simpler way to just find text elements and join them as a single string.


Alternative Approach:

You can use Select-String to find your text. Then use the -join operator to create your comma-separated string.

$urls = (Select-String $file -Pattern "(?<=dstdomain\s+)\S+").Matches.Value -join ","
$ports = (Select-String $file -Pattern "(?<=port\s+)\d+").Matches.Value -join ","

Explanation:

Select-String uses the -Pattern parameter by default to perform a regex match. It returns a MatchInfo object. In our case, this will be an array of MatchInfo objects. Accessing the .Matches.Value property outputs the matched string only.

(?<=) is the positive lookbehind assertion for regex. In both commands, it is performed to look behind the current character for strings dstdomain and port and any white space that may follow them. \d+ matches consecutive digits. \S+ matches consecutive non-white space.

The resulting arrays are joined as comma-separated strings using the -join operator.


You could technically do all of this with one Select-String. It will likely add coding complexity to separate the combined data though. Two commands just appears simpler to me.

Upvotes: 1

Related Questions