Search code examples
regexpowershellregex-grouptf-cli

RegEx to match field values in a block (tf.exe perm) TFS 2008


I am trying to write a regex to extract the blocks of information below, as well as the fields within each block. I am using Powershell.

I want to capture all "Server Item" blocks, and the following information for each one:

Server Item (1 **or more** of these items in the text)

   Identity (1 **or more** of these Identity items per Server Item)

    -- Allow (Each Identity contains **one** Allow)

    -- Deny (Each Identity contains **one** Deny)

    -- Allow (Inherited) (Each Identity contains **one** Allow (Inherited))

    -- Deny (Inherited) (Each Identity contains **one** Deny (Inherited))

The information is hierarchical (one to many for each heading to its children), as you can see.

Any answers greatly appreciated!

Sample Input text, below:

Server item: $/The/Path/Goes/Here
   Identity: Identity Number One (TYPE A)
      Allow:      
      Deny:
      Allow (Inherited): Read, Write, Checkin, Label
                         Lock, CheckinOther
      Deny (Inherited):  
====================================================================

Server item: $/The/Other/Path/Goes/Here
   Identity: Identity Number One (TYPE B)
      Allow: Read, Write, Checkin, Label
                         Lock, CheckinOther     
      Deny:
      Allow (Inherited): 
      Deny (Inherited):  
====================================================================

etc.

I have tried something like the following:

$thePattern = @"
(?<serveritem>Server item:(.|\n)*?=)
"@
$myText -match $thePattern

This does not capture all of the items and just gives me the first one! Also, how do I capture the Identity and field information for each Server item --> Identities --> Permissions?

The desired output would be to capture all of the Server items, and to be able to access each of the Identities, and for each Identity, to be able to access the permissions (Allow, Deny etc) The objective is to iterate through the blocks so as to add the information to a database for querying.

I am working on this with the following modification.

  • this includes named capture groups.
  • also note the use of (?s) to set the single-line option.
  • as powershell/.net do not support the global option, I have used [Regex]::Matches to match all.

    (?s)Server item:(?<serveritem>.*?)[\r\n]+ *Identity:(?<identity>.*?)[\r\n]+ *Allow: ?(?<allow>.*?)[\r\n]+ *Deny: ?(?<deny>.*?)[\r\n]+ *Allow \(Inherited\): ?(?<allowinherited>.*?)[\r\n]+ *Deny \(Inherited\): ?(?<denyinherited>.*?)([\r\n]+=|$)
    

Solution

  • Assuming the (text) input is as consistently formatted as your sample, you can extract the information you need with much simpler regular expressions if you break up the input and iterate in a line-by-line fashion.

    For example, given the following input with "1 or more of these Identity items per Server Item":

    Server item: $/The/Path/Goes/Here
       Identity: Identity Number One (TYPE A)
          Allow:      
          Deny:
          Allow (Inherited): Read, Write, Checkin, Label
                             Lock, CheckinOther
          Deny (Inherited):  
    ====================================================================
    
    Server item: $/The/Other/Path/Goes/Here
       Identity: Identity Number One (TYPE B)
          Allow: Read, Write, Checkin, Label
                             Lock, CheckinOther     
          Deny:
          Allow (Inherited): 
          Deny (Inherited):  
    ====================================================================
    
    Server item: $/The/Other/other/Path/Goes/Here
       Identity: Identity Number One (TYPE C)
          Allow: Read, Write, Checkin, Label
                             Lock, CheckinOther     
          Deny:
          Allow (Inherited): 
          Deny (Inherited):  
       Identity: Identity Number One (TYPE D)
          Allow: Read, Write, Checkin, Label
                             Lock, CheckinOther     
          Deny:
          Allow (Inherited): 
          Deny (Inherited): 
    

    To get the hierarchical information:

    # used .txt file for example 
    $lines = Get-Content $path;
    $result = @{};
    $serverItem = '';
    $identityItem = '';
    $currentKey = '';
    foreach ($line in $lines) {
        $key, $value = [Regex]::Split($line.Trim(), '\s*:\s*', 2);
        switch -Regex ($key) {
            '^server item' { 
                $serverItem = $value;
                $result.$serverItem = @{};
                continue;
            }
            '^identity' { 
                $identityItem = $value;
                $result.$serverItem.$identityItem = @{};
                continue;
            }
            '^[A-Za-z]+' {
                if ($value -ne $null) {
                    $currentKey = $key;
                    $result.$serverItem.$identityItem.$key = $value;
                } else {
                    $result.$serverItem.$identityItem.$currentKey += ", $key";
                }
            }
        }
    }