0

We are trying to Pull AP name, bss, and ess values out of text files provided by a network team, in PowerShell 5.1. We have numerous files to go through and multiple AP Targets in each file.

Here's example of Text file. We need to extract the ap name, the ess, and bss values for each ess that matches "trustedwifi" and "guest" items only. The rest of the data is unneeded.

*********************************************************************************************************
 9/5/2021 7:42:16 AM    Target: AP01 (VC)    
*********************************************************************************************************
WIFI AP BSS Table
------------------
bss                ess              port  ip            band/ht-mode/bandwidth  ch/EIRP/max-EIRP  type  cur-cl  ap name   in-t(s)  tot-t            flags
---                ---              ----  --            ----------------------  ----------------  ----  ------  -------   -------  -----            -----
ab:cd:ef:gh:if:jk  trustedwifi      ?/?   A.b.c.d       2.4GHz/HT/20MHz         1/24.0/25.5       ap    0       AP01      0        43d:14h:48m:14s  K
ab:cd:ef:gh:if:jk  secure           ?/?   A.b.c.d       2.4GHz/HT/20MHz         1/24.0/25.5       ap    0       AP01      0        43d:14h:47m:53s  -
ab:cd:ef:gh:if:jk  guest            ?/?   A.b.c.d       2.4GHz/HT/20MHz         1/24.0/25.5       ap    0       AP01      0        22h:11m:43s      -
ab:cd:ef:gh:if:jk  trustedwifi      ?/?   A.b.c.d       5GHz/VHT/40MHz          100+/18.0/30.0    ap    0       AP01      0        43d:14h:48m:15s  K
ab:cd:ef:gh:if:jk  secure           ?/?   A.b.c.d       5GHz/VHT/40MHz          100+/18.0/30.0    ap    0       AP01      0        43d:14h:47m:54s  -
ab:cd:ef:gh:if:jk  guest            ?/?   A.b.c.d       5GHz/VHT/40MHz          100+/18.0/30.0    ap    0       AP01      0        22h:11m:44s      -

Channel followed by "*" indicates channel selected due to unsupported configured channel.
"Spectrum" followed by "^" indicates Local Spectrum Override in effect.

Num APs:6
Num Associations:0

Flags:       a = Airslice policy; A = Airslice app monitoring; c = MBO Cellular Data Capable BSS; d = Deferred Delete Pending; D = VLAN Discovered; E = Enhanced-open BSS without transition mode; I = Imminent VAP Down; K = 802.11K Enabled; m = Agile Multiband (MBO) BSS; M = WPA3-SAE mixed mode BSS; o = Enhanced-open transition mode open BSS; O = Enhanced-open BSS with transition mode; r = 802.11r Enabled; t = Broadcast TWT Enabled; T = Individual TWT Enabled; W = 802.11W Enabled; x = MBSSID Tx BSS; 3 = WPA3 BSS; 


*********************************************************************************************************
  9/5/2021 7:42:18 AM    Target: AP02    
*********************************************************************************************************
WIFI AP BSS Table
------------------
bss                ess              port  ip            band/ht-mode/bandwidth  ch/EIRP/max-EIRP  type  cur-cl  ap name   in-t(s)  tot-t            flags
---                ---              ----  --            ----------------------  ----------------  ----  ------  -------   -------  -----            -----
ab:cd:ef:gh:if:jk  trustedwifi      ?/?   A.b.c.d       2.4GHz/HT/20MHz         11/24.0/25.5      ap    0       AP02      0        43d:14h:47m:24s  K
ab:cd:ef:gh:if:jl  secure           ?/?   A.b.c.d       2.4GHz/HT/20MHz         11/24.0/25.5      ap    0       AP02      0        43d:14h:47m:3s   -
ab:cd:ef:gh:if:jm  guest            ?/?   A.b.c.d       2.4GHz/HT/20MHz         11/24.0/25.5      ap    0       AP02      0        22h:11m:43s      -
ab:cd:ef:gh:if:j0  rustedwifi       ?/?   A.b.c.d       5GHz/VHT/40MHz          108+/18.0/30.0    ap    0       AP02      0        43d:14h:47m:24s  K
ab:cd:ef:gh:if:jp  secure           ?/?   A.b.c.d       5GHz/VHT/40MHz          108+/18.0/30.0    ap    0       AP02      0        43d:14h:47m:4s   -
ab:cd:ef:gh:if:jq  guest            ?/?   A.b.c.d       5GHz/VHT/40MHz          108+/18.0/30.0    ap    0       AP02      0        22h:11m:43s      -

Preferred Output would be something like this repeated for each Ap name in the files with ALL records containing trustedwifi and guest. Repeated for every match that includes the two search criteria.

