I have a well-formed CSV file that I want to read, reformatting some values while doing so. For some reason the code below does not work ($csv variable ends up being empty):
$csv = Import-Csv "result.log" -Delimiter "|" | ForEach-Object {
$_.PSObject.Properties.Value | ForEach-Object {
if ($_ -like '*---*') { $_ = "" }
}
}
What am I doing wrong?
Your result is blank because you aren't returning anything to the pipeline (you are just changing the value of one or more properties but then not outputting them).
There might be a simpler solution but I think this achieves what you want:
$CSV = Import-Csv "result.log" -Delimiter "|" | Foreach-Object {
$Output = New-Object -TypeName PSObject
$_.PSObject.Properties | Foreach-Object {
If ($_.Value -like '*---*') { $_.Value = '' }
$Output | Add-Member -Name $_.Name -Value $_.Value -MemberType NoteProperty
}
$Output
}
This performs the following for each row of the CSV:
creates a new empty PowerShell object
loops through the properties of the CSV, blanking ones that include --- and then uses Add-Member to add those properties to our object
outputs the new object to the standard pipeline
The result of this goes to the $CSV variable which you then could output as CSV via Export-CSV (or you could skip putting it in the variable and use Export-CSV on the end of the outer ForEach-Object).
Related
I am using below code to add extra special character on all column except first column and empty cell value but code isn't working yet.
$path = 'F:\temp.csv'
Import-Csv $path | ForEach-Object {
if ($_.value -eq $path.value ) {
$_.value = ';'+$path.value
}
$_
} | Export-Csv $path -NoTypeInformation
Please see Image for more details:
Image
Please find csv file uploaded on Google Drive:
CSV FILE
I'm not sure what you were trying to do with $a, but if we remove that seems like you were close :)
Instead of checking if a value equals something we will just take every object and add a new property (i.e., a new column) to the object. We will call it 'B' and make the value the same as what's in 'A' but prefix a ';' to it using -replace. This replace operator uses regex so if we specify that we would like to replace '^', we are saying we would like to replace the start of the line/value. We replace this with ';' and save as our value. Then we output the object as you were already doing and then convert back to csv.
$path = 'F:\temp.csv'
Import-Csv $path | ForEach-Object {
$_ | Add-Member -NotePropertyName 'B' -NotePropertyValue ($_.A -replace '^', ';')
# or instead of -replace we can do similar to how you were trying
# $_ | Add-Member -NotePropertyName 'B' -NotePropertyValue (';' + $_.A)
$_
} | Export-Csv $path -NoTypeInformation
Update
Per your comment, this code should update values in all columns except the first where value is not null/empty
$path = 'F:\temp.csv'
$data = Import-Csv $path
# Track all the properties (columns) minus the first
$props = $data[0].psobject.Properties.Name | Select-Object -Skip 1
$data | ForEach-Object {
foreach ($prop in $props) {
if ( -not ([string]::IsNullOrWhiteSpace($_.$prop)) ){
$_.$prop = ';' + $_.$prop
}
}
$_
} | Export-Csv $path -NoTypeInformation
I have a script that should look in a CSV file and modify it.
My file looks like this:
"mydata","module1","module2","module3","module4","module5"
"kk-ll","module1","","module3","",""
"kk-pp","module1","","module3","",""
In case the data in column mydata exists: modify value in column $Module.
In case it does not exist: add a new line to the file.
The code I wrote for the fist part is OK, for the second part (updating the file) it's not working.
$ExistingCSV = Import-Csv MyCsv.csv
if ($ExistingCSV.mydata -eq "$LOT-$WID") {
$ExistingCSV | ForEach-Object {
if ($_.mydata -eq "$LOT-$WID") {
$_.$Module = $Module
}
}
$ExistingCSV | Export-Csv $ProgressLogPath\$LOT.csv -NoTypeInformation
} else {
$ExistingCSV.mydata = "$LOT-$WID"
$ExistingCSV.$Module = $Module
Add-Content $ExistingCSV -Value $_.Lot_WaferID $_.$Module $_.ScriptLogPath
$ExistingCSV | Export-Csv $ProgressLogPath\$LOT.csv -NoTypeInformation
}
I would use -contains instead of -eq, but since PowerShell operators work as enumerators the latter should work too in your case.
If a match is found, modify the existing data and export the result back to the CSV. Otherwise all you need to do is create a custom object with the data you want to add, and append that to the CSV.
$csv = 'C:\path\to\your.csv'
$ExistingCSV = Import-Csv $csv
if ($ExistingCSV.mydata -contains "$LOT-$WID") {
foreach ($row in $ExistingCSV) {
if ($row.mydata -eq "$LOT-$WID") {
$row.$Module = $Module
}
}
$ExistingCsv | Export-Csv $csv -NoType
} else {
$obj = New-Object -Type PSObject -Property #{
'mydata' = "$LOT-$WID"
'module1' = $null
'module2' = $null
'module3' = $null
'module4' = $null
'module5' = $null
}
$obj.$Module = $Module
$obj | Export-Csv $csv -NoType -Append
}
Replace $null with whatever value the moduleX fields are supposed to have.
I am fairly new in powershell scripting and need help on the following output in a csv format. I am trying to select a column e.g. ACCOUNT.UPLOAD and make and if/else statement to output it in another csv file. May someone help please.
Output csv should look like below:
$results = Import-Csv 'C:\Users\test\Desktop\Test\customer.csv' |
Select-Object "ACCOUNT.UPLOAD"
ForEach ($row in $results)
{
If ($row.Type0 -ne 'CP000101', 'CP000102')
{
$row."ACCOUNT.UPLOAD" = "$($row.ACCOUNT.UPLOAD)"
Write-Host $row."ACCOUNT.UPLOAD"
}
}
$results | Export-Csv C:\Users\test\Desktop\Test\test.csv -NoTypeInformation
Thank you
This will get you what you need. Added comments to explain what I have done.
$results = Import-Csv "C:\Users\test\Desktop\Test\customer.csv" | Select-Object "ACCOUNT.UPLOAD"
# Created array to be able to add individual results from foreach
$TheCSV = #()
ForEach ($row in $results) {
# You can use a -ne in the right hand side, if done like this.
If (($row.'ACCOUNT.UPLOAD' -ne 'CP000101') -and $row.'ACCOUNT.UPLOAD' -ne 'CP000102') {
# Adds the ROW column to the entry and finds the index that it was in from $results.
# Did a +2 as it does not include the header and it starts at value 0. So to match it up with the actual excel row numbers, add 2.
$row | Add-Member -Name 'ROW' -type NoteProperty -Value "$([array]::IndexOf($results.'ACCOUNT.UPLOAD',$row.'ACCOUNT.UPLOAD')+2)"
$TheCSV += $row
}
}
$TheCSV | Export-Csv "C:\Users\test\Desktop\Test\test.csv" -NoTypeInformation
Do it PowerShell way:
param(
[Parameter(Position=0)]
$InputFile = 'D:\\Temp\\Data.csv',
[Parameter(Position=1)]
$OutputFile = 'D:\\Temp\\Output.csv'
)
Import-Csv $InputFile |
Select-Object "ACCOUNT.UPLOAD" |
%{
$lineno++
if ($_.'ACCOUNT.UPLOAD' -notin #('CP000101', 'CP000102')) {
$_ | Add-Member -Name 'ROW' -type NoteProperty -Value $lineno
$_ # Output to pipeline
}
} -Begin { $lineno = 1 } |
Export-Csv $OutputFile -NoTypeInformation
Using:
.\Script.ps1
.\Script.ps1 inputfilename.csv outputfilefname.csv
I need to import a CSV file and then replace full usernames domain\username with username.
The following lines work but I only receive the amended usernames as the output and not the full file.
Could you please advise?
$TestFile = Import-Csv .\file.csv
$NewFile = $TestFile | ForEach-Object {$_."Username" -replace 'domain\\',''}
When processing CSV input with a ForEach-Object loop you need to output the data back to the pipeline. Also, the -replace operator doesn't modify variables or properties in-place. It takes the value, does the work, and outputs the modified string to the success output stream. If you want to update a property you need to assign the modified value back to that property.
Change this:
$TestFile = Import-Csv .\file.csv
$NewFile = $TestFile | ForEach-Object {$_."Username" -replace 'domain\\',''}
into this:
$NewFile = Import-Csv .\file.csv | ForEach-Object {
$_.Username = $_.Username -replace 'domain\\', '' # update username
$_ # feed data back into the pipeline
}
and the code will do what you want.
You can perform the replace on the string data, then convert it into an object using ConvertFrom-Csv.
$TestFile = (Get-Content .\file.csv) -replace 'domain\\',''
$NewFile = ConvertFrom-Csv $TestFile
Here's one way - get the column names from the input table, iterate each row in the table, and output new custom objects with needed changes.
$table = Import-Csv "Test.csv"
# Get column names
$columnNames = ($table | Select-Object -First 1).PSObject.Properties |
Select-Object -ExpandProperty Name
# Iterate each row in the table
foreach ( $row in $table ) {
$outputObject = New-Object PSObject
foreach ( $columnName in $columnNames ) {
if ( $columnName -eq "Username" ) {
$outputObject | Add-Member NoteProperty "Username" ($row.Username.Split('\')[1])
}
else {
$outputObject | Add-Member NoteProperty $columnName $row.$columnName
}
}
$outputObject
}
To create a new CSV file as output, put the above code in a script and pipe to Export-Csv.
I am trying to figure out how to correct this script I've wrote. I know it is something wrong with the way it is importing the list of hostnames. I don't know how to fix it.
Part 1: This is supposed to import a .csv with the hostnames and dig the registry for the application's uninstall information, put it into an array, and export into .csv's for later use. Also it creates .txt files in order to later compare the applications on the system to a baseline.
$path = "\\path"
$computers = Import-Csv -Path "\\Path\hostnames.csv"
$array = #()
foreach($pc in $computers)
{
$computername = $pc.computername
#$computername = "KNOWN_HOSTNAME" #test line for one system
$UninstallKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$reg = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$computername)
$regkey = $reg.OpenSubKey($UninstallKey)
$subkeys = $regkey.GetSubKeyNames()
foreach($key in $subkeys)
{
$thisKey=$UninstallKey+"\\"+$key
$thisSubKey=$reg.OpenSubKey($thisKey)
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $computername
$obj | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $($thisSubKey.GetValue("DisplayName"))
$obj | Add-Member -MemberType NoteProperty -Name "DisplayVersion" -Value $($thisSubKey.GetValue("DisplayVersion"))
$obj | Add-Member -MemberType NoteProperty -Name "Publisher" -Value $($thisSubKey.GetValue("Publisher"))
$obj | Add-Member -MemberType NoteProperty -Name "InstallDate" -Value $($thisSubKey.GetValue("InstallDate"))
$array += $obj
$ExportArray = $array | Where-Object { $_.DisplayName } |
select ComputerName , DisplayName, DisplayVersion, Publisher, InstallDate
$ExportArray |
Export-csv $path\$computername.csv -NoTypeInformation
$ExportArray2 = $array |
Where-Object { $_.DisplayName } |
select DisplayName, DisplayVersion, Publisher
$ExportArray2 |
Export-csv $path\$computername.txt -NoTypeInformation
}
}
Part 2: This portion compiles the .csv's into one excel document for reporting
$csvs = Get-ChildItem $path\* -Include *.csv
$outputfilename = "Network_" + (Get-Date -Format yyyyMMdd)
$excelapp = new-object -comobject Excel.Application
$excelapp.sheetsInNewWorkbook = $csvs.Count
$xlsx = $excelapp.Workbooks.Add()
$sheet=1
foreach ($csv in $csvs)
{
$row=1
$column=1
$worksheet = $xlsx.Worksheets.Item($sheet)
$worksheet.Name = $csv.Name
$file = (Get-Content $csv.PSPath | ForEach-Object {$_ -replace '"', ""})
foreach($line in $file)
{
$linecontents = $line -split ‘,(?!\s*\w+”)’
foreach($cell in $linecontents)
{
$worksheet.Cells.Item($row,$column) = $cell
$column++
}
$column = 1
$row++
}
$sheet++
}
$output = $path + “\” + $outputfilename + ".xlsx"
$xlsx.SaveAs($output)
$excelapp.quit()
Part 3: This portion loads up a baseline, and the .txt's created preciously, and checks for differences in the files. (also deletes blank ouput files)
$bline = Get-ChildItem $path\* -Include Baseline.txt
$txts = Get-ChildItem $path\* -Include *.txt -Exclude Baseline.txt
foreach ($txt in $txts)
{
Compare-Object -referenceobject $(Get-Content $bline) -differenceobject $(Get-Content $txt) |
ft inputobject, #{n = "file"; e = {if ($_.SideIndicator -eq '=>') {"System"} else {"Baseline"}}} |
Out-File $txt'_has_diff'.csv -Width 256
Get-ChildItem $path |
where {$_.Length -eq 0} |
Remove-Item
}
Thank you
Edit:
The Hostnames.csv files I've tried are:
HOSTNAME1
HOSTNAME2
and
"HOSTNAME1","HOSTNAME2"
It's a little unclear what the problem is, because you say there is "something wrong with the way it is importing the list of hostnames", but you haven't specified what kind of results you're getting and how they differ from the intended results.
However, based on your sample data I think I can infer what the problem is: You're trying to use Import-Csv on non-CSV data. Neither of your examples looks like a CSV file. They both look like lists. A list in which the items are separated by commas, such as
"HOSTNAME1","HOSTNAME2","HOSTNAME3","HOSTNAME4"
is not called a "CSV file". CSV files are a form of "flat file", in which the data represents the rows and columns of a single database table. An example of a CSV file would be something like this, where the first line is a list of field (column) names, and the other lines are records (rows) with the comma-separated values corresponding to the columns in the header row:
"Hostname","OS","OS Version","Primary Function","Location"
"BOSEXCH01","Windows","Server 2012","Microsoft Exchange","Boston"
"BOSDC01","Windows","Server 2008 R2","Active Directory domain controller","Boston"
"MYWEB","Linux","Ubuntu 13.04","Apache web server","Phoenix"
The cmdlet Import-Csv imports a CSV file into an array of objects in which the properties are the field names in the header row, and the values are the comma-separated items in each row corresponding to the property names derived from the header row. Export-Csv does the reverse—it creates a CSV file from an array of objects.
It looks like what you're trying to do is read a simple list of hostnames into an array of strings. If your data looks like the first example,
HOSTNAME1
HOSTNAME2
[etc...]
you can read it into an array by simply using Get-Content, as follows (note that I changed the extension to .txt to reflect the actual format of the data):
$computers = Get-Content "\\Path\hostnames.txt"
If your data looks like the second example,
"HOSTNAME1","HOSTNAME2",[etc...]
you can read it into array like this:
$computers = (Get-Content "\\Path\hostnames.txt") -split ','
On the other hand, it appears that you are using Export-Csv correctly: You're exporting a bunch of objects with the same properties into a flat file, which is the correct usage of the term "CSV".