Powershell Open File, Edit File, Update File - document lock issue - powershell

I have a text file with a list of multiple files that exceeded x characters. What I am trying to do is open each file, scan each line of the file, and if a file is more than x characters long I move the line to the next line so the file does not exceed x characters. That piece works great. The problem I am having is updating the text file I am trying to change/edit. I suspect the lock is the powershell script since the script is reading the file. Does anyone have any ideas on what I can do to update the original text file or remove the lock? Thanks for any help! My code is below:
[int] $limit = 131
$path = get-content C:\document\fix.txt
foreach ($f in $path)
{
Get-Content -path $f |
ForEach-Object {
$line = $_
for ($i = 0; $i -lt $line.Length; $i += $limit)
{
$length = [Math]::Min($limit, $line.Length - $i)
$line.SubString($i, $length)
}
} |
Set-Content $f
}

I figured it out! I had to put ( ) around get-content. Basically means - finish what you are doing before going to the next step.
[int] $limit = 131
$path = get-content C:\Soarian\fix.txt
foreach ($f in $path)
{
(Get-Content -path $f) |
ForEach-Object {
$line = $_
for ($i = 0; $i -lt $line.Length; $i += $limit)
{
$length = [Math]::Min($limit, $line.Length - $i)
$line.SubString($i, $length)
}
} |
Set-Content $f -Force
}

Related

Reducing amout of lines in variable within loop in Powershell

I have a txt file containing 10000 lines. Each line is an ID.
Within every loop iteration I want to select 100 lines, put them in a special format and do something. I want to do this until the document is finished.
The txt looks like this:
406232C1331283
4062321N022075
4062321H316457
Current approach:
$liste = get-content "C:\x\input.txt"
foreach ($item in $liste) {
azcopy copy $source $target --include-pattern "*$item*" --recursive=true
}
The system will go throug the TXT file and make a copy request for every name it finds in the TXT file. Now the system is able to handle like 300 search-patterns in one request. like
azcopy copy $source $target --include-pattern "*id1*;*id2*;*id3*"
How can I extract 300 items from the document at once, separate them with semicolon and embedd them in wildcard? I tried to pipe everyting in a variable and work with -skip.
But it seems not easy to handle :(
Use the -ReadCount parameter to Get-Content to send multiple lines down the pipeline:
Get-Content "C:\x\input.txt" -ReadCount 300 | ForEach-Object {
$wildCards = ($_ | ForEach-Object { "*$_*" } -join ';'
azcopy copy $source $target --include-pattern $wildCards --recursive=true
}
Do you want 100 or 300 at a time? ;-)
I'm not sure if I really got what the endgoal is but to slice a given amount of elements in chunks of a certain size you can use a for loop like this:
$liste = Get-Content -Path 'C:\x\input.txt'
for ($i = 0; $i -lt $Liste.Count; $i += 100) {
$Liste[$i..$($i + 99)]
}
Now if I got it right you want to join these 100 elements and surround them with certain cahrachters ... this might work:
'"*' + ($Liste[$i..$($i + 99)] -join '*;*') + '*"'
Together it would be this:
$liste = Get-Content -Path 'C:\x\input.txt'
for ($i = 0; $i -lt $Liste.Count; $i += 100) {
'"*' + ($Liste[$i..$($i + 99)] -join '*;*') + '*"'
}
There's many ways, here's one of them...
First I would split array to chunks of 100 elements each, using this helper function:
Function Split-Array ($list, $count) {
$aggregateList = #()
$blocks = [Math]::Floor($list.Count / $count)
$leftOver = $list.Count % $count
for($i=0; $i -lt $blocks; $i++) {
$end = $count * ($i + 1) - 1
$aggregateList += #(,$list[$start..$end])
$start = $end + 1
}
if($leftOver -gt 0) {
$aggregateList += #(,$list[$start..($end+$leftOver)])
}
$aggregateList
}
For example to split your list into chunks of 100 do this:
$Splitted = Split-Array $liste -count 100
Then use foreach to iterate each chunk and join its elements for the pattern you need:
foreach ($chunk in $Splitted)
{
$Pattern = '"' + (($chunk | % {"*$_*"}) -join ";") + '"'
azcopy copy $source $target --include-pattern $Pattern --recursive=true
}

Powershell script to apply Caption-Abstract on image from .txt file

Question answered!
Feel free to use code below, alter to correct paths on your system.
[Array] $arrayFromFile = Get-Content -Path '<path>\renameFileTitle.txt'
$iterator = 0
$files = Get-ChildItem "<path>\*.jpg"
$arrayFromFile[0]
foreach ($file in $files){
$i = $arrayFromFile[$iterator]
<path>\exiftool.exe exiftool -Caption-Abstract="$i" $file.FullName
$iterator++
}
You are setting $i = 0 again in every iteration. Move it outside the loop.
# initialization
$i = 0
foreach ($file in $files) {
C:\Users\Chris\Desktop\Pics\exiftool.exe exiftool -Caption-Abstract=$arrayFromFile[$i] $file.FullName
# increase at every iteration
$i++
}

Nested while loop only runs once

I am trying to use this script to add text to every file in a folder. It is working, but only on the first file in the folder. The for statement seems to be working because it is giving an accurate count of the files in the folder, but only modifying the first file. I feel like I am missing something stupid here.
$fullPath = "M:\BHX\DrillTeqConversion"
$reader = [System.IO.File]::OpenText("M:\BHX\DrillteqConversion.txt")
$lineNumberx = 25
function get200Files($path) {
$mprFiles = #(Get-ChildItem $path -include *.mpr -Recurse)
if ($mprFiles -ne $NULL) {
$mprFileCount = 0
For ($i = 0; $i -lt $mprFiles.Length; $i++) {
$mprFileCount += 1
$thisFile = $mprFiles[$i]
while($null -ne ($line = $reader.ReadLine())) {
$textToAdd = $line
$newLineToAdd = "`n"
$fileContent = Get-Content $thisFile
$fileContent[$lineNumberx-1] += $newLineToAdd
$fileContent[$lineNumberx-1] += $textToAdd
$fileContent | set-Content $thisFile
$lineNumberx = $lineNumberx + 1
}
}
Write-Host ("A total of " + $mprFileCount + " files were converted.")
}
}
get200Files $fullPath
[System.IO.File]::OpenText("M:\BHX\DrillteqConversion.txt") with ReadLine() only allows reading through a file once. So you cannot loop through the file endlessly without reopening it or using another strategy. Code samples below have been reduced for simplicity.
for ($i = 0; $i -lt $mprFiles.Length; $i++) {
# for loop code before while loop
$reader = [System.IO.File]::OpenText("M:\BHX\DrillteqConversion.txt")
while($null -ne ($line = $reader.ReadLine())) {
# while loop code
}
# After while loop but inside of For loop
$reader.Dispose()
$reader.Close()
}
You could make a new parameter for your function and pass that into OpenText() as well.
function get200Files($path,$FileToRead) {
for ($i = 0; $i -lt $mprFiles.Length; $i++) {
# for loop code before while loop
$reader = [System.IO.File]::OpenText($FileToRead)
while($null -ne ($line = $reader.ReadLine())) {
# while loop code
}
# After while loop but inside of For loop
$reader.Dispose()
$reader.Close()
}
}
$fullPath = "M:\BHX\DrillTeqConversion"
$ReaderPath = "M:\BHX\DrillteqConversion.txt"
get200Files $fullPath $ReaderPath

Keep lines from line X then delete others if does not contain pattern

I am trying to manipulate a textfile. I want it to keep the first X numbers of lines and after that it should look for a string pattern. If a line contains the pattern it should be kept otherwise deleted.
I got both things to work separately but not together. It works to keep lines until X and remove the rest. And I got it to work to remove all lines except for lines with a pattern, but I can't get it to work for both together.
EDIT: here is the code:
$data = Get-Content test.md
$newdata = ""
$n = 0
Foreach ($line in $data) {
if ($n++ -ge 6) {
$newdata += $line | Where{$_ -match '\[R\]'}
} else {
$newdata += $line
}
$newdata += " `r`n"
}
$newdata > test2.md
The problem is the lines are still there as empty lines. But they should be completely deleted.
$data = Get-Content test.md
$newdata = ""
$n = 0
Foreach ($line in $data) {
if ($n++ -gt 6) {
if ($line -match '\[R\]') {
$newdata += $line + " `r`n"
}
} else {
$newdata += $line + " `r`n"
}
}
$newdata > test2.md
got it to work like that.
You could use
"test.md" | % {
Get-Content $_ -TotalCount 6
(Select-String -path $_ -match '\[R \]' -AllMatches).Line
} | Out-File test2.md -Encoding Ascii

powershell result of 'if condition' write to a outfile

In powershell i am writing a script using 'if' condition to check a folder for files received in last 2 hours. The code works fine and the output is written to the screen, instead i want it to write to a file which can be emailed.
Request for kind help.
Regards
Abhijeet
EDIT: Code
$f = 'D:\usr\for_check'
$files = ls $f
Foreach ($file in $files)
{
$createtime = $file.CreationTime
$nowtime = get-date
if (($nowtime - $createtime).totalhours -le 2)
{
"$file"
}
}
You can either use the redirection operator > or Out-File
Examples:
"abc" > c:\out.txt
"abc" | Out-File c:\out.txt
Your code is way too complicated. Something like this would be more PoSh:
$src = "D:\usr\for_check"
$out = "C:\output.txt"
$append = $false
Get-ChildItem $src | ? {
$_.CreationTime -ge (Get-Date).AddHours(-2)
} | % { $_.Name } | Out-File $out -Append:$append
You will want to use the >> operator instead of > or out-file operators as they will overwrite the file every time it's used. Whereas the >> operator will write to the file on the next line.
Example:
$file >> c:\out.txt
Writing each line to the file inside the loop can cause a lot of disk I/O.
You can wrap the loop in a script block, and then output all the lines to the file in one write operation.
$f = 'D:\usr\for_check'
$files = ls $f
&{Foreach ($file in $files)
{
$createtime = $file.CreationTime
$nowtime = get-date
if (($nowtime - $createtime).totalhours -le 2)
{
"$file"
}
}
} | set-content c:\outfile.tx