ap name           ess                   bss
AP01              Trustedwifi           ab:cd:ef:gh:if:jk
AP01              guest                 ab:cd:ef:gh:if:jm
AP02              Trustedwifi           ab:cd:ef:gh:if:jk
AP02              guest                 ab:cd:ef:gh:if:jm
.
.

Started with the following to try and solve it, but am stumped on how to get the data extracted and formatted properly to export to a .csv file

# Specify the directory to search
$directory = "C:\Your\Directory" 

# Specify the search terms
$searchTerms = "error", "warning", "exception"

# Get all .txt files in the directory
$files = Get-ChildItem -Path $directory -Filter "*.txt"

# Search for each term in each file
foreach ($file in $files) {
    foreach ($term in $searchTerms) {
        $matches = Select-String -Path $file.FullName -Pattern $term

        if ($matches) {
            Write-Host "File: $($file.FullName)"
            foreach ($match in $matches) {
                Write-Host "Line $($match.LineNumber): $($match.Line)"
            }
            Write-Host ""
        }
    }
}

But expect to end up with the output example from above.

0

3 Answers 3

1

As a general solution, you might consider this (custom) ConvertFrom-SourceTable cmdlet:

The latest version (0.5.1, just uploaded) supports suppressing certain columns by supplying an empty column name:

Install-Script -Name ConvertFrom-SourceTable
Get-Content $Files | Select-String -Pattern '^\w\w:\w\w:\w\w:\w\w:\w\w:\w\w' |
  ConvertFrom-SourceTable -Header 'bss', 'ess', '', '', '', '', '', '', 'ap name'

Explanation:

  • The Select-String -Pattern '^\w\w:\w\w:\w\w:\w\w:\w\w:\w\w' command, selects all the lines (data rows) that start with a mac address
  • Each data row is passed to the ConvertFrom-SourceTable cmdlet which determines the columns based on their fixed size (and spaces in between).
  • The header names (-Header 'bss', 'ess', '', '', '', '', '', '', 'ap name') are applied to each of the corresponding column with the same index

Note that the above command will not work if the concerned tables have different column widths. In that case you might convert each table separately:

$Files | ForEach-Object { 
    Get-Content $_ | Select-String -Pattern '^\w\w:\w\w:\w\w:\w\w:\w\w:\w\w' |
      ConvertFrom-SourceTable -Header 'bss', 'ess', '', '', '', '', '', '', 'ap name'
}

For either command the order of the (captured) columns needs to same (e.g. the 'ap name' column is presumed to be the 9th column).

Sign up to request clarification or add additional context in comments.

7 Comments

Checking out feasibility of solutions offered, thanks for the input.
We have a portion of the input file that changes table column header from band to Phy is there a way in the following $patternbss variable to match on either band or phy for that particular field? -- \s+(?<band>or phy?[^\s]+)? Thanks,
Also, an interesting bit some of the flag fields are completely empty of any characters in the input file, we do not seem to be matching on those and need to. Is there a way to make the pattern match the flag field whether there is a character there or not?
Yes Ron, working on that now
Interesting, appreciate the input. thanks.
|
0

Try following

$filename = "c:\temp\test.txt"

$lines = Get-Content -Path $filename

