Use Powershell to print out line number of code matching a RegEx - regex
I think we have a bunch of commented out code in our source, and rather than delete it immediately, we've just left it. Now I would like to do some cleanup.
So assuming that I have a good enough RegEx to find comments (the RegEx below is simple and I could expand on it based on our coding standards), how do I take the results of the file that I read up and output the following:
Filename
Line Number
The actual line of code
I think I have the basis of an answer here, but I don't know how to take the file that I've read up and parsed with RegEx and spit it out in this format.
I'm not looking for the perfect solution - I just want to find big blocks of commented out code. By looking at the result and seeing a bunch of files with the same name and sequential line numbers, I should be able to do this.
$Location = "c:\codeishere"
[regex]$Regex = "//.*;" #simple example - Will expand on this...
$Files = get-ChildItem $Location -include *cs -recurse
foreach ($File in $Files) {
$contents = get-Content $File
$Regex.Matches($contents) | WHAT GOES HERE?
}
You could do:
dir c:\codeishere -filter *.cs -recurse | select-string -Pattern '//.*;' | select Line,LineNumber,Filename
gci c:\codeishere *.cs -r | select-string "//.*;"
The select-string cmdlet already does exactly what you're asking for, though the filename displayed is a relative path.
I would go personally even further. I would like to compute number of consecutive following lines. Then print the file name, count of lines and the lines itself. You may sort the result by count of lines (candidates for delete?).
Note that my code doesn't count with empty lines between commented lines, so this part is considered as two blocks of commented code:
// int a = 10;
// int b = 20;
// DoSomething()
// SomethingAgain()
Here is my code.
$Location = "c:\codeishere"
$occurences = get-ChildItem $Location *cs -recurse | select-string '//.*;'
$grouped = $occurences | group FileName
function Compute([Microsoft.PowerShell.Commands.MatchInfo[]]$lines) {
$local:lastLineNum = $null
$local:lastLine = $null
$local:blocks = #()
$local:newBlock = $null
$lines |
% {
if (!$lastLineNum) { # first line
$lastLineNum = -2 # some number so that the following if is $true (-2 and lower)
}
if ($_.LineNumber - $lastLineNum -gt 1) { #new block of commented code
if ($newBlock) { $blocks += $newBlock }
$newBlock = $null
}
else { # two consecutive lines of commented code
if (!$newBlock) {
$newBlock = '' | select File,StartLine,CountOfLines,Lines
$newBlock.File, $newBlock.StartLine, $newBlock.CountOfLines, $newBlock.Lines = $_.Filename,($_.LineNumber-1),2, #($lastLine,$_.Line)
}
else {
$newBlock.CountOfLines += 1
$newBlock.Lines += $_.Line
}
}
$lastLineNum=$_.LineNumber
$lastLine = $_.Line
}
if ($newBlock) { $blocks += $newBlock }
$blocks
}
# foreach GroupInfo objects from group cmdlet
# get Group collection and compute
$result = $grouped | % { Compute $_.Group }
#how to print
$result | % {
write-host "`nFile $($_.File), line $($_.StartLine), count of lines: $($_.CountOfLines)" -foreground Green
$_.Lines | % { write-host $_ }
}
# you may sort it by count of lines:
$result2 = $result | sort CountOfLines -desc
$result2 | % {
write-host "`nFile $($_.File), line $($_.StartLine), count of lines: $($_.CountOfLines)" -foreground Green
$_.Lines | % { write-host $_ }
}
If you have any idea how to improve the code, post it! I have a feeling that I could do it using some standard cmdlets and the code could be shorter..
I would look at doing something like:
dir $location -inc *.cs -rec | `
%{ $file = $_; $n = 0; get-content $_ } | `
%{ $_.FileName = $file; $_.Line = ++$n; $_ } | `
?{ $_ -match $regex } | `
%{ "{0}:{1}: {2}" -f ($_.FileName, $_.Line, $_)}
I.e. add extra properties to the string to specify the filename and line number, which can be carried through the pipeline after the regex match.
(Using ForEach-Object's -begin/-end script blocks should be able to simplify this.)
Related
Powershell: Replace only fist occurence of a line/string in entire file
I have following beggining of a Powershell script in which I would like to replace the values of variables for different enviroment. $SomeVar1 = "C:\path\to\file\a" $SomeVar1 = "C:\path\to\file\a" # Copy for test - Should not be rewriten $SomeVar2 = "C:\path\to\file\b" # Note $SomeVar1 = "C:\path\to\file\a" - Should not be rewriten When I run the rewrite script, the result should look like this: $SomeVar1 = "F:\different\path\to\file\a" $SomeVar1 = "C:\path\to\file\a" # Copy for test - Should not be rewrite $SomeVar2 = "F:\different\path\to\file\b" # Note $SomeVar1 = "C:\path\to\file\a" - Should not be rewriten Current script that does(n't) rewrite: $arr = #( [PSCustomObject]#{Regex = '$SomeVar1 = "'; Replace = '$SomeVar1 = "F:\different\path\to\file\a"'} [PSCustomObject]#{Regex = '$SomeVar2 = "'; Replace = '$SomeVar1 = "F:\different\path\to\file\b"'} ) for ($i = 0; $i -lt $arr.Length; $i++) { $ArrRegex = [Regex]::Escape($arr[$i].Regex) $ArrReplace = $arr[$i].Replace # Get full line for replacement $Line = Get-Content $Workfile | Select-String $ArrRegex | Select-Object -First 1 -ExpandProperty Line # Rewrite part $Line = [Regex]::Escape($Line) $Content = Get-Content $Workfile $Content -replace "^$Line",$ArrReplace | Set-Content $Workfile } This replaces all the occurences in file on the start of the line (and I need only the 1st one) and doest not replace the one in Note which is okay. Then I found this Powershell: Replace last occurence of a line in a file which does the exact oposite of what I need, only rewrites the last occurence of the string and it does it in the Note aswell and I would somehow like to change it to do the opposite - 1st occurence, line begining (Wont target the Note) Code in my case looks like this: # Rewrite part $Line = [Regex]::Escape($Line) $Content = Get-Content $Workfile -Raw $Line = "(?s)(.*)$Line" $ArrReplace = "`$1$ArrReplace" $Content -replace $Line,$ArrReplace | Set-Content $Workfile Do you have any recommendations on how to archive my goal, or is there a more sothisticated way to replace variables for powershell scripts like this? Thanks in advance.
So I finally figured it out, I had to add Select-String "^$ArrRegex" during $Line creation to exclude any string that were on on line beggining and then use this Regex to do the job: ^(?s)(.*?\n)$Line In my case it does the following: Only selects 1st occurnece on the beggining of the line and replaces it. It ignores everything else and when re-run, does not rewrite others. The copies of vars will not really exist in final version and will be set once like $Var1 = "Value" and never changed during script, but I wanted to be sure that I won't replace something by mistake. The final replacing part does look like this: for ($i = 0; $i -lt $arr.Length; $i++) { $ArrRegex = [Regex]::Escape($arr[$i].Regex) $ArrReplace = $arr[$i].Replace $Line = Get-Content $Workfile | Select-String "^$ArrRegex" | Select-Object -First 1 -ExpandProperty Line $Line = [Regex]::Escape($Line) $Line = "^(?s)(.*?\n)$Line" $ArrReplace = "`$1$ArrReplace" $Content -replace $Line, $ArrReplace | Set-Content $Workfile }
You could possibly use flag variables like below to only do the first replacement for each of your regex patterns. $Altered = Get-Content -Path $Workfile | Foreach-Object { if(-not $a) { #If replacement hasn't been done, replace $_ = $_ -replace 'YOUR_REGEX1','YOUR_REPLACEMENT1' if($_ -match 'YOUR_REPLACEMENT1') { $a = 'replacement done' } #Set Flag } if(-not $b) { #If replacement hasn't been done, replace $_ = $_ -replace 'YOUR_REGEX2','YOUR_REPLACEMENT2' if($_ -match 'YOUR_REPLACEMENT2') { $b = 'replacement done' } #Set Flag } $_ # Pipe back to $Altered } $Altered | Set-Content -Path $WorkFile
Just reverse the RegEx, if that is what you are after: Clear-Host #' abc abc abc '# -replace '^(.*?)\babc\b', '$1HelloWorld' # Results <# HelloWorld abc abc #>
Powershell script using RegEx to look for a pattern in one .txt and find line in a second .txt
I have a real "headsmasher" on my plate. I have this piece of script: $lines = Select-String -List -Path $sourceFile -Pattern $pattern -Context 20 foreach ($id in $lines) { if (Select-String -Quiet -LiteralPath export.txt -Pattern "$($Matches[1]).+$($id.Pattern)") { } else { Select-String -Path $sourceFile -Pattern $pattern -Context 20 >> $duplicateTransactionsFile } } but it is not working for me as I wanted it to. I have two .txt files: "$sourcefile = source.txt" and "export.txt" The source.txt looks like something like this: Some text here *********** ------------------------------------------------ F I N A L C O U N T 1 9 , 9 9 ************** ** [0000123456] ID Number:0000123456 Complete! ****************! *********** Some other text here******* ------------------------------------------------ F I N A L C O U N T 9 , 9 9 ********** ** [0000789000] ID Number:0000789000 Complete! ******************! ************ The export.txt is like this: 0000123456 19,99 0000555555 ,89 0000666666 3,05 0000777777 31,19 0000789000 9,99 What I am trying to do is look into source.txt and search for the number that I enter (spaced out in my case) *e.g: "9,99" but only that. As you can see, the next number in the source.txt is "19,99" and it also contains "9,99" but I do not want it to be matched. and once I find the number, look for the next line in the source.txt that contains the text "ID Number:" then get the numbers right after the ":" Once I get those numbers after the ":", I want to now look into the export.txt and see if the numbers after the ":" are there and whether it has the "9,99" on the same line next to it but exactly "9,99" and nothing else lie "19,99", "29,99", and so on. Then the rest is easy: if (*true*) { do this } else { do that } Could you guys give me some love here and help a brother out? I very much appreciate any help or hint you could share. Best of wishes!
You could approach this like below: # read the export.txt file and convert to a Hashtable for fast lookup $export = ((Get-Content -Path 'D:\Test\export.txt').Trim() -replace '\s+', '=') -join "`r`n" | ConvertFrom-StringData # read the source file and split into multiline data blocks $source = ((Get-Content -Path 'D:\Test\source.txt' -Raw) -split '-{2,}').Trim() | Where-Object { $_ -match '(?sm)^\s?F I N A L C O U N T' } # make sure the number given is spaced-out $search = (((Read-Host "Search for Final Count number") -replace '\s' -split '') -join ' ').Trim() Write-Host "Looking for a matching item using Final Count '$search'" # see if we can find a data block that matches the $search $blocks = $source | Where-Object { $_ -match "(?sm)^F I N A L C O U N T\s+$search\s?$" } if (!$blocks) { Write-Host "No item in source.txt could be found with Final Count '$search'" -ForegroundColor Red } else { # loop over the data block(s) and pick the one that matches the search count $blocks | ForEach-Object { # parse out the ID $id = $_ -replace '(?sm).*ID Number:(\d+).*', '$1' # check if the $export Hashtable contains a key with that ID number if ($export.Contains($id)) { # check if that item has a value of $search without the spaces if ($export[$id] -eq ($search -replace '\s')) { # found it; do something Write-Host "Found a match in the export.txt" -ForegroundColor Green } else { # found ID with different FinalCount Write-Host "An item with ID '$id' was found, but with different Final Count ($($export[$id]))" -ForegroundColor Red } } else { # ID not found Write-Host "No item with ID '$id' could be found in the export.txt" -ForegroundColor Red } } } If as per your comment, you would like the code to loop over the Final Count numbers found in the source.txt file instead of a user typing in a number to search for, you can shorten the above code to: # read the export.txt file and convert to a Hashtable for fast lookup $export = ((Get-Content -Path 'D:\Test\export.txt').Trim() -replace '\s+', '=') -join "`r`n" | ConvertFrom-StringData # read the source file and split into multiline data blocks $blocks = ((Get-Content -Path 'D:\Test\source.txt' -Raw) -split '-{2,}').Trim() | Where-Object { $_ -match '(?sm)^\s?F I N A L C O U N T' } if (!$blocks) { Write-Host "No item in source.txt could be found with Final Count '$search'" -ForegroundColor Red } else { # loop over the data block(s) $blocks | ForEach-Object { # parse out the FINAL COUNT number to look for in the export.txt $search = ([regex]'(?sm)^F I N A L C O U N T\s+([\d,\s]+)$').Match($_).Groups[1].Value # remove the spaces, surrounding '0' and trailing comma (if any) $search = ($search -replace '\s').Trim('0').TrimEnd(',') Write-Host "Looking for a matching item using Final Count '$search'" # parse out the ID $id = $_ -replace '(?sm).*ID Number:(\d+).*', '$1' # check if the $export Hashtable contains a key with that ID number if ($export.Contains($id)) { # check if that item has a value of $search without the spaces if ($export[$id] -eq $search) { # found it; do something Write-Host "Found a match in the export.txt with ID: $($export[$id])" -ForegroundColor Green } else { # found ID with different FinalCount Write-Host "An item with ID '$id' was found, but with different Final Count ($($export[$id]))" -ForegroundColor Red } } else { # ID not found Write-Host "No item with ID '$id' could be found in the export.txt" -ForegroundColor Red } } }
There are surely multiple valid ways to accomplish this. Here is my approach: (See comments for explanations. Let me know if you have any questions) param ( # You can provide this when calling the script using "-Search 9,99" # If not privided, powershell will prompt to enter the value [Parameter(Mandatory)] $Search, $Source = "source.txt", $Export = "export.txt" ) # insert spaces $pattern = $Search.ToCharArray() -join " " # Search for the value in the source file. $found = $false switch -Regex -File $Source { # This regex looks for something that is not a number, # followed by only whitespace, and then your (spaced) search value. # This makes sure "19,99" is not matched with "9,99". # You could use a more elaborate regex here, but for your example, # this one should work fine. "\D\s+$pattern" { $found = $true } "ID Number:(\d+)" { # Get the ID number from the match. $id = $Matches[1] # If the search value was found # (that means, this ID number is immediately followed by the search value) # we can stop looking. if ($found) { break } } } # quick check if the value was actually found if (-not $found) { throw "Value $Search not found in $Source." } # Search for the id in the export file. switch -Regex -File $Export { "$id\s+(\S+)" { # Get the amount value from the match $value = $Matches[1] # If the value matches your search... if ($value -eq $search) { # do this } else { # otherwise do that } break } } Note: You could additionally convert the values to decimal to account for different text representations when searching and comparing.
Skip Header Row in a High Performance Powershell Regex Script Block
I received some amazing help from Stack Overflow ... however ... it was so amazing I need a little more help to get to closer to the finish line. I'm parsing multiple enormous 4GB files 2X per month. I need be able to be able to skip the header, count the total lines, matched lines, and the not matched lines. I'm sure this is super-simple for a PowerShell superstar, but at my newbie PS level my skills are not yet strong. Perhaps a little help from you would save the week. :) Data Sample: ID FIRST_NAME LAST_NAME COLUMN_NM_TOO_LON5THCOLUMN 10000000001MINNIE MOUSE COLUMN VALUE LONGSTARTS 10000000002MICKLE ROONEY MOUSE COLUMN VALUE LONGSTARTS Code Block (based on this answer): #$match_regex matches each fixed length field by length; the () specifies that each matched field be stored in a capture group: [regex]$match_regex = '^(.{10})(.{50})(.{50})(.{50})(.{50})(.{3})(.{8})(.{4})(.{50})(.{2})(.{30})(.{6})(.{3})(.{4})(.{25})(.{2})(.{10})(.{3})(.{8})(.{4})(.{50})(.{2})(.{30})(.{6})(.{3})(.{2})(.{25})(.{2})(.{10})(.{3})(.{10})(.{10})(.{10})(.{2})(.{10})(.{50})(.{50})(.{50})(.{50})(.{8})(.{4})(.{50})(.{2})(.{30})(.{6})(.{3})(.{2})(.{25})(.{2})(.{10})(.{3})(.{4})(.{2})(.{4})(.{10})(.{38})(.{38})(.{15})(.{1})(.{10})(.{2})(.{10})(.{10})(.{10})(.{10})(.{38})(.{38})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})$' Measure-Command { & { switch -File $infile -Regex { $match_regex { # Join what all the capture groups matched with a tab char. $Matches[1..($Matches.Count-1)].Trim() -join "`t" } } } | Out-File $outFile }
You only need to keep track of two counts - matched, and unmatched lines - and then a Boolean to indicate whether you've skipped the first line $first = $false $matched = 0 $unmatched = 0 . { switch -File $infile -Regex { $match_regex { if($first){ # Join what all the capture groups matched with a tab char. $Matches[1..($Matches.Count-1)].Trim() -join "`t" $matched++ } $first = $true } default{ $unmatched++ # you can remove this, if the pattern always matches the header $first = $true } } } | Out-File $outFile $total = $matched + $unmatched
Using System.IO.StreamReader reduced the processing time to about 20% of what it had been. This was absolutely needed for my requirement. I added logic and counters without sacrificing much on performance. The field counter and row by row comparison is particularly helpful in finding bad records. This is a copy/paste of actual code but I shortened some things, made some things slightly pseudo code, so you may have to play with it to get things working just so for yourself. Function Get-Regx-Data-Format() { Param ([String] $filename) if ($filename -eq 'FILE NAME') { [regex]$match_regex = '^(.{10})(.{10})(.{10})(.{30})(.{30})(.{30})(.{4})(.{1})' } return $match_regex } Foreach ($file in $cutoff_files) { $starttime_for_file = (Get-Date) $source_file = $file + '_' + $proc_yyyymm + $source_file_suffix $source_path = $source_dir + $source_file $parse_file = $file + '_' + $proc_yyyymm + '_load' +$parse_target_suffix $parse_file_path = $parse_target_dir + $parse_file $error_file = $file + '_err_' + $proc_yyyymm + $error_target_suffix $error_file_path = $error_target_dir + $error_file [regex]$match_data_regex = Get-Regx-Data-Format $file Remove-Item -path "$parse_file_path" -Force -ErrorAction SilentlyContinue Remove-Item -path "$error_file_path" -Force -ErrorAction SilentlyContinue [long]$matched_cnt = 0 [long]$unmatched_cnt = 0 [long]$loop_counter = 0 [boolean]$has_header_row=$true [int]$field_cnt=0 [int]$previous_field_cnt=0 [int]$array_length=0 $parse_minutes = Measure-Command { try { $stream_log = [System.IO.StreamReader]::new($source_path) $stream_in = [System.IO.StreamReader]::new($source_path) $stream_out = [System.IO.StreamWriter]::new($parse_file_path) $stream_err = [System.IO.StreamWriter]::new($error_file_path) while ($line = $stream_in.ReadLine()) { if ($line -match $match_data_regex) { #if matched and it's the header, parse and write to the beg of output file if (($loop_counter -eq 0) -and $has_header_row) { $stream_out.WriteLine(($Matches[1..($array_length)].Trim() -join "`t")) } else { $previous_field_cnt = $field_cnt #add year month to line start, trim and join every captured field w/tabs $stream_out.WriteLine("$proc_yyyymm`t" + ` ($Matches[1..($array_length)].Trim() -join "`t")) $matched_cnt++ $field_cnt=$Matches.Count if (($previous_field_cnt -ne $field_cnt) -and $loop_counter -gt 1) { write-host "`nError on line $($loop_counter + 1). ` The field count does not match the previous correctly ` formatted (non-error) row." } } } else { if (($loop_counter -eq 0) -and $has_header_row) { #if the header, write to the beginning of the output file $stream_out.WriteLine($line) } else { $stream_err.WriteLine($line) $unmatched_cnt++ } } $loop_counter++ } } finally { $stream_in.Dispose() $stream_out.Dispose() $stream_err.Dispose() $stream_log.Dispose() } } | Select-Object -Property TotalMinutes write-host "`n$file_list_idx. File $file parsing results....`nMatched Count = $matched_cnt UnMatched Count = $unmatched_cnt Parse Minutes = $parse_minutes`n" $file_list_idx++ $endtime_for_file = (Get-Date) write-host "`nEnded processing file at $endtime_for_file" $TimeDiff_for_file = (New-TimeSpan $starttime_for_file $endtime_for_file) $Hrs_for_file = $TimeDiff_for_file.Hours $Mins_for_file = $TimeDiff_for_file.Minutes $Secs_for_file = $TimeDiff_for_file.Seconds write-host "`nElapsed Time for file $file processing: $Hrs_for_file`:$Mins_for_file`:$Secs_for_file" } $endtime = (Get-Date -format "HH:mm:ss") $TimeDiff = (New-TimeSpan $starttime $endtime) $Hrs = $TimeDiff.Hours $Mins = $TimeDiff.Minutes $Secs = $TimeDiff.Seconds write-host "`nTotal Elapsed Time: $Hrs`:$Mins`:$Secs"
Loop through a text file and Extract a set of 100 IP's from a text file and output to separate text files
I have a text file that contains around 900 IP's. I need to create batch of 100 IP's from that file and output them into new files. That would create around 9 text files. Our API only allows to POST 100 IP's at a time. Could you please help me out here? Below is the format of the text file 10.86.50.55,10.190.206.20,10.190.49.31,10.190.50.117,10.86.50.57,10.190.49.216,10.190.50.120,10.190.200.27,10.86.50.58,10.86.50.94,10.190.38.181,10.190.50.119,10.86.50.53,10.190.50.167,10.190.49.30,10.190.49.89,10.190.50.115,10.86.50.54,10.86.50.56,10.86.50.59,10.190.50.210,10.190.49.20,10.190.50.172,10.190.49.21,10.86.49.18,10.190.50.173,10.86.49.49,10.190.50.171,10.190.50.174,10.86.49.63,10.190.50.175,10.13.12.200,10.190.49.27,10.190.49.19,10.86.49.29,10.13.12.201,10.86.49.28,10.190.49.62,10.86.50.147,10.86.49.24,10.86.50.146,10.190.50.182,10.190.50.25,10.190.38.252,10.190.50.57,10.190.50.54,10.86.50.78,10.190.50.23,10.190.49.8,10.86.50.80,10.190.50.53,10.190.49.229,10.190.50.58,10.190.50.130,10.190.50.22,10.86.52.22,10.19.68.61,10.41.43.130,10.190.50.56,10.190.50.123,10.190.49.55,10.190.49.66,10.190.49.68,10.190.50.86,10.86.49.113,10.86.49.114,10.86.49.101,10.190.50.150,10.190.49.184,10.190.50.152,10.190.50.151,10.86.49.43,10.190.192.25,10.190.192.23,10.190.49.115,10.86.49.44,10.190.38.149,10.190.38.151,10.190.38.150,10.190.38.152,10.190.38.145,10.190.38.141,10.190.38.148,10.190.38.142,10.190.38.144,10.190.38.147,10.190.38.143,10.190.38.146,10.190.192.26,10.190.38.251,10.190.49.105,10.190.49.110,10.190.49.137,10.190.49.242,10.190.50.221,10.86.50.72,10.86.49.16,10.86.49.15,10.190.49.112,10.86.49.32,10.86.49.11,10.190.49.150,10.190.49.159,10.190.49.206,10.86.52.28,10.190.49.151,10.190.49.207,10.86.49.19,10.190.38.103,10.190.38.101,10.190.38.116,10.190.38.120,10.190.38.102,10.190.38.123,10.190.38.140,10.190.198.50,10.190.38.109,10.190.38.108,10.190.38.111,10.190.38.112,10.190.38.113,10.190.38.114,10.190.49.152,10.190.50.43,10.86.49.23,10.86.49.205,10.86.49.220,10.190.50.230,10.190.192.238,10.190.192.237,10.190.192.239,10.190.50.7,10.190.50.10,10.86.50.86,10.190.38.125,10.190.38.127,10.190.38.126,10.190.50.227,10.190.50.149,10.86.49.59,10.190.49.158,10.190.49.157,10.190.44.11,10.190.38.124,10.190.50.153,10.190.49.40,10.190.192.235,10.190.192.236,10.190.50.241,10.190.50.240,10.86.46.8,10.190.38.234,10.190.38.233,10.86.50.163,10.86.50.180,10.86.50.164,10.190.49.245,10.190.49.244,10.190.192.244,10.190.38.130,10.86.49.142,10.86.49.102,10.86.49.141,10.86.49.67,10.190.50.206,10.190.192.243,10.190.192.241 I tried looking online to come up with a bit of working code but can't really think what would best work in this situation $IP = 'H:\IP.txt' $re = '\d*.\d*.\d*.\d*,' Select-String -Path $IP -Pattern $re -AllMatches | Select-Object -Expand Matches | ForEach-Object { $Out = 'C:\path\to\out.txt' -f | Set-Content $clientlog }
This will do what you are after $bulkIP = (get-content H:\IP.txt) -split ',' $i = 0 # Created loop Do{ # Completed an action every 100 counts (including 0) If(0 -eq $i % 100) { # If the array is a valid entry. Removing this will usually end up creating an empty junk file called -1 or something If($bulkIP[$i]) { # outputs 100 lines into a folder with the starting index as the name. # Eg. The first 1-100, the file would be called 1.txt. 501-600 would be called 501.txt etc $bulkIP[$($i)..$($i+99)] | Out-File "C:\path\to\$($bulkip.IndexOf($bulkip[$($i)+1])).txt" } } $i++ }While($i -le 1000)
what this does ... calculates the number of batches calcs the start & end index of each batch creates a range from the above creates a PSCustomObject to hold each batch creates an array slice from the range sends that out to the collection $Var shows what is in the collection & in the 1st batch from that collection here's the code ... # fake reading in a raw text file # in real life, use Get-Content -Raw $InStuff = #' 10.86.50.55,10.190.206.20,10.190.49.31,10.190.50.117,10.86.50.57,10.190.49.216,10.190.50.120,10.190.200.27,10.86.50.58,10.86.50.94,10.190.38.181,10.190.50.119,10.86.50.53,10.190.50.167,10.190.49.30,10.190.49.89,10.190.50.115,10.86.50.54,10.86.50.56,10.86.50.59,10.190.50.210,10.190.49.20,10.190.50.172,10.190.49.21,10.86.49.18,10.190.50.173,10.86.49.49,10.190.50.171,10.190.50.174,10.86.49.63,10.190.50.175,10.13.12.200,10.190.49.27,10.190.49.19,10.86.49.29,10.13.12.201,10.86.49.28,10.190.49.62,10.86.50.147,10.86.49.24,10.86.50.146,10.190.50.182,10.190.50.25,10.190.38.252,10.190.50.57,10.190.50.54,10.86.50.78,10.190.50.23,10.190.49.8,10.86.50.80,10.190.50.53,10.190.49.229,10.190.50.58,10.190.50.130,10.190.50.22,10.86.52.22,10.19.68.61,10.41.43.130,10.190.50.56,10.190.50.123,10.190.49.55,10.190.49.66,10.190.49.68,10.190.50.86,10.86.49.113,10.86.49.114,10.86.49.101,10.190.50.150,10.190.49.184,10.190.50.152,10.190.50.151,10.86.49.43,10.190.192.25,10.190.192.23,10.190.49.115,10.86.49.44,10.190.38.149,10.190.38.151,10.190.38.150,10.190.38.152,10.190.38.145,10.190.38.141,10.190.38.148,10.190.38.142,10.190.38.144,10.190.38.147,10.190.38.143,10.190.38.146,10.190.192.26,10.190.38.251,10.190.49.105,10.190.49.110,10.190.49.137,10.190.49.242,10.190.50.221,10.86.50.72,10.86.49.16,10.86.49.15,10.190.49.112,10.86.49.32,10.86.49.11,10.190.49.150,10.190.49.159,10.190.49.206,10.86.52.28,10.190.49.151,10.190.49.207,10.86.49.19,10.190.38.103,10.190.38.101,10.190.38.116,10.190.38.120,10.190.38.102,10.190.38.123,10.190.38.140,10.190.198.50,10.190.38.109,10.190.38.108,10.190.38.111,10.190.38.112,10.190.38.113,10.190.38.114,10.190.49.152,10.190.50.43,10.86.49.23,10.86.49.205,10.86.49.220,10.190.50.230,10.190.192.238,10.190.192.237,10.190.192.239,10.190.50.7,10.190.50.10,10.86.50.86,10.190.38.125,10.190.38.127,10.190.38.126,10.190.50.227,10.190.50.149,10.86.49.59,10.190.49.158,10.190.49.157,10.190.44.11,10.190.38.124,10.190.50.153,10.190.49.40,10.190.192.235,10.190.192.236,10.190.50.241,10.190.50.240,10.86.46.8,10.190.38.234,10.190.38.233,10.86.50.163,10.86.50.180,10.86.50.164,10.190.49.245,10.190.49.244,10.190.192.244,10.190.38.130,10.86.49.142,10.86.49.102,10.86.49.141,10.86.49.67,10.190.50.206,10.190.192.243,10.190.192.241 '# $SplitInStuff = $InStuff.Split(',') $BatchSize = 25 $BatchCount = [math]::Truncate($SplitInStuff.Count / $BatchSize) + 1 $Start = $End = 0 $Result = foreach ($BC_Item in 1..$BatchCount) { $Start = $End if ($BC_Item -eq 1) { $End = $Start + $BatchSize - 1 } else { $End = $Start + $BatchSize } $Range = $Start..$End [PSCustomObject]#{ IP_List = $SplitInStuff[$Range] } } $Result '=' * 20 $Result[0] '=' * 20 $Result[0].IP_List.Count '=' * 20 $Result[0].IP_List screen output ... IP_List ------- {10.86.50.55, 10.190.206.20, 10.190.49.31, 10.190.50.117...} {10.86.49.18, 10.190.50.173, 10.86.49.49, 10.190.50.171...} {10.86.50.80, 10.190.50.53, 10.190.49.229, 10.190.50.58...} {10.190.49.115, 10.86.49.44, 10.190.38.149, 10.190.38.151...} {10.86.49.32, 10.86.49.11, 10.190.49.150, 10.190.49.159...} {10.86.49.23, 10.86.49.205, 10.86.49.220, 10.190.50.230...} {10.190.50.240, 10.86.46.8, 10.190.38.234, 10.190.38.233...} ==================== {10.86.50.55, 10.190.206.20, 10.190.49.31, 10.190.50.117...} ==================== 25 ==================== 10.86.50.55 10.190.206.20 10.190.49.31 10.190.50.117 10.86.50.57 10.190.49.216 10.190.50.120 10.190.200.27 10.86.50.58 10.86.50.94 10.190.38.181 10.190.50.119 10.86.50.53 10.190.50.167 10.190.49.30 10.190.49.89 10.190.50.115 10.86.50.54 10.86.50.56 10.86.50.59 10.190.50.210 10.190.49.20 10.190.50.172 10.190.49.21 10.86.49.18
try this $cpt=0 $Rang=1 #remove old file Get-ChildItem "H:\FileIP_*.txt" -file | Remove-Item -Force (Get-Content "H:\IP.txt") -split ',' | %{ if (!($cpt++ % 100)) {$FileResult="H:\FileIP_{0:D3}.txt" -f $Rang++} # build filename if cpt divisile by 100 $_ | Out-File $FileResult -Append }
PowerShell Get-Content and replace object in a specific line
I have a text file with the following content: Static Text MachineA MachineB MachineC Just Another Line The first line has two static words (Static Text) with a space between. After those two words there are 0 or more computer names, also seperated with a space. I need to find a way to add text to the first line (second line does not change) if there are 0 computers but also if there is 1 or more computers. I need to replace all computer names with a new computer name. So the script should edit the file to get something like this: Static Text MachineX MachineY Just Another Line I've looked at the -replace function with Regex but can't figure out why it is not working. This is the script I have: $OptionsFile = "C:\scripts\OptionsFile.txt" $NewComputers = "MachineX MachineY" $content = Get-Content $OptionsFile $content | ForEach-Object { if ($_.ReadCount -eq 1) { $_ -replace '\w+', $NewComputers } else { $_ } } | Set-Content $OptionsFile I hope someone can help me out with this.
If Static Text doesn't appear elsewhere in the file, you could simply do this: $OptionsFile = "C:\scripts\OptionsFile.txt" $NewComputers = "MachineX MachineY" (Get-Content $OptionsFile) -replace '^(Static Text) .*', "`$1 $NewComputers" | Set-Content $OptionsFile If Static Text can appear elsewhere, and you only want to replace the first line, you could do something like this: $OptionsFile = "C:\scripts\OptionsFile.txt" $NewComputers = "MachineX MachineY" (Get-Content $OptionsFile) | % { if ($_.ReadCount -eq 1) { "Static Text $NewComputers" } else { $_ } } | Set-Content $OptionsFile If you only know that Static Text consists of two words in the first line, but don't know which words exactly they'll be, something like this should work: $OptionsFile = "C:\scripts\OptionsFile.txt" $NewComputers = "MachineX MachineY" (Get-Content $OptionsFile) | % { if ($_.ReadCount -eq 1) { $_ -replace '^(\w+ \w+) .*', "`$1 $NewComputers" } else { $_ } } | Set-Content $OptionsFile
Check if a line is starting with a 'Static Text ' followed by a sequence of word characters and return your string in case there a match: Get-Content $OptionsFile | foreach { if($_ -match '^Static Text\s+(\w+\s)+') { 'Static Text MachineX MachineY' } else { $_ } }