I've got a huge comma seperated CSV-list with IP-addresses of my network that I want to run queries against. Example of my CSV input:
172.168.0.1,172.168.0.2,172.168.0.3,172.168.0.4
Etc....
When I run the following code to test for the output:
$filepath = "c:\scripts\servers.csv"
$servers = Import-CSV $filepath -delimiter ","
Foreach ($server in $servers) {
write-host $server
}
I get no output, I think it's because there are no headers specified. I can obviously do a workaround and open the CSV-file and type in all the headers. Are there any other ways to solve this?
You can create the headers on the fly (no need to specify delimiter when the delimiter is a comma):
Import-CSV $filepath -Header IP1,IP2,IP3,IP4 | Foreach-Object{
Write-Host $_.IP1
Write-Host $_.IP2
...
}
$IP_Array = (Get-Content test2.csv)[0].split(",")
foreach ( $IP in $IP_Array){
$IP
}
Get-content Filename returns an array of strings for each line.
On the first string only, I split it based on ",". Dumping it into $IP_Array.
$IP_Array = (Get-Content test2.csv)[0].split(",")
foreach ( $IP in $IP_Array){
if ($IP -eq "2.2.2.2") {
Write-Host "Found $IP"
}
}
Solution is to change Delimiter.
Content of the csv file -> Note .. Also space and , in value
Values are 6 Dutch word aap,noot,mies,Piet, Gijs, Jan
Col1;Col2;Col3
a,ap;noo,t;mi es
P,iet;G ,ijs;Ja ,n
$csv = Import-Csv C:\TejaCopy.csv -Delimiter ';'
Answer:
Write-Host $csv
#{Col1=a,ap; Col2=noo,t; Col3=mi es} #{Col1=P,iet; Col2=G ,ijs; Col3=Ja ,n}
It is possible to read a CSV file and use other Delimiter to separate each column.
It worked for my script :-)
$filepath = ".\ADcomputerslist.csv"
$servers = Import-CSV $filepath -delimiter ","
Foreach ($entry in $servers) { write-host $entry.name }
also can replace stupid file with object.
$servers = Get-ADComputer -Filter * -Property * | Select-Object Name,OperatingSystem,OperatingSystemVersion,ipv4Address
Foreach ($entry in $servers) { write-host $entry.name }
Related
I have a PowerShell script that creates a csv file and neatly separates all user input. I need the remaining output to be split across the two headers and I'm struggling to find out how. Tried lots of different code but had no luck.
$Devices = read-host -Prompt "Enter Full Device Name" | out-file 'C:\Users\Public\Desktop\Devices.csv' -Force
$Find = ", "
$Replace = "`n"
$Arrange = (Get-Content 'C:\Users\Public\Desktop\Devices.csv') -replace "$Find","$Replace" | Set-Content 'C:\Users\Public\Desktop\Devices.csv' -Force
$CSV = import-csv 'C:\Users\Public\Desktop\Devices.csv' -Header "Firstname","Lastname"
$CSV | Export-Csv -NoTypeInformation 'C:\Users\Public\Desktop\Devices.csv'
$import = Import-Csv 'C:\Users\Public\Desktop\Devices.csv'
This is the output I currently have in the CSV:
This is the output I am after:
Could almost do with a foreach loop as the first and last names are likely to change as these are inputted using a variable
any help is appreciated.
Export-Csv exports 1 column per distinct property of the input - so to get 2 columns, you need to pipe an object with 2 properties to Export-Csv.
# read device names, split into individual strings
$devices = Read-Host -Prompt "Enter Full Device Name(s)"
$devices = $devices -split ',\s*' |ForEach-Object Trim
# now create one object per device name
$records = $devices |ForEach-Object {
# start by splitting the string into 2 on the first `-`
$FirstName,$LastName = $_ -split '-',2
# now create the object
[pscustomobject]#{
FirstName = $FirstName
LastName = $LastName
}
}
# ... and finally, export to CSV
$records |Export-Csv 'C:\Users\Public\Desktop\Devices.csv' -NoTypeInformation
If you want to retain the - as part of the FirstName value, change this line:
$FirstName,$LastName = $_ -split '-',2
to:
$FirstName,$LastName = $_ -split '(?<=-)',2
Try this out. Since I don't know what your input file looks like there might be some redundant steps in there. Feel free to modify the code to remove any redundant lines if you feel like.
$Devices = read-host -Prompt "Enter Full Device Name" | out-file 'C:\Users\Public\Desktop\Devices.csv' -Force
$Find = ", "
$Replace = "`n"
$Arrange = (Get-Content 'C:\Users\Public\Desktop\Devices.csv') -replace "$Find","$Replace" | Set-Content 'C:\Users\Public\Desktop\Devices.csv' -Force
$CSV = import-csv 'C:\Users\Public\Desktop\Devices.csv' -Header "Firstname","Lastname"
$X = $CSV | select -Skip 1
$y = $x -replace '-','-,' # this adds a comma so that the values are in different columns
$y | Export-Csv -NoTypeInformation 'C:\Users\Public\Desktop\Devices.csv'
$import = Import-Csv 'C:\Users\Public\Desktop\Devices.csv' -Header "Firstname","Lastname"
I want to import .csv file in Powershell. It is only one line in the CSV, which is structured as follows: Text;Text;Text...
This is what i have tried before:
$folder_csv = 'C:\Users\Win_User\Desktop\Folder\CSV_Files'
$files = Get-ChildItem $folder_csv -File -Filter *.csv
foreach ($file in $files) {
$Split_content = $file.split(";")
$timestamp = $($Split_content[0])
$User = $($Split_content[1])
$PC = $($Split_content[2])
$Software = $($Split_content[3]).Substring(1)
}
Write-Host $timestamp + " " + $User + " " + $PC + " " + $Software
I get the following Error Message: "Method invocation failed because [System.IO.FileInfo] does not contain a method named 'split'" .
Is there a better way to imort a csv file and safe each value in a seperate varibale?
Thanks for your help.
Your example file is not containing a header so I guess that's your problem. Then you need to specify it manually when Importing the CSV file. This code works only for when you have one row, if you have multiple rows it will just overwrite the variables and keep the last one. But feel free to change that.
$Header = 'timestamp','User','PC','Software'
$data = Import-Csv -Path .\testcsv.csv -Delimiter ';' -Header $Header
foreach ($row in $data) {
$timestamp = $row.timestamp
$User = $row.User
$PC = $row.PC
$Software = $row.Software
}
$timestamp
$User
$PC
$Software
$Header = 'Name','Age','Profession'
$data = Import-Csv -Path F:\Temp\NoHeader.csv -Delimiter ',' -Header $Header
$data | select Name, Age, Profession
here is my problem:
I have a list of only lastnames stored in a smallfile.csv. Each name is a separate line.
I have a second hugefile.csv with several strings per line among them somewhere the last name.
Now I want to search each lastname of smallfile.csv in hugefile.csv and save the resulting hits.
I managed to do this manually for one lastname at a time using the following command line:
Get-Content 'C:\Y\Y\MAG\hugefile.csv' –read 10000000 | foreach { $_ -match "Smith"}|Out-File 'C:\Y\Y\MAG\Smith.csv'
How can I loop over this command drawing from the first file?
I tried something like this which did not work:
foreach($line in Get-Content C:\Y\Y\MAG\smallfile.csv') {
Get-Content 'C:\Y\Y\MAG\hugefile.csv' | foreach { $_ -match $line}| Out-File 'C:\Y\Y\MAG\$line.csv' -append
}
Thanks for suggestions!
Something like this should work.
$rootPath = "C:\Y\Y\MAG\"
$smallFilePath = $rootPath + "smallfile.csv"
$hugeFilePath = $rootPath + "hugefile.csv"
$smallFile = Get-Content -Path $smallFilePath
foreach ($line in $smallFile)
{
$outPath = $rootPath + $line + ".csv"
Get-Content -Path $hugeFilePath | Where { $_ -match $line } | Out-File $outPath
}
I have two csv file where I contain data, I need to check if value from CSV 1 exist in CSV 2 and if so then replace this value in file2 with data from file1, if no just skip to another row,
File1.csv
NO;Description
L001;DREAM
L002;CAR
L003;PHONE
L004;HOUSE
L005;PLANE
File2.csv
ID;Name;Status*;Scheduled Start Date;Actual Start Date;Actual End Date;Scheduled End Date;SLA
144862;DREAM;Scheduled;1524031200;;;1524033000;
149137;CAR;Implementation In Progress;1528588800;;;1548968400;
150564;PHONE;Scheduled;1569456000;;;1569542400;
150564;HOUSE;Scheduled;1569456000;;;1569542400;
150564;PLANE;;;;;;
I tried something like that but it is not working for me:
$file1 = Import-Csv "C:\Users\file1.csv" |Select-Object -ExpandProperty Description
$file2 = Import-Csv "C:\Users\file1.csv" |Select-Object -ExpandProperty NO
Import-Csv "C:\Users\file3.csv" |Where-Object {$file1 -like $_.Name} |ForEach-Object {
$_.Name = $file2($_.NO)
} |Out-File "C:\Users\File4.csv"
File4.csv should like that:
ID;Name;Status*;Scheduled Start Date;Actual Start Date;Actual End Date;Scheduled End Date;SLA
144862;L001;Scheduled;1524031200;;;1524033000;
149137;L002;Implementation In Progress;1528588800;;;1548968400;
150564;L003;Scheduled;1569456000;;;1569542400;
150564;L004;Scheduled;1569456000;;;1569542400;
150564;L005;;;;;;
Maybe there is another way to achive my goal! Thank you
Here's one approach you can take:
Import both CSV files with Import-Csv
Create a lookup hash table from the first CSV file, where the Description you want to replace are the keys, and NO are the values.
Go through the second CSV file, and replace any values from the Name column from the hash table, if the key exists. We can use System.Collections.Hashtable.ContainsKey to check if the key exists. This is a constant time O(1) operation, so lookups are fast.
Then we can export the final CSV with Export-Csv. I used -UseQuotes Never to put no " quotes in your output file. This feature is only available in PowerShell 7. For lower PowerShell versions, you can have a look at How to remove all quotations mark in the csv file using powershell script? for other alternatives to removing quotes from a CSV file.
Demo:
$csvFile1 = Import-Csv -Path .\File1.csv -Delimiter ";"
$csvFile2 = Import-Csv -Path .\File2.csv -Delimiter ";"
$ht = #{}
foreach ($item in $csvFile1) {
if (-not [string]::IsNullOrEmpty($item.Description)) {
$ht[$item.Description] = $item.NO
}
}
& {
foreach ($line in $csvFile2) {
if ($ht.ContainsKey($line.Name)) {
$line.Name = $ht[$line.Name]
}
$line
}
} | Export-Csv -Path File4.csv -Delimiter ";" -NoTypeInformation -UseQuotes Never
Or instead of wrapping the foreach loop inside a script block using the Call Operator &, we can use Foreach-Object. You can have a look at about_script_blocks for more information about script blocks.
$csvFile2 | ForEach-Object {
if ($ht.ContainsKey($_.Name)) {
$_.Name = $ht[$_.Name]
}
$_
} | Export-Csv -Path File4.csv -Delimiter ";" -NoTypeInformation -UseQuotes Never
File4.csv
ID;Name;Status*;Scheduled Start Date;Actual Start Date;Actual End Date;Scheduled End Date;SLA
144862;L001;Scheduled;1524031200;;;1524033000;
149137;L002;Implementation In Progress;1528588800;;;1548968400;
150564;L003;Scheduled;1569456000;;;1569542400;
150564;L004;Scheduled;1569456000;;;1569542400;
150564;L005;;;;;;
Update
For handling multiple values with the same Name, we can transform the above to use a hash table of System.Management.Automation.PSCustomObject, where we have two properties Count to keep track of the current item we're seeing and NO which is an array of numbers:
$csvFile1 = Import-Csv -Path .\File1.csv -Delimiter ";"
$csvFile2 = Import-Csv -Path .\File2.csv -Delimiter ";"
$ht = #{}
foreach ($row in $csvFile1) {
if (-not $ht.ContainsKey($row.Description) -and
-not [string]::IsNullOrEmpty($item.Description)) {
$ht[$row.Description] = [PSCustomObject]#{
Count = 0
NO = #()
}
}
$ht[$row.Description].NO += $row.NO
}
& {
foreach ($line in $csvFile2) {
if ($ht.ContainsKey($line.Name)) {
$name = $line.Name
$pos = $ht[$name].Count
$line.Name = $ht[$name].NO[$pos]
$ht[$name].Count += 1
}
$line
}
} | Export-Csv -Path File4.csv -Delimiter ";" -NoTypeInformation -UseQuotes Never
If your files aren't too big, you could do this with a simple ForEach-Object loop:
$csv1 = Import-Csv -Path 'D:\Test\File1.csv' -Delimiter ';'
$result = Import-Csv -Path 'D:\Test\File2.csv' -Delimiter ';' |
ForEach-Object {
$name = $_.Name
$item = $csv1 | Where-Object { $_.Description -eq $name } | Select-Object -First 1
# update the Name property and output the item
if ($item) {
$_.Name = $item.NO
# if you output the row here, the result wil NOT contain rows that did not match
# $_
}
# if on the other hand, you would like to retain the items that didn't match unaltered,
# then output the current row here
$_
}
# output on screen
$result | Format-Table -AutoSize
#output to new CSV file
$result | Export-Csv -Path 'D:\Test\File4.csv' -Delimiter ';' -NoTypeInformation
Result on screen:
ID Name Status* Scheduled Start Date Actual Start Date Actual End Date Scheduled End Date SLA
-- ---- ------- -------------------- ----------------- --------------- ------------------ ---
144862 L001 Scheduled 1524031200 1524033000
149137 L002 Implementation In Progress 1528588800 1548968400
150564 L003 Scheduled 1569456000 1569542400
150564 L004 Scheduled 1569456000 1569542400
150564 L005
I have trouble to use several commands in one Foreach or Foreach-Object loop
My situation is -
I have many text files, about 100.
So they are read Get-ChildItem $FilePath -Include *.txt
Every file's structure is same only key information is different.
Example
User: Somerandomname
Computer: Somerandomcomputer
With -Replace command I remove "User:" and "Computer:" so $User = Somerandomname and $computer = "Somerandomcomputer.
In each circle $user and $Computer with -Append should be written to one file. And then next file should be read.
foreach-object { $file = $_.fullname;
should be used, but I can not figure out the right syntax for it. Could someone help me with it?
Assuming you've defined $FilePath, $user, and/or $computer elsewhere, try something like this.
$files = Get-ChildItem $FilePath\*.txt
foreach ($file in $files)
{
(Get-Content $file) |
Foreach-Object { $content = $_ -replace "User:", "User: $user" ; $content -replace "Computer:", "Computer: $computer" } |
Set-Content $file
}
You can use ; to delimit additional commands in within the Foreach-Object, for example if you wanted to have separate commands for your user and computer name. If you don't enclose the Get-Content cmdlet with parenthesis you will get an error because that process will still have $file open when Set-Content tries to use it.
Also note that with Powershell, strings in double quotes will evaluate variables, so you can put $user in the string to do something like "User: $user" if you so desired.
Try this:
gci $FilePath -Include *.txt | % {
gc $_.FullName | ? { $_ -match '^(?:User|Computer): (.*)' } | % { $matches[1] }
} | Out-File 'C:\path\to\output.txt'
If User and Computer are on separate lines, you need to read the lines two at a time. The ReadCount parameter of Get-Content allows you to do that.
Get-ChildItem $FilePath -Include *.txt `
| Get-Content -ReadCount 2 `
| %{ $user = $_[0] -replace '^User: ', ''; $computer = $_[1] -replace '^Computer: ', ''; "$user $computer" } `
| Out-File outputfile.txt
This makes the assumption that every file contains only lines of the exact form
User: someuser
Computer: somecomputer
User: someotheruser
Computer: someothercomputer
...
If this is not the case, you will need to provide whatever is the exact file format.