Can you use a negative number in the string length attribute for Substring
in PowerShell? For example:
$str.Substring($startPos, -3)
I read that in PowerShell 7 reading backwards may have been added ("negative values return the amount of substrings requested starting from the end of the input string") but it looked like that was for Split
.
Currently, I cannot upgrade to v7. I am on v4. Is it possible to do this in Version 4?
OR is there another way to read backwards on a string in PowerShell v4?
Example:
I need to replace ABCD
, but because of the commas and lack of consistent data points, it's very hard for me to find a consistent index before ABCD
. Hence, why I use LastIndexOf
to find the last comma. Now, I am hoping I can read backwards the length of $replaceStr
from the last comma, if that makes sense. $replaceStr.length
is what I was hoping to make negative.
$str = '12345,FOO FOO,ABCD,12351235'
$replaceStr = #code to get value of string that needs replaced
$str.Replace($str.Substring($str.LastIndexOf(',') + 1, $replaceStr.length), $Value)
Import-Csv method (mentioned in comments)
This is my PowerShell to import the CSV, replace name
, and then Set-Content
to the original file. When I Set-Content
the CSV file's output is empty.
#gets all the full paths of each csv file
$files = (Get-ChildItem $path -Filter '*.csv').FullName
#loops through all found csv files
$files | Foreach-Object {
#imports current csv file
$csv = Import-Csv $_ -Header foo, foofoo, name, foobar
#loops through csv
$csv | Foreach-Object {
#replaces .name with $replaceStr
$str.Replace($_.name, $replaceStr)
#set content of csv file
} | Set-Content -Path $_
}
Here is an example of my CSV file:
12345,FOO FOO,ABCD,12351235
54321,FOO BAR,ABCD,56785678
23232,FOO,ABCD,98765432
00000,FOO FOO BAR,ABCD,123456789
Trying to not overcomplicate the code, you might find it easier if you transform your string into an array via splitting on ,
then updating the 2nd to last token and lastly joining it back with ,
as delimiter:
$str = '12345,FOO FOO,ABCD,12351235'
$tokens = $str.Split(',')
$tokens[-2] = 'myNewValue'
$str = $tokens -join ','
$str # 12345,FOO FOO,myNewValue,12351235
You're really close with your example treating the files as CSV, a minor update would fix the problem:
Get-ChildItem $path -Filter '*.csv' | Foreach-Object {
$csv = $_ | Import-Csv -Header col1, col2, col3, col4
$csv | ForEach-Object {
# update the value of this property
$_.col3 = $replaceStr
# then output the updated object
$_
} | ConvertTo-Csv |
# here we're skipping the headers
Select-Object -Skip 1 |
Set-Content -LiteralPath $_.FullName
}
To update the value of a property since now you're dealing with objects due to Import-Csv
you can simply refer to the property name to be updated and assign it a new value: $obj.Property = 'mynewvalue'
. You would also need to convert these objects back to a CSV representation, for that you would be using ConvertTo-Csv
and lastly skip the headers with Select-Object
and save it back with Set-Content
.