How to set as variable csv column using powershell? - powershell

I have csv file like this
ID Name
4 James
6 John
1 Cathy
I want to save those file as .cmd with this format
SET NUMBER1=4
SET NUMBER2=6
SET NUMBER3=1
The total of ID in the csv file is not always 3. If the ID more than 3, it means my cmd file be like this
SET NUMBER1=4
SET NUMBER2=6
SET NUMBER3=1
SET NUMBERN=N
Anyone can help please. I really new in powershell, really need help and advice please. Thanks
$ID = Import-Csv .\Data.csv | Select-Object -ExpandProperty ID
$ID.Count
ForEach ( $id in $ID ) {
}
I am stuck here

An alternative approach is below if your headers are always present in the file. It doesn't matter what the delimiter is as long as it isn't a number. Your delimited data in the sample is not consistent. Otherwise, Import-Csv would be a safer option.
$fileData = Get-Content file.csv
$output = for ($i = 1; $i -lt $fileData.count; $i++) {
"SET NUMBER{0}={1}" -f $i,($fileData[$i] -replace "(?<=^\d+).*")
}
$output | Out-File file.cmd
Explanation:
The format operator (-f) is used to help construct the output strings. The ID numbers are selected using regex by replacing everything that comes after the beginning digits on each line.

Try this:
# set current directory to script directory
Set-Location $PSScriptRoot
# import csv-file, delimiter = space
$content = Import-Csv 'test.csv' -Delimiter ' '
$output = ''
# create output lines
for( $i = 1; $i -le $content.Count; $i++ ) {
$output += 'SET NUMBER' + $i.ToString() + '=' + $content[$i-1].ID.ToString() + [environment]::NewLine
}
# output to file
$output | Out-File 'result.bat' -Force

Related

How to add text to existing text in a csv file using PowerShell

I have a csv file that contains one column of cells (column A), each row/cell contains a single file name. The csv file has no header.
Something like this -
6_2021-05-10_02-00-36.mp4
6_2021-05-10_05-04-01.mp4
6_2021-05-10_05-28-59.mp4
6_2021-05-10_05-35-05.mp4
6_2021-05-10_05-35-34.mp4
6_2021-05-10_05-39-36.mp4
6_2021-05-10_05-39-41.mp4
6_2021-05-10_05-39-52.mp4
The number of rows in this csv file is variable.
I need to add a URL to the beginning of the text in each cell, such that, a valid URL is created - and the resulting csv content looks exactly like this:
https:\\www.url.com\6_2021-05-10_02-00-36.mp4
https:\\www.url.com\6_2021-05-10_05-04-01.mp4
https:\\www.url.com\6_2021-05-10_05-28-59.mp4
https:\\www.url.com\6_2021-05-10_05-35-05.mp4
https:\\www.url.com\6_2021-05-10_05-35-34.mp4
https:\\www.url.com\6_2021-05-10_05-39-36.mp4
https:\\www.url.com\6_2021-05-10_05-39-41.mp4
https:\\www.url.com\6_2021-05-10_05-39-52.mp4
So, this is what I've come up with, but it does not work.....
Param($File)
$csvObjects = C:\_TEMP\file_list_names.csv $file
$NewCSVObject = "https:\\www.url.com\"
foreach ($item in $csvObjects)
{
$item = ($NewCSVObject += $item)
}
$csvObjects | export-csv "C:\_TEMP\file_list_names_output.csv" -noType
But it's not working, and my PowerShell skills are not so sharp.
I'd be so very grateful for some assistance on this.
Thanks in advance-
Gregg
Sierra Vista, AZ
just concat with what you want:
$file2 ="C:\fic2.csv"
$x = Get-Content $file2
for($i=0; $i -lt $x.Count; $i++){
$x[$i] = "https:\\www.url.com\" + $x[$i]
}
$x
Technically speaking your inputfile can serve as csv, but because it contains only one column of data and has no headers, you can treat it best with Get-Content instead of using Import-Csv
Here's two alternatives for you to try.
$result = foreach ($fileName in (Get-Content -Path 'C:\_TEMP\file_list_names.csv')) {
'https:\\www.url.com\{0}' -f $fileName
}
# next save the file
$result | Set-Content -Path 'C:\_TEMP\file_urls.csv'
OR something like:
Get-Content -Path 'C:\_TEMP\file_list_names.csv' | ForEach-Object {
"https:\\www.url.com\$_"
} | Set-Content -Path 'C:\_TEMP\file_urls.csv'
Urls usually use forward slashes / not backslashes \.. I left these in, so you can replace them yourself if needed
With the help of Frenchy.... the complete answer is.... (URL changed for security reasons obviously)
#opens list of file names
$file2 ="C:\_TEMP\file_list_names.csv"
$x = Get-Content $file2
#appends URl to beginning of file name list
for($i=0; $i -lt $x.Count; $i++){
$x[$i] = "https://bizops-my.sharepoint.com/:f:/g/personal/gpowell_bizops_onmicrosoft_com/Ei4lFpZHTe=Jkq1fZ\" + $x[$i]
}
$x
#remove all files in target directory prior to saving new list
get-childitem -path C:\_TEMP\file_list_names_url.csv | remove-item
Add-Content -Path C:\_TEMP\file_list_names_url.csv -Value $x