$patternAP = 'Target:\s+(?<ap>[^\s]+)'
$patternBss = '^(?<bss>[a-z]{2}:[a-z]{2}:[a-z]{2}:[a-z]{2}:[a-z]{2}:[a-z0-9]{2})\s+(?<ess>[^\s]+)\s+(?<port>[^\s]+)\s+(?<ip>[^\s]+)\s+(?<band>[^\s]+)\s+(?<ch>[^\s]+)\s+(?<type>[^\s]+)\s+(?<cur>[^\s]+)\s+(?<apname>[^\s]+)\s+(?<in>[^\s]+)\s+(?<tot>[^\s]+)\s+(?<flags>[^\s]+)'
$table = [System.Collections.Generic.List[pscustomobject]]::new()
foreach($line in $lines)
{
   if($line -match $patternAP)
   {
      $line -match $patternAP | Out-Null
      $ap = $matches.ap
   } `
   else
   {

      if($line -match $patternBss)
      {
         $line -match $patternBss | Out-Null
         if($matches.ess -eq 'guest')
         {
             $newRow = [pscustomobject]@{
                ap = $ap
                bss = $matches.bss
                ess = $matches.ess
                port = $matches.port
                ip = $matches.ip
                'band/ht-mode/bandwidth' = $matches.band
                'ch/EIRP/max-EIRP' = $matches.ch
                type = $matches.type
                'curl-cl' = $matches.cur
                'ap name' = $matches.apname
                'in-t(s)' = $matches.in
                'tot-t' = $matches.tot
                'flags' = $matches.flags
             }
             $table.Add($newRow)  | Out-Null
         }
      }
   }
}

$table | format-list

Results

ap                     : AP01
bss                    : ab:cd:ef:gh:if:jk
ess                    : guest
port                   : ?/?
ip                     : A.b.c.d
band/ht-mode/bandwidth : 2.4GHz/HT/20MHz
ch/EIRP/max-EIRP       : 1/24.0/25.5
type                   : ap
curl-cl                : 0
ap name                : AP01
in-t(s)                : 0
tot-t                  : 22h:11m:43s
flags                  : -

ap                     : AP01
bss                    : ab:cd:ef:gh:if:jk
ess                    : guest
port                   : ?/?
ip                     : A.b.c.d
band/ht-mode/bandwidth : 5GHz/VHT/40MHz
ch/EIRP/max-EIRP       : 100+/18.0/30.0
type                   : ap
curl-cl                : 0
ap name                : AP01
in-t(s)                : 0
tot-t                  : 22h:11m:44s
flags                  : -

ap                     : AP02
bss                    : ab:cd:ef:gh:if:jm
ess                    : guest
port                   : ?/?
ip                     : A.b.c.d
band/ht-mode/bandwidth : 2.4GHz/HT/20MHz
ch/EIRP/max-EIRP       : 11/24.0/25.5
type                   : ap
curl-cl                : 0
ap name                : AP02
in-t(s)                : 0
tot-t                  : 22h:11m:43s
flags                  : -

ap                     : AP02
bss                    : ab:cd:ef:gh:if:jq
ess                    : guest
port                   : ?/?
ip                     : A.b.c.d
band/ht-mode/bandwidth : 5GHz/VHT/40MHz
ch/EIRP/max-EIRP       : 108+/18.0/30.0
type                   : ap
curl-cl                : 0
ap name                : AP02
in-t(s)                : 0
tot-t                  : 22h:11m:43s
flags                  : -

After reviewing code I found a simpler method. Original code was geting AP from line between the asterisks. New code is getting AP from column 'ap -name'

$filename = "c:\temp\test.txt"

$lines = Get-Content -Path $filename

$patternBss = '^(?<bss>[a-z]{2}:[a-z]{2}:[a-z]{2}:[a-z]{2}:[a-z]{2}:[a-z0-9]{2})\s+(?<ess>[^\s]+)\s+(?<port>[^\s]+)\s+(?<ip>[^\s]+)\s+(?<band>[^\s]+)\s+(?<ch>[^\s]+)\s+(?<type>[^\s]+)\s+(?<cur>[^\s]+)\s+(?<apname>[^\s]+)\s+(?<in>[^\s]+)\s+(?<tot>[^\s]+)\s+(?<flags>[^\s]+)'
$table = [System.Collections.Generic.List[pscustomobject]]::new()
foreach($line in $lines)
{
   if($line -match $patternBss)
   {
      $line -match $patternBss | Out-Null
      if($matches.ess -eq 'guest')
      {
          $newRow = [pscustomobject]@{
             bss = $matches.bss
             ess = $matches.ess
             port = $matches.port
             ip = $matches.ip
             'band/ht-mode/bandwidth' = $matches.band
             'ch/EIRP/max-EIRP' = $matches.ch
             type = $matches.type
             'curl-cl' = $matches.cur
             'ap name' = $matches.apname
             'in-t(s)' = $matches.in
             'tot-t' = $matches.tot
             'flags' = $matches.flags
         }
         $table.Add($newRow)  | Out-Null
      }
   }
}

$table | format-list

Comments

0

Assuming all columns in your files are in the same order and all fields are separated by at least 2 spaces like you show in your post, then a quick and dirty way of parsing out the values you need could be like below:

$sourcePath = 'D:\Test'
$outputFile = 'D:\Test\result.csv'

$result = Get-ChildItem -Path $sourcePath -Filter '*.txt' -File | ForEach-Object {
    switch -Regex -File $_.FullName {
        '^..:..:..:..:..:..' {
            $data = $_ -split '\s{2,}'
            # You could process only items where column 'ess' ($data[1]) 
            # is either 'trustedwifi' or 'guest' at this point:
            if ($data[1] -match 't?rustedwifi|guest') {
                # output an object with the columns needed
                [PsCustomObject]@{
                    appname = $data[8]
                    ess     = $data[1]
                    bss     = $data[0]
                }
            }
        }
    }
}

# save the result
$result | Export-Csv -Path $outputFile -NoTypeInformation

# if you didn't use the filtering for 'trustedwifi' or 'guest' in the above, you can do that here:
$result | Where-Object { $_.ess -match 't?rustedwifi|guest' } | Export-Csv -Path $outputFile -NoTypeInformation

P.S. In your example, there is a t missing in one of the rows for trustedwifi, so that is why the regex now uses t?rustedwifi. If that is just a typo in your post and does not occur in the real files, just remove the questionmark in the regex.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.