Reputation: 357
I need to filter the content of a variable to exclude all the lines with matching strings from a SubnetExceptions.txt
file as filter, just as a grep -v
command.
The $Value
variable suffered lots of treatments in order to achieve the format I need.
The working part of the code is as follows:
$Value=netsh dhcp server show mibinfo | findstr "Subnet Addresses"
$Value=$Value -replace "Subnet","% `n Subnet"
$Value=$Value -replace "No. of Addresses in use","AddressesInUse"
$Value=$Value -replace "No. of free Addresses","AddressesFree"
$Value=$Value -replace '^.|.$', ' '
$Value=$Value -replace ' ', ""
$Value=$Value -replace ' ', " "
$Value= -join $Value
$Value=$Value -replace '\n', ''
$Value=$Value -replace "% ", "`n"
$Value=$Value -replace ' = ', '='
These first 11 lines of the ps1 treats the output ($Value
) of that command from this:
Subnet = 10.1.8.0. No. of Addresses in use = 11. No. of free Addresses = 18. Subnet = 10.1.9.0. No. of Addresses in use = 1. No. of free Addresses = 201. Subnet = 10.1.11.0. No. of Addresses in use = 188. No. of free Addresses = 61. Subnet = 10.1.12.0. No. of Addresses in use = 207. No. of free Addresses = 44. Subnet = 10.1.13.0. No. of Addresses in use = 149. No. of free Addresses = 100.
to this:
Subnet=10.1.8.0 AddressesInUse=11 AddressesFree=18 Subnet=10.1.9.0 AddressesInUse=1 AddressesFree=201 Subnet=10.1.11.0 AddressesInUse=188 AddressesFree=61 Subnet=10.1.12.0 AddressesInUse=207 AddressesFree=44 Subnet=10.1.13.0 AddressesInUse=149 AddressesFree=100
These replace lines work on linebreaks, dots, spaces, and "variable=value" formatting. I'll need the subnet values to sit in the same line so I can filter them out, hence the string treatments.
The actual output of the command is 278 lines long with more of the same, so I trimmed it to 5 lines in order to keep it minimal to allow reproducing it in lab.
The content of the filter file (C:\Scripts\SubnetExceptions.txt) reads as follows:
10.1.12.0 10.1.13.0
These are the last two subnet values, that I want to filter out. That's what has been tested so far (adding it right below the treatments above):
$Filter = (Get-Content '.\SubnetExceptions.txt' |
ForEach-Object {[regex]::Escape($_)}) -join '|'
($Value) -notmatch $Filter | Set-Content '.\output.txt'
The expected result should be:
Subnet=10.1.8.0 AddressesInUse=11 AddressesFree=18 Subnet=10.1.9.0 AddressesInUse=1 AddressesFree=201 Subnet=10.1.11.0 AddressesInUse=188 AddressesFree=61
Where the last 2 lines would be removed due to the filter, but instead the output file writes only the value "false".
Upvotes: 1
Views: 4228
Reputation: 200293
Build a regular expression from the content of your second file:
$re = (Get-Content '.\filter.txt' | ForEach-Object {[regex]::Escape($_)}) -join '|'
Then use that filter to exclude matching lines from your first file:
(Get-Content '.\MyList.txt') -notmatch $re | Set-Content '.\output.txt'
Use Tee-Object
instead of Set-Content
if you need the output written to both a file and STDOUT.
Edit:
Now that we can see the broader picture we might be able to offer some more thorough advice. For one thing I would suggest to change your handling of the netsh
output to something like this:
$Value = netsh dhcp server show mibinfo | findstr "Subnet Addresses" | Out-String
$Value = $Value -replace '(?ms)\.\r?\n\s+No\. of ', "`t"
$Value = $Value -replace 'Addresses in use', 'AddressesInUse'
$Value = $Value -replace 'free Addresses', 'AddressesFree'
$Value = $Value -replace ' '
$Value = $Value -split '\r?\n'
$Value = $Value -replace '\.$'
That will give you a list of tab-separated rows that are probably easier to handle than the single string you have now.
Note that you could also daisy-chain the operations listed above in a single statement:
$Value = (netsh dhcp server show mibinfo | findstr "Subnet Addresses" | Out-String) `
-replace '(?ms)\.\r?\n\s+No\. of ', "`t" `
-replace 'Addresses in use', 'AddressesInUse' `
...
I would, however, stick with the form you chose despite the multiple assignments, because it provides better maintainability. You can easily disable or enable individual operations simply by commenting/uncommenting a line.
With your data in the form of a list of rows the regular expression filter will now work as expected:
$Value -notmatch $Filter | Tee-Object -FilePath '.\output.txt'
The reason why that didn't work before is that you had a single string instead of an array of strings.
With all of that said, I would strongly recommend to re-design your solution. While PowerShell is perfectly capable of parsing and handling strings you're ignoring many features that could make your life a lot easier.
For one thing, there are DHCP cmdlets that will give you the data in object form, removing the need to parse the string output of netsh
. But even if you can't use them for some reason you can still transform the string output into objects, e.g. like this:
...
$Value = $Value -split '\r?\n'
$Value = $Value -replace '\.$'
$obj = $Value | ForEach-Object {
$ht = $_ -replace '\t', "`n" | ConvertFrom-StringData
New-Object -Type PSObject -Property $ht
}
or like this:
$Value = netsh dhcp server show mibinfo | findstr "Subnet Addresses" | Out-String
$Value = $Value -replace '(?ms)\.\r?\n\s+No\. of ', "`t"
$Value = $Value -replace ' '
$obj = $Value -split '\r?\n' | Where-Object {
$_ -match '=(\d+\.\d+\.\d+\.\d+)\t.*?=(\d+)\t.*?=(\d+)'
} | ForEach-Object {
New-Object -Type PSObject -Property @{
'Subnet' = $matches[1]
'Used' = [int]$matches[2]
'Free' = [int]$matches[3]
}
}
With your data in the form of a list of objects like that you can simplify your filtering to something like this, because you can now compare individual properties instead of having to match partial strings:
$Filter = Get-Content '.\SubnetExceptions.txt'
$obj | Where-Object {
$Filter -notcontains $_.Subnet
} | Export-Csv '.\output.csv' -NoType
You can also export the data in a structured format like CSV that will allow for simplified transfer/import should further processing of the data be required.
Upvotes: 7
Reputation: 114
I would recommend you to use compare-object cmdlet.
$refference = get-content C:\text_file1.txt
$difference = get-content C:\text_file2.txt
Compare-Object -ReferenceObject $refference -DifferenceObject $difference -IncludeEqual | Where sideindicator -ne "==" | select -ExpandProperty inputobject
Upvotes: -1