Capture multiline, multi-group to Powershell varia

2019-02-25 01:32发布

问题:

Ideally, I would like to create an object from ipconfig that allows us to drilldown to each adapter's attributes like this: $ip.$lan.$mac for the lan adapter's mac address.

To start, I would like to develop a way to capture these 3 groups (adapter type, adapter name, adapter attributes) per adapter match into Powershell variables (objects are preferred): https://regex101.com/r/wZ3sV1/1

Here are some ideas to capture three parts of the Ethernet adapter section, but they are only capturing "Ethernet adapter Local Area Connection:":

$ip = ipconfig /all

$ip_lan = $ip | Select-String -pattern "(Ethernet [^a]*adapter) (Local[^:]+):\s*(([^\n]+\n)*)" -AllMatches | Foreach {$_.Matches} | ForEach-Object {$_.Value}

$regex_lan = [regex]"(Ethernet [^a]*adapter) (Local[^:]+):\n*(( +[^\n]+\n)*)"
$regex_lan.Matches($ip)
$regex_lan.Matches($ip).value

Also, is there a way to capture the name of the group extraction like this?:

   Description . . . . . . . . . . . : Realtek PCIe GBE Family Controller

becomes Description = Realtek PCIe GBE Family Controller

回答1:

I know this doesn't directly answer your question. But rather than parsing the output of ipconfig with Regex. You could instead use Get-NetIPConfiguration to get a powershell object that is easier to deal with.

PS> $ip = Get-NetIPConfiguration
PS> $ip

InterfaceAlias       : Ethernet
InterfaceIndex       : 12
InterfaceDescription : Intel(R) Ethernet Connection I217-LM
NetProfile.Name      : xyz.com
IPv4Address          : 10.20.102.162
IPv6DefaultGateway   :
IPv4DefaultGateway   : 10.20.102.1
DNSServer            : 10.20.100.9
                       10.20.100.11
                       10.20.100.13

PS> $ip.IPv4Address

IPAddress         : 10.20.102.162
InterfaceIndex    : 12
InterfaceAlias    : Ethernet
AddressFamily     : IPv4
Type              : Unicast
PrefixLength      : 23
PrefixOrigin      : Dhcp
SuffixOrigin      : Dhcp
AddressState      : Preferred
ValidLifetime     : 05:16:53
PreferredLifetime : 05:16:53
SkipAsSource      : False
PolicyStore       : ActiveStore
PSComputerName    :

Thus you can do the following to get the values you are looking to acquire.

$ip.InterfaceAlias
$ip.InterfaceDescription
$ip.IPv4Address.IPAddress

To get the MAC the address you can use the Get-NetAdapter cmdlet.

$adapter = Get-NetAdapter
$adapter.MacAddress

You can correlate the two pieces of information using the InterfaceIndex. Then return a hashtable that makes each accessible. The following creates an array of these combined objects.

$combined = Get-NetIPConfiguration | ForEach-Object {
    $adapter = Get-NetAdapter -InterfaceIndex $_.InterfaceIndex
    @{ IP = $_; Adapter = $adapter }
}


回答2:

Another approach, if you want (1) an object and (2) something that should work in older versions of PowerShell, is to pull the network information using WMI:

$adapters = Get-WmiObject -Class Win32_NetworkAdapterConfiguration

$adapters | Format-Table Description,IPAddress,MACAddress

$enabled = $adapters | Where-Object{$_.IPEnabled -eq $true}

You can use the following to explore the full set of data that you get per adapter:

$enabled | Format-List *


回答3:

If you want to pull data out of strings (with regexes) and assign to variables, I think what you are looking for are named capture groups, which you can use in a manner similar to the following:

(?<word1>\w+)

Then you can pull these out of the $matches hashtable by name, for example:

PS> "hello world!" -match '(?<word1>\w+)'
True

PS> $matches["word1"]
hello

You can have multiple named capture groups in the same regex, but each one will need to have distinct names. Armed with this you should be able to match the various bits of text you want and give them names to be picked up easily afterwards.

The following blog talks about this concept a little more:

  • http://tasteofpowershell.blogspot.co.uk/2012/01/named-groups-in-regular-expressions.html


回答4:

Looking at the output of IPCONFIG /ALL, it looks like there are 3 different types of data being returned - the header section at the beginning and the an arbitrary number of sections for active and inactive adapters, each with a different format and set of data returned.

Here is a set of regular expressions that can be used to parse each one, and capture the values presented:

$Header_Regex = 
@'
(?m)Windows IP Configuration

   Host Name . . . . . . . . . . . . : (.*)
   Primary Dns Suffix  . . . . . . . : (.*)
   Node Type . . . . . . . . . . . . : (.*)
   IP Routing Enabled. . . . . . . . : (.*)
   WINS Proxy Enabled. . . . . . . . : (.*)

'@


$Active_Adapter_Regex  =
@'
(?m)(.+? adapter .+):

   Connection-specific DNS Suffix  . : (.*)
   Description . . . . . . . . . . . : (.*)
   Physical Address. . . . . . . . . : (.*)
   DHCP Enabled. . . . . . . . . . . : (.*)
   Autoconfiguration Enabled . . . . : (.*)
   Link-local IPv6 Address . . . . . : (.*) 
   IPv4 Address. . . . . . . . . . . : (.*)
   Subnet Mask . . . . . . . . . . . : (.*)
   Lease Obtained. . . . . . . . . . : (.*)
   Lease Expires . . . . . . . . . . : (.*)
   Default Gateway . . . . . . . . . : (.*)
   DHCP Server . . . . . . . . . . . : (.*)
   DHCPv6 IAID . . . . . . . . . . . : (.*)
   DHCPv6 Client DUID. . . . . . . . : (.*)
   DNS Servers . . . . . . . . . . . : ((?:.|\n)*)
   NetBIOS over Tcpip. . . . . . . . : (.*)
'@

$Inactive_Adapter_Regex = 
@'
(?m)(.+? adapter .+):

   Media State . . . . . . . . . . . : (.*)
   Connection-specific DNS Suffix  . : (.*)
   Description . . . . . . . . . . . : (.*)
   Physical Address. . . . . . . . . : (.*)
   DHCP Enabled. . . . . . . . . . . : (.*)
   Autoconfiguration Enabled . . . . : (.*)

'@

$Cmd_Output = (ipconfig /all | out-string) 

$header = 
if ($Cmd_Output -match $Header_Regex)
  {$matches}

$Inactive_Adapters = 
[regex]::Matches($Cmd_Output,$Inactive_Adapter_Regex) 

$Active_Adapters =
[regex]::Matches($Cmd_Output,$Active_Adapter_Regex) 

chew on that a bit, and let me know if that's making any sense.