I want to append several strings in a data set with custom strings.
Example
Content of Dataset:
Test1
Test2
Test3
Result after appending:
Test1.com
Test2.com
Test3.com
Would I have to use regex to parse to the end of each Test[n] to be able to append it with a custom string (.com)? Has anyone got an example that describes exactly how to do it?
I am reading from a SQL-Table and writing values into a DataSet which is exported to CSV the following way:
$DataSet.Tables[0] | ConvertTO-Csv -Delimiter ',' -NotypeInformation |`% { $_ -replace '"','' } | out-file $outfile -Encoding "unicode"
The DataSet contains of Strings such as:
Banana01
Banana02
Apple01
Cherry01
Cherry02
Cherry03
The thing I want to do is append .com to only Cherry01, Cherry02, and Cherry03, and after appending .com, export it as a CSV file.
There are many ways. Here are a few:
# Using string concatenation
'Test1','Test2','Test3' | Foreach-Object{ $_ + '.com' }
# Using string expansion
'Test1','Test2','Test3' | Foreach-Object{ "$_.com" }
# Using string format
'Test1','Test2','Test3' | Foreach-Object{ "{0}{1}" -f $_,'.com' }
You could use something like this:
Example 1
$t = "test"
$t = $t + ".com"
Example 2
$test = #("test1","test2")
$test | ForEach-Object {
$t = $_ + ".com"
Write-Host $t}
With your added code I did this. I don't have a database to test it on, so I made the data set manually, so you might just have to change the $DataSet[0] in my code to $DataSet.Tables[0].
$DataSet[0] | ConvertTO-Csv -Delimiter ',' -NotypeInformation | Foreach-Object{$T=$_
IF($T -match "(Cherry\d\d)"){$T = $T -replace "(Cherry\d\d)(.+)",'$1.com$2'};$T } | out-file $outfile -Encoding "unicode"
$array | %{if($_ -match "^Cherry\d\d"){$_ += ".com"};$_}
Related
1 .. $Count | ForEach-Object {
$i = $_.ToString($Length)
$Offset = $BatchSize * ($_ - 1)
$outputFile = $ParentDirectory + "\" + $strBaseName + "-" + $i + $strExtension
If($_ -eq 1) {
$objFile | Select-Object -First $BatchSize | Export-Csv $outputFile -NoTypeInformation -Encoding UTF8
} Else {
$objFile | Select-Object -First $BatchSize -Skip $Offset | Export-Csv $outputFile -NoTypeInformation -Encoding UTF8
}
}
I have a .txt with a comma on row 3 below. My code is stripping anything after the comma as seen below. how do I fix it? My file is pipe delimited.
Original file contains
|Header1|Header2|Header3|Header4|
|320|A1| |0900|
|320|A2|This, comma is needed|0900|
|320|A3| |0700|
|320|A4|f2|0900|
|320|A5| |0700|
|320|L2|c6|0900|
After splitting into 2 files -notice the missing text after "this,"
file1
|Header1|Header2|Header3|Header4|
|320|A1| |0900|
|320|A2|This,
|320|A3| |0700|
file2
|Header1|Header2|Header3|Header4|
|320|A4|f2|0900|
|320|A5| |0700|
|320|L2|c6|0900|
Please advise. Thanks
I tried to use delimiter and replace commands. Didn't work
It looks like when you imported your delimited file into $objFile, you forgot to pass -Delimiter '|' to the Import-Csv call, which would not interpret your |-separated file properly, given that Import-Csv - as well as Export-Csv - default to , as the separator.
Thus, the solution is to use -Delimiter '|' in both your Import-Csv and Export-Csv calls.
As for what you tried:
Here's a minimal example that demonstrates the problem with omitting -Delimiter '|', using the in-memory CSV processing cmdlets, ConvertFrom-Csv and ConvertTo-Csv:
#'
Field1|Field2
Value1|Value2, and more
'# |
ConvertFrom-Csv |
ConvertTo-Csv
Output (note the missing , and more part, and how the output lines as a whole are double-quoted):
"Field1|Field2"
"Value1|Value2"
Since header row Field1|Field2 contains no , it became a single property in the resulting objects, literally named Field1|Field2.
Since the data row happened to contain , it was parsed as two fields, and since there is only one column, the extra field was simply discarded.
I have the following script and it gets me the info I need.
$Monitors = Get-WmiObject WmiMonitorID -Namespace root\wmi
$LogFile = "d:\monitors.csv"
"Manufacturer,Name,Serial" | Out-File $LogFile
ForEach ($Monitor in $Monitors)
{
$Manufacturer = ($Monitor.ManufacturerName|where {$_ -ne 0}|ForEach{[char]$_}) -join ""
$Name = ($Monitor.UserFriendlyName |where {$_ -ne 0}| ForEach{[char]$_}) -join ""
$Serial = ($Monitor.SerialNumberID |where {$_ -ne 0}| ForEach{[char]$_}) -join ""
"$Manufacturer,$Name,$Serial" | Out-File $LogFile -append
}
My problem is the data is exported to the excel spreadsheet like this..
Manufacturer,Name,Serial.
ACI,VE248,K8LMQS048382
HWP,HP P232,6CM8122DXL
HWP,HP P232,6CM7241DRB
I need it to be:
Manufacturer Name Serial
in the spreadsheet, and when I do the next pc, it adds to the next line and so on.
I have looked online and the examples just don't match.
Does anyone have any advice?
As others already commented, use Export-Csv to write out the wanted data in csv format, rather than constructing it manually.
That means your ForEach-Object loop should emit objects instead of lines of concatenated strings.
Also, nowadays, I would use the newer Get-CimInstance instead of Get-WmiObject (What's the difference)
Try
$LogFile = "d:\monitors.csv"
Get-CimInstance -ClassName WmiMonitorID -Namespace root\wmi | ForEach-Object {
[PsCustomObject]#{
Manufacturer = [string]::new($_.ManufacturerName, 0, $_.ManufacturerName.Length).Trim("`0")
Name = [string]::new($_.UserFriendlyName, 0, $_.UserFriendlyName.Length).Trim("`0")
Serial = [string]::new($_.SerialNumberID, 0, $_.SerialNumberID.Length).Trim("`0")
}
} | Export-Csv -Path $LogFile -NoTypeInformation -UseCulture
The -UseCulture switch makes sure the output csv file uses the same delimiter characters your locally installed Excel would expect, so you can simply double-click the file to open it in Excel
Actually I have this loop :
foreach($line in Get-Content .\script2.csv)
{ $firstname = $line.split(';')[0]
$lastname = $line.split(';')[1]
$email = $line.split(';')[2]
$newLine = "$firstname,""$lastname"",""$email"""
$newLine >> newCSV.csv }
I use it to extract data and paste it in a correct format.
I would like to know what is the correct syntax to start it from the row 2 and not taking all my sheet ?
Thanks !
Use Select -Skip $N to skip the first $N items of a collection:
foreach($line in Get-Content .\script2.csv |Select -Skip 1)
{
$firstname = $line.split(';')[0]
$lastname = $line.split(';')[1]
$email = $line.split(';')[2]
$newLine = "$firstname,""$lastname"",""$email"""
$newLine >> newCSV.csv
}
If what you want to do is to convert a CSV file that uses the semi-colon ; as delimiter to a new Csv file that uses the comma , as delimiter, and in the process remove the header line from it, you can do:
Import-Csv -Path 'D:\Test\blah.csv' -Delimiter ';' | ConvertTo-Csv -NoTypeInformation |
Out-String -Stream | Select-Object -Skip 1 | Set-Content -Path 'D:\Test\newCSV.csv'
I'm looking for a translation of my Excel formula in a form of a script in Powershell, vbscript or Excel VBA. I'm trying to get the list of column headers and the max length of string under it.
Normally, what I do is manually open the .txt file in Excel, from there I can get the header names.. next, I create an array formula =MAX(LEN(A1:A100,000)) for example. This will get the max length of string in the column. I'll do the same formula to other columns.
Right now I can't do this since files have increased to 1GB in size and i can't open them anymore, my desktop crashes. It is also maybe because theyre more than 1 million rows which Excel cant handle. My friend suggested Powershell but I have limited knowledge there.. don't know if it can be done in vbscript or Excel VBA.
Thanks in advance for your help.
Below code works for .csv files but does not with .txt delimited files -
$fileName = "C:\Desktop\EFile.csv"
<#
Sample format of c:\temp\data.csv
"id","name","grade","address"
"1","John","Grade-9","test1"
"2","Ben","Grade-9","test12222"
"3","Cathy","Grade-9","test134343"
#>
$colCount = (Import-Csv $fileName | Get-Member | Where-Object {$_.MemberType -eq 'NoteProperty'} | Measure-Object).Count
$csv = Import-Csv $fileName
$csvHeaders = ($csv | Get-Member -MemberType NoteProperty).name
$dict = #{}
foreach($header in $csvHeaders) {
$dict.Add($header,0)
}
foreach($row in $csv)
{
foreach($header in $csvHeaders)
{
if($dict[$header] -le ($row.$header).Length)
{
$dict[$header] =($row.$header).Length
}
}
}
$dict.Keys | % { "key = $_ , Column Length = " + $dict.Item($_) }
This is how I get my data.
$data = #"
"id","name","grade","address"
"1","John","Grade-9","test1"
"2","Ben","Grade-9","test12222"
"3","Cathy","Grade-9","test134343"
"#
$csv = ConvertFrom-Csv -Delimiter ',' $data
But you should get your data like this
$fileName = "C:\Desktop\EFile.csv"
$csv = Import-Csv -Path $fileName
And then
# Extract the header names
$headers = $csv | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name
# Capture output in $result variable
$result = foreach($header in $headers) {
# Select all items in $header column, find the longest, and select the item for output
$maximum = $csv | Select-Object -ExpandProperty $header | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum
# Generate new object holding the information.
# This will end up in $results
[pscustomobject]#{
Header = $header
Max = $maximum.Length
String = $maximum
}
}
# Simple output
$result | Format-Table
This is what I get:
Header Max String
------ --- ------
address 10 test134343
grade 7 Grade-9
id 1 3
name 4 John
Alternatively, if you have memory issues dealing with large files, you may have to get a bit more dirty with the .NET framework. This snippet processes one csv line at a time, instead of reading the entire file into memory.
$fileName = "$env:TEMP\test.csv"
$delimiter = ','
# Open a StreamReader
$reader = [System.IO.File]::OpenText($fileName)
# Read the headers and turn it into an array, and trim away any quotes
$headers = $reader.ReadLine() -split $delimiter | % { $_.Trim('"''') }
# Prepare a hashtable for the results
$result = #{}
# So long as there's more data, keep running
while(-not $reader.EndOfStream) {
# Read a single line and process it as csv
$csv = $reader.ReadLine() | ConvertFrom-Csv -Header $headers -Delimiter $delimiter
# Determine if the item in the result hashtable is smaller than the current, using the header as a key
foreach($header in $headers) {
$item = $csv | Select-Object -ExpandProperty $header
if($result[$header].Maximum -lt $item.Length) {
$result[$header] = [pscustomobject]#{
Header = $header
Maximum = $item.Length
String = $item
}
}
}
}
# Clean up our spent resource
$reader.Close()
# Simple output
$result.Values | Format-Table
I'm attempting to create a PowerShell script to pick particular lines from large log files. Using Select-String, I've gotten the data down to just the rows I need in a multiline string. Now I'd like to further massage it to return only the ID numbers from those rows, in a single, comma-delimited string.
Current code:
if (Select-String $SearchFile -Pattern $SearchString -Quiet) {
Write-Host "Error message found"
$body += Select-String $SearchFile -Pattern $SearchString -Context 1,0 |
foreach {$_.Context.DisplayPreContext} | Out-String
Send-MailMessage (email_info_here) -Body $body
} else {
Write-Host "No errors found"
}
Currently returning the following string:
INFO | Creating Batch for 197988 | 03/24/2016 02:10 AM
INFO | Creating Batch for 202414 | 03/24/2016 02:10 AM
INFO | Creating Batch for 173447 | 03/24/2016 02:10 AM
Would like to get the output to the format:
197988, 202414, 173447
If Body contains those lines, then you just need to split and index into the column that has our data.
$body | ForEach-Object {$psitem.Split()[5]}
197988
202414
173447
In this sample, we call ForEach-Object to make a little code block to execute on each line. Then, we call the line's $split() method to split on spaces. Then we just index into the fifth column, using $psitem[5].
Assuming you want to save the lines back into $body again, just add $body = to the front of line 1.
Edit: Multi-line-string vs. Array
In the original post, the $body variable was created with Out-String as the last command in the pipeline. This would make it a single multi-line string. Leaving out the | Out-String part would make $body an array of strings. The latter (an array) is easier to work with and is what the answer above assumes, since it is easy to loop through each line in the array with foreach.
Converting between the two is done like this:
$string = #"
INFO | Creating Batch for 197988 | 03/24/2016 02:10 AM
INFO | Creating Batch for 202414 | 03/24/2016 02:10 AM
INFO | Creating Batch for 173447 | 03/24/2016 02:10 AM
"#
$array = #(
"INFO | Creating Batch for 197988 | 03/24/2016 02:10 AM"
"INFO | Creating Batch for 202414 | 03/24/2016 02:10 AM"
"INFO | Creating Batch for 173447 | 03/24/2016 02:10 AM"
)
$array_from_string = $string -split("`n")
$string_from_array = $array | Out-String
In order for the answer to work you need to make sure that $body is an array, else you will only get one ID number:
$string | Foreach-Object {$psitem.Split()[5]}
197988
Replace Out-String with a Where-Object filter that matches the number part of each result line, extract the number submatch, and join the result:
$body += (Select-String $SearchFile -Pattern $SearchString -Context 1,0 |
ForEach-Object { $_.Context.DisplayPreContext } |
Where-Object { $_ -match 'for (\d+) \|' } |
ForEach-Object { $matches[1] }) -join ', '
This might be a dirty way to do it, but it works:
#This can also be your variable
$log = gc "C:\[log path here]"
#Remove beginning of string up to ID
$log = $log -replace '(.*?)for ' , ""
#Select first 6 characters since all IDs shown are 6 characters
$logIDs = #()
foreach($line in $log){
$logIDs += $line.substring(0,6)
}
### At this point $logIDs contains all IDs, now we just need to comma separate them ###
$count = 1
foreach($ID in $logIDs){
if($count -eq $logIDs.count){
$result += $ID
}
else{
$result += $ID+", "
$count++
}
}
#Here are your results separated by commas
$result
Hope this helps, let me know if you need any type of variation.