Requirement is to add 4 line if the matching pattern followed by the next pattern is unmatched along with count number in power shell

Hello my input file will be like below,my requiremnet is to add 4 line if the macthing pattern folled by the next pattern is unmacthed along with count number.
i will check look for the socket and if matches will incrremnt the line count to +1 toi get the next line and look for the word "address",if the address is not present i need to insert a set of line "communication.manageraddress_9,communication.manageraddress_10,communication.manageraddress_11" netx to the line.
communication.manageraddress_7=xxx.com
communication.managerid_7=xxx
communication.managerport_7=xxx
communication.socket_7=xx
communication.manageraddress_8=xxx.com
communication.managerid_8=xxx
communication.managerport_8=xxx
communication.socket_8=plain
Added by Manager
communication.managerhealthmon_4=true
communication.protocolrev_4=3
communication.managerhealthmon_1=true
communication.protocolrev_1=2
output will be like this
communication.manageraddress_7=xxx.com
communication.managerid_7=xxx
communication.managerport_7=xxx
communication.socket_7=xx
communication.manageraddress_8=xxx.com
communication.managerid_8=xxx
communication.managerport_8=xxx
communication.socket_8=plain
communication.manageraddress_9=xxx.com
communication.managerid_9=xxx
communication.managerport_9=xxx
communication.socket_9=plain
communication.manageraddress_10=xxx.com
communication.managerid_10=xxx
communication.managerport_1o=xxx
communication.socket_1o=plain
Added by Manager
communication.managerhealthmon_4=true
communication.protocolrev_4=3
communication.managerhealthmon_1=true
communication.protocolrev_1=2
this my script and i am struck with insert into text file along with increment number,can some one help in power shell.
$files = $File = 'C:\Users\rseerala\Desktop\ARUN\in.txt'
#$NewContent = Get-Content -Path $File
foreach($file in $files){
$content = Get-Content $file
for($i = 0; $i -lt $content.Count; $i++){
$line = $content[$i]
if ($line.Contains("socket"))
{
$line = $content[$i+2]
if ($line.Contains("address"))
{
Write-Host "This line starts with 6"
}}}}
Ok, so if I understand correctly, this is what you want:
#read the file as a single multiline string
$txt = Get-Content -Path 'C:\Users\rseerala\Desktop\ARUN\in.txt' -Raw
# if it contains the magic word '.socket_' followed by a number
if ($txt -match '\.socket_\d+') {
# first split off the 'Added by Manager' stuff
$content, $managerAdded = ($txt -split 'Added by Manager').Trim()
# split the content part into separate blocks of 4 lines
$blocks = $content -split '(\r?\n){2}' | Where-Object { $_ -match '\S' }
# get the index value from the last block
$index = [int]([regex] '(?i)\.socket_(\d+)').Match($blocks[-1]).Groups[1].Value
# now repeat the blocks you already have and output copies with incremented indices
$newBlocks = ($blocks | ForEach-Object {
$_ -replace '_\d+=', ('_{0}=' -f ++$index)
}) -join "`r`n`r`n"
# finally, combine the content part with the new blocks
# and the 'Added by Manager' lines with double newlines
$result = $content, $newBlocks, 'Added by Manager', $managerAdded -join "`r`n`r`n"
# output on screen
$result
# write to a new file
$result | Set-Content -Path 'C:\Users\rseerala\Desktop\ARUN\out.txt'
}
else {
Write-Warning "The file does not contain the word '.socket_' followed by a number.."
}
Output:
communication.manageraddress_7=xxx.com
communication.managerid_7=xxx
communication.managerport_7=xxx
communication.socket_7=xx
communication.manageraddress_8=xxx.com
communication.managerid_8=xxx
communication.managerport_8=xxx
communication.socket_8=plain
communication.manageraddress_9=xxx.com
communication.managerid_9=xxx
communication.managerport_9=xxx
communication.socket_9=plain
communication.manageraddress_10=xxx.com
communication.managerid_10=xxx
communication.managerport_10=xxx
communication.socket_10=plain
Added by Manager
communication.managerhealthmon_4=true
communication.protocolrev_4=3
communication.managerhealthmon_1=true
communication.protocolrev_1=2

Changing multiple lines in a text file based on a psobject

I'm working on a script which will add some additional informations to a txt file. These informations are stored in a CSV file which looks like this (the data will differs each time the script will launch):
Number;A;B;ValueOfB
FP01340/05/20;0;1;GTU_01,GTU_03
FP01342/05/20;1;0;GTU01
The txt file looks like this (data inside will of course differ each time):
1|1|FP01340/05/20|2020-05-02|2020-05-02|2020-05-02|166,91|203,23|36,32|nothing interesting 18|33333|63-111 somewhere|||||
2|zwol|9,00|9,00|0,00
2|23|157,91|194,23|36,32
1|1|FP01341/05/20|2020-05-02|2020-05-02|2020-05-02|12,19|14,99|2,80|Some info |2222222|blabla|11-111 something||||
2|23|12,19|14,99|2,80
1|1|FP01342/05/20|2020-05-02|2020-05-02|2020-05-02|525,36|589,64|64,28|bla|222222|blba 36||62030|something||
2|5|213,93|224,63|10,70
2|8|120,34|129,97|9,63
2|23|191,09|235,04|43,95
What I need to do is to find a line which contains 'Number' and then add value 'A' and 'B' from a CSV in a form: |0|1 and then on the first line below, at the end, add 'ValueofB' in a form |AAA_01,AAA_03
So the first two lines should look like this at the end:
1|1|FP01340/05/20|2020-05-02|2020-05-02|2020-05-02|166,91|203,23|36,32|nothing interesting 18|33333|63-111 somewhere||||||0|1
2|zwol|9,00|9,00|0,00|AAA_01,AAA_03
2|23|157,91|194,23|36,32
Rest of lines should not be touched.
I made a script which uses select-string method with context to find what I need to - put that into an object and then add to previously found strings what I need to and put that in to an another object.
My script is as follws:
$csvFile = Import-Csv -Path Somepath\file.csv -Delimiter ";"
$file = "Somepath2\SomeName.txt"
$LinesToChange = #()
$script:LinesToChange = $LinesToChange
$LinesOriginal = #()
$script:LinesOriginal = $LinesOriginal
foreach ($line in $csvFile) {
Select-String -Path $file -Pattern "$($Line.number)" -Encoding default -Context 0, 1 | ForEach-Object {
$1 = $_.Line
$2 = $_.Context.PostContext
}
$ListOrg = [pscustomobject]#{
Line_org = $1
Line_GTU_org = $2
}
$LinesOriginal = $LinesOriginal + $ListOrg
$lineNew = $ListOrg.Line_org | foreach { $_ + "|$($line.A)|$($line.B)" }
$GTUNew = $ListOrg.Line_GTU_org | foreach { $_ + "|$($line.ValueofB)" }
$ListNew = [pscustomobject]#{
Line_new = $lineNew
Line_GTU_new = $GTUNew
Line_org = $ListOrg.Line_org
Line_GTU_org = $ListOrg.Line_GTU_org
}
$LinesToChange = $LinesToChange + $ListNew
}
The output is an object $LinesToChange which have original lines and lines after the change. The issue is I have no idea how to use that to change the txt file. I tried few methods and ended up with file which contains updated lines but all others are doubbled (I tried foreach) or PS is using whole RAM and couldn't finish the job :)
My latest idea is to use something like that:
(Get-Content -Path $file) | ForEach-Object {
$line = $_
$LinesToChange.GetEnumerator() | ForEach-Object {
if ($line -match "$($LinesToChange.Line_org)") {
$line = $line -replace "$($LinesToChange.Line_org)", "$($LinesToChange.Line_new)"
}
if ($line -match "$($LinesToChange.Line_GTU_org)") {
$line = $line -replace "$($LinesToChange.Line_GTU_org)", "$($LinesToChange.Line_GTU_new)"
}
}
} | Set-Content -Path Somehere\newfile.txt
It seemed promising at first, but the variable $line contains all lines and as such it can't find the match.
Also I need to be sure that the second line will be directly below the first one (it is unlikely but it can be a case that there will be two or more lines with the same data while the "number" from CSV file is unique) so preferably while changing the txt file it would be needed to find a match for a two-liner; in short:
find this two lines:
1|1|FP01340/05/20|2020-05-02|2020-05-02|2020-05-02|166,91|203,23|36,32|nothing interesting 18|33333|63-111 somewhere|||||
2|zwol|9,00|9,00|0,00
change them to:
1|1|FP01340/05/20|2020-05-02|2020-05-02|2020-05-02|166,91|203,23|36,32|nothing interesting 18|33333|63-111 somewhere||||||0|1
2|zwol|9,00|9,00|0,00|AAA_01,AAA_03
Do that for all lines in a $LinesToChange
Any help will be much appreciated!
Greetings!
Some strange text file you have there, but anyway, this should do it:
# read in the text file as string array
$txt = Get-Content -Path '<PathToTheTextFile>'
$csv = Import-Csv -Path '<PathToTheCSVFile>' -Delimiter ';'
# loop through the items (rows) in the CSV and find matching lines in the text array
foreach ($item in $csv) {
$match = $txt | Select-String -Pattern ('|{0}|' -f $item.Number) -SimpleMatch
if ($match) {
# update the matching text line (array indices count from 0, so we do -1)
$txt[$match.LineNumber -1] += ('|{0}|{1}' -f $item.A, $item.B)
# update the line following
$txt[$match.LineNumber] += ('|{0}' -f $item.ValueOfB)
}
}
# show updated text on screen
$txt
# save updated text to file
$txt | Set-Content -Path 'Somehere\newfile.txt'

Having trouble using the export-csv

I have 3 csv files and they are all only 1 column long. I have tried lots of thing to put it all in one csv file but i cant get it to work. When i output it, it all ends up in one column here is what i did so far
#Putting Csv files to Array
$CSV1 = #(gc $EmailPathCsv)
$CSV2 = #(gc $UserLPathCsv)
$CSV3 = #(gc $EmailPathCsv)
#
for ($i=0; $i -lt $CSV1.Count; $i++)
{
$CSV4 += $CSV1[$i] + "," + $CSV2[$i] + "," + $CSV3[$i] + " "
}
$csv4 | out-file -append $MergedCsvExport
Your loop is adding everything into $CSV4, each time through the loop $CSV4 gets longer and longer.
Then you print it once. That's why you get one really long line. Try printing it once every time through the loop, and overwriting $CSV4 every time:
#Putting Csv files to Array
$CSV1 = #(gc $EmailPathCsv)
$CSV2 = #(gc $UserLPathCsv)
$CSV3 = #(gc $EmailPathCsv)
#
for ($i=0; $i -lt $CSV1.Count; $i++)
{
$CSV4 = $CSV1[$i] + "," + $CSV2[$i] + "," + $CSV3[$i] + " "
out-file -InputObject $csv4 -Append -FilePath $MergedCsvExport
}
I'd use a foromat string for that.
$CSV1 = #(gc $EmailPathCsv)
$CSV2 = #(gc $UserLPathCsv)
$CSV3 = #(gc $EmailPathCsv)
for ($i=0; $i -lt $CSV1.Count; $i++)
{
'"{0}","{1}","{2}"' -f $CSV1[$i],$CSV2[$i],$CSV3[$i] |
add-content $MergedCsvExport
}
As a more fun answer:
$CSV1 = 1,2,3,4
$CSV2 = 10,11,12,13
$CSV3 = 'a','b','c','d'
$c = gv -Name CSV* | select -expand name | sort
(gv -Va $c[0])|%{$r=0}{#($c|%{(gv -Va $_)[$r]}) -join ',';$r++}
Sample output:
1, 10, a
2, 11, b
3, 12, c
4, 13, d
You could put |Out-File "merged-data.csv" on the end to save to a file.
It works for more columns too, just add more arrays called $CSV{something}.
Edit: I wonder if Get-Variable's output is in a predictable order, or unspecified? If you don't mind if the column order might change, it collapses to:
$CSV1 = 1,2,3,4
$CSV2 = 10,11,12,13
$CSV3 = 'a','b','c','d'
(gv CSV*)[0].Value|%{$r=0}{#((gv CSV*)|%{(gv -Va $_.Name)[$r]}) -join ',';$r++}
Edit again: Well, in case anyone notices and is curious, and has time on their hands, I've expanded it all out with an explanation of what it's doing:
# Search the local variable scope for variables named CSV*
# This will find $CSV1, $CSV2, etc.
# This means the number of columns
# isn't fixed, you can easily add more.
# Take their names, sort them.
# Result: an array of strings "CSV1", "CSV2", ...
# for however many variables there are
$columnVariables = Get-Variable -Name "CSV*" | Select-Object -Expand Name | Sort-Object
# NB. if you remove $CSV3= from your code, it is
# still in memory from previous run. To remove
# it, use `Remove-Variable "CSV3"
# In pseudo-code, what the next part does is
# for row in range(data):
# #(CSV1[row], CSV2[row], ... CSVn[row]) -join ','
# The outer loop over the number of columns
# is done by piping something of the right length
# into a foreach loop, but ignoring the content.
# So get the first column array content:
$firstColumn = (Get-Variable $columnVariables[0]).Value
# and pipe it into a loop.
# The loop uses ForEach {setup} {loop} pattern
# to setup a row-counter before the loop body
$firstColumn | ForEach { $row=0 } {
# Now we know the row we are on, we can get
# $CSV1[row], $CSV2[row], ...
# Take the column variable array "CSV1", "CSV2", ..
# Loop over them
$rowContent = $columnVariables | ForEach {
# $_ a string of the name, e.g. "CSV1"
# Use Get-Variable to convert it
# into the variable $CSV1
# with -ValueOnly to get the array itself
# rather than details about the variable
$columnVar = Get-Variable -ValueOnly $_
# $columVar is now one of the $CSVn variables
# so it contains, e.g. 1,2,3,4
# Index into that for the current row
# to get one item, e.g. 3
# Output it into the pipeline
($columnVar)[$row]
} # This is the end of the inner loop
# The pipeline now contains the column
# values/content making up a single row
# 1
# 10
# 'a'
# Back in the outer row loop, Take the row
# content and make it a comma separated string
# e.g. "1,10,a"
# Output this into the pipeline
#($rowContent) -join ','
# Increment the row counter
$row++
}

Extracting columns from text file using PowerShell

I have to extract columns from a text file explained in this post:
Extracting columns from text file using Perl one-liner: similar to Unix cut
but I have to do this also in a Windows Server 2008 which does not have Perl installed. How could I do this using PowerShell? Any ideas or resources? I'm PowerShell noob...
Try this:
Get-Content test.txt | Foreach {($_ -split '\s+',4)[0..2]}
And if you want the data in those columns printed on the same line:
Get-Content test.txt | Foreach {"$(($_ -split '\s+',4)[0..2])"}
Note that this requires PowerShell 2.0 for the -split operator. Also, the ,4 tells the the split operator the maximum number of split strings you want but keep in mind the last string will always contain all extras concat'd.
For fixed width columns, here's one approach for column width equal to 7 ($w=7):
$res = Get-Content test.txt | Foreach {
$i=0;$w=7;$c=0; `
while($i+$w -lt $_.length -and $c++ -lt 2) {
$_.Substring($i,$w);$i=$i+$w-1}}
$res will contain each column for all rows. To set the max columns change $c++ -lt 2 from 2 to something else. There is probably a more elegant solution but don't have time right now to ponder it. :-)
Assuming it's white space delimited this code should do.
$fileName = "someFilePath.txt"
$columnToGet = 2
$columns = gc $fileName |
%{ $_.Split(" ",[StringSplitOptions]"RemoveEmptyEntries")[$columnToGet] }
To ordinary态
type foo.bar | % { $_.Split(" ") | select -first 3 }
Try this. This will help to skip initial rows if you want, extract/iterate through columns, edit the column data and rebuild the record:
$header3 = #("Field_1","Field_2","Field_3","Field_4","Field_5")
Import-Csv $fileName -Header $header3 -Delimiter "`t" | select -skip 3 | Foreach-Object {
$record = $indexName
foreach ($property in $_.PSObject.Properties){
#doSomething $property.Name, $property.Value
if($property.Name -like '*CUSIP*'){
$record = $record + "," + '"' + $property.Value + '"'
}
else{
$record = $record + "," + $property.Value
}
}
$array.add($record) | out-null
#write-host $record
}