I get an element from the array, I check whether the line exists in the file or not. If it exists, then I change it to an element from the second array by index. Everything works fine. The problem is that if a string from an array is similar to a string in a file, then it is considered that it is in the file. For example, "#TokenUri" and "#Token" are treated the same. The "$initial_array" variable is taken from the vault secret store. Added to the code for ease of debugging. All keys and values are a random set of characters, close to reality. It is necessary to look for a strict one-to-one correspondence.
$pathFile = 'D:\Git\Gitlab\powershell\appsettings.json'
$array_key = #()
$array_value = #()
$initial_array = "#{#TokenUri=ovnsinv-iovi0ew-dvoiw9; #User=Vasia; #Timeout=00:00:30; #ExternalServices=gdgdfg; #Password=xvnen834n9; #ApplicationName=Tupoe; #Uri=https://gitlab.com/}" -replace '[#,{,},;]'
$array= $initial_array.Split('=').Split(' ')
for ($i = 0; $i -le $array.Count; $i++) {
if ( ($i % 2) -eq 0) {
$array[$i] | ForEach-Object { $array_key+=$_ }
}
else {
$array[$i] | ForEach-Object { $array_value+=$_ }
}
}
for ($i=0; $i -lt $array_key.Length; $i++) {
if ((Get-Content -Path $pathFile) -match $array_key[$i]) {
(Get-Content -Path $pathFile) -replace $array_key[$i], $array_value[$i] | Set-Content -Path $pathFile
}
else {
$element = $array_key[$i]
throw "Element $element is missing from the file - $pathFile"
break
}
}
Related
I have a text file that contains a string I want to modify.
Example text file contents:
abc=1
def=2
ghi=3
If I run this code:
$file = "c:\test.txt"
$MinX = 100
$MinY = 100
$a = (Get-Content $file) | %{
if($_ -match "def=(\d*)"){
if($Matches[1] -gt $MinX){$_ -replace "$($Matches[1])","$($MinX)" }
}
}
$a
The result is:
def=100
If I omit the greater-than check like so:
$a = (Get-Content $file) | %{
if($_ -match "def=(\d*)"){
$_ -replace "$($Matches[1])","$($MinX)"
}
}
$a
The result is correct:
abc=1
def=100
ghi=3
I don't understand how a simple integer comparison before doing the replace could screw things up so badly, can anyone advise what I'm missing?
The comparison operator -gt will never get you a value of $true because you need to
cast the $matches[1] string value to int first so it compares two integer numbers
2 is never greater than 100.. Change the operator to -lt instead.
Your code outputs only one line, because you forgot to also output unchanged lines that do not match the regex
$file = 'c:\test.txt'
$MinX = 100
$MinY = 100
$a = (Get-Content $file) | ForEach-Object {
if ($_ -match '^def=(\d+)'){
if([int]$matches[1] -lt $MinX){ $_ -replace $matches[1],$MinX }
}
else {
$_
}
}
$a
Or use switch (is also faster than using Get-Content):
$file = 'c:\test.txt'
$MinX = 100
$MinY = 100
$a = switch -Regex -File $file {
'^def=(\d+)' {
if([int]$matches[1] -lt $MinX){ $_ -replace $matches[1],$MinX }
}
default { $_ }
}
$a
Output:
abc=1
def=100
ghi=3
That's because the expression ($Matches[1] -gt $MinX) is a string comparison. In Powershell, the left-hand side of a comparison dictates the comparison type and since that is of type [string], Powershell has to cast/convert the right-hand side of the expression to [string] also. You expression, therefore, is evaluated as ([string]$Matches[1] -gt [string]$MinX).
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
}
I am trying to use powershell for extracting email addresses from a .csv file.
Each row in the .csv may have none or more emails separated by ",".
f.e.
Email
info#domain.com, email#domain.com, person#contonso.com
something#domain.com
My goal is to write it that way so I can get the "info#" from the row if it is present + 1 extra email from the row if it is present. If there is no "info#" get at least 1 or 2 emails from that row.
Here is the fracture of the code, where I am manually able to say on what position is what email, but I am not able to get this part to work in the for cycle which I could use to enumerate the number of occurences as it appears I cannot convert it to int at all.
$Occurrences = $email.Split(",").GetUpperBound(0);
[int]$Occurrences
$data = Import-Csv -path $path
foreach($contact in $data)
{
$email = $contact.Email
if($email.Contains("info"))
{
$emailSplit = $contact.Email.Split(",")
$Occurrences = $email.Split(",").GetUpperBound(0);
[int]$Occurrences
$name = $domainSplit[0]
for([int]$i = 0;-lt $Occurrences.ToInt32(); $i++)
{
}
}
}
Any help is appreciated.
This is not a valid CSV Format. Cant you export the data via JSON from the datasource?
You need to split the single lines and then do your operations
$data = Get-Content -path $path
for($i=1; $i -lt $data.Length; $i++)
{
$emailSplit = [array]$data[$i].Split(",")
for($j = 0; $j -lt $emailSplit.Length; $j++) {
<#do your operation here...
loop once through the elements, check for info#, and then assign them accoringly...
#>
}
}
V2:
$data = Get-Content -path $path
for($i=1; $i -lt $data.Length; $i++)
{
$emailSplit = [array]$data[$i].Split(",")
Write-Host ('Results for line: ' + $i)
$infoFound = $false
for($j = 0; $j -lt $emailSplit.Length; $j++) {
if($emailSplit[$j] -match 'Info#*') {
$infoFound = $true
$infoPos = $j
}
}
[array]$results = $emailSplit[0]
$results += $emailSplit[-1]
if($infoFound) {
if($infoPos = 0) {$results[1] = $emailSplit[$infoPos]}
else {$results[0] = $emailSplit[$infoPos]}
}
Write-Host ('Element1: ' + $results[0] + ' Element2: ' + $results[1])
}
I'am trying to collect my array into a multidimensional array by using the -like comparison operator for further processing.
I wrote the following array loop but i cannot replace "*kw1*" with "*$keyword[$j]*". It will break the operator validation.
$keywords = #("kw1", "kw2")
$list = #("name_kw1_000", "name_kw1_001", "name_kw1_002", "name_kw2_000", "name_kw2_001", "name_kw2_002")
$mdarr= New-Object object[][] $keywords.Length
for ($i = 0; $i -lt $list.Length; ++$i) {
for ($j = 0; $j -lt $keywords.Length; ++$j) {
if ( $list[$i] -like "*kw1*" ) {
$mdarr[$j] += $list[$i];
}
}
}
My expected output is:
$mdarr[0]
name_kw1_000
name_kw1_001
name_kw1_002
$mdarr[1]
name_kw2_000
name_kw2_001
name_kw2_002
Is this possible with the above array loop or would i have to do this completely different since the -like operator does not seem to be array friendly.
I think you mean to get output for a variable length array, using more keywords.
As montonero comments, you never test if the keyword is actually part of the item in the list of words.
Maybe this will help:
# there is no need to enclose the items with '#()'
$keywords = "kw1", "kw2"
$list = "name_kw1_000", "name_kw1_001", "name_kw1_002", "name_kw2_000", "name_kw2_001", "name_kw2_002"
# in case your keywords contain characters that have special meaning
# for regex '-match', we should escape these characters.
$keywords = $keywords | ForEach-Object { [RegEx]::Escape($_) }
# fill the object array
$mdarr= New-Object object[][] $keywords.Count
for ($i = 0; $i -lt $keywords.Count; $i++) {
foreach ($item in $list) {
if ($item -match $keywords[$i]) {
$mdarr[$i] += $item
}
}
}
# write result
for ($i = 0; $i -lt $mdarr.Count; $i++) {
Write-Host ("`$mdarr[$i]") -ForegroundColor Yellow
$mdarr[$i]
}
This will output
$mdarr[0]
name_kw1_000
name_kw1_001
name_kw1_002
$mdarr[1]
name_kw2_000
name_kw2_001
name_kw2_002
In my current powershell script I have hash table with values. Am using
this syntax
$x = $f.contains("$k")
but I figured recently that am having problems with this approach I was wondering if powershell has something that says "starts with," or related, that would search thru the hash table with "starts with" instead of contains
Example of the hash table:
"bio.txt" = "server1\datafiles\bio";
etc.......
EDIT Sample from comments
foreach ($key in $filehash.keys) {
$path = $filehash.get_Item($key)
$filecount = 0
foreach ($file in $FileArray) {
if ($file.LastWriteTime -lt($(GetDate).adddays(-1))) {
[string] $k = $key.ToLower()
[string] $f = $file.name.ToLower()
if ($x = $f.contains("$k")) { }
}
}
}
Try using -like to check if a string starts with yourvalue. I rewrote your sample in the comments to use it:
$filehash.GetEnumerator() | foreach {
#$_ is now current object from hashtable(like foreach)
#$_.key is key and $_.value is path
$filecount = 0
foreach ($file in $FileArray) {
if ( ($file.LastWriteTime -lt $((Get-Date).AddDays(-1))) -and ($file.name -like "$($_.Key)*") ) {
#process file
}
}
}