I have a CSV with several rows and two columns: "Name" and "Information".
I'm looping through the CSV and checking each line for a condition, if the condition is met I'd like to remove the line:
for ($i=0; $i -le $CSV.length; $i++)
{
if ($CSV.name == "Fred")
{
#remove $CSV[$i] -- that one line; both "Name" and "Information"
}
}
I've seen solutions that use Get-Content or Import-Csv and temporary file(s) but I haven't wrapped my head around it and figure there must be an easier way.
Regardless, any help is appreciated!
I would read the CSV using the Import-CSV cmdlet and use the Where-Object cmdlet to filter the entries. Finally, write the CSV back using the Export-CSV cmdlet:
$csv = import-csv 'YourPath.csv'
$csv | Where Name -ne 'Fred' | Export-Csv 'YourPath.csv' -NoTypeInformation
Related
I am new to PowerShell, and I have an issue figuring out how to create from one or multiple .csv files, one file for each value finding in a column, with all the rows that contains in that value.
Let me explain with a example:
I have this source CSV:
I need to create a file for each App in the file. the output of the script should be something like this.
App1.csv
App2.CSV
That for each app that appear in the Original CSV, a new file with all row that have such value, in this case App.
I want to do it in PowerShell so in can be automated, I try with Group-object, then foreach with the values, without luck. I wasn't even remotely close to found the solution.
Thanks in advance and happy coding!
I do not have the most elegant solution, but it works, I checked it on your files, but I ask you to upload the contents of the file as text next time to make it easier to copy. And don't forget choose delimiter in code (I usually use ';')
$some=Import-Csv "D:\testdir\file1.csv" -Delimiter ';'|
Sort-Object header2|
Group-Object -Property header2
foreach ($i in $some){
$i.Group|
Export-Csv -Delimiter ';' -Encoding UTF8 -NoTypeInformation -Force -Path ("D:\testdir\"+$i.Name+".csv")
}
Import the CSV.
Select all the unique values from the column that contains the App name.
Loop through the app names and get all rows where the app name matches.
Export to CSV.
$Path = "./MyFile.csv"
$DestinationDir = "./"
$CSV = Import-CSV -Path $Path
$AppNames = $CSV.H2 | Select -Unique
Foreach ($App in $AppNames)
{
$DestinationPath = Join-Path -ChildPath $App -Path $DestinationDir
$CSV | Where {$_.H2 -eq $APP} | Export-Csv -NoTypeInformation -Path $DestinationPath
}
Example CSV:
H1,H2,H3,H4
Data,App1,Data,Data
Data,App1,Data,Data
Data,App1,Data,Data
Data,App2,Data,Data
Data,App2,Data,Data
For performance reasons, you probably want to use the steppable pipeline here:
$Pipeline = #{}
Import-Csv .\Source.csv |
ForEach-Object -Process {
if (!$Pipeline.Contains($_.Header2)) {
$Pipeline[$_.Header2] = { Export-CSV -notype -Path .\$($_.Header2).csv }.GetSteppablePipeline()
$Pipeline[$_.Header2].Begin($True)
}
$Pipeline[$_.Header2].Process($_)
} -End {
foreach ($Key in $Pipeline.Keys) { $Pipeline[$Key].End() }
}
For a detailed explanation, see: Mastering the (steppable) pipeline
New to Powershell and looking for some help. I have multiple xyz files that are currently displaying a z value with positive up and I need to make all the values negative (or z-positive down). So far my best attempt has been to try to cobble together what I know from other lines of code, but I'm still far from a solution.
$data = Get-ChildItem "C:\Users\dwilson\Desktop\test" -Recurse |
foreach ($item in $data) {$item.'Col 3' = 0 - $item.'Col 3'}
Any help would be greatly appreciated!
Somewhat of an aside, but you're using mixed syntax here.
foreach ($i in $set) { ... }
This is the Foreach statement. It does not accept input from the pipeline, nor will it automatically send output down the pipeline. See also Get-Help about_Foreach.
Get-ChildItem | ForEach-Object { ... }
This is the ForEach-Object command. It accepts input from the pipeline and sends output down the pipeline. Critically, this command also has a default alias of foreach. See also Get-Help ForEach-Object.
The help for the Foreach statement explains how PowerShell decides what foreach means (emphasis mine):
When Foreach appears in a command pipeline, PowerShell uses the foreach alias, which calls the ForEach-Object command. When you use the foreach alias in a command pipeline, you do not include the ($<item> in $<collection>) syntax as you do with the Foreach statement. This is because the prior command in the pipeline provides this information.
Using the looping over the files returned by Get-ChildItem you can import each with Import-CSV using the -Header parameter to assign the property name for each column. Then we can update the information for that property then export it. Using the ConvertTo-CSV cmdlet and then using Select-Object -Skip 1 we can drop the header off the CSV before exporting it.
$Files = Get-ChildItem "C:\Users\dwilson\Desktop\test" -Recurse
foreach ($File in $Files) {
$Data = Import-CSV $File -Header 'Col1','Col2','Col3'
$newData = ForEach ($Row in $Data) {
$Row.'Col3' = 0 - $Row.'Col3'
$Row
}
$newData |
Convertto-CSV -NoTypeInformation |
Select-Object -Skip 1 |
Out-File "$($File.Fullname).new)"
}
I tried the following to turn a text file into a document by leveraging import-csv where each item in the original document was a new line
Sample file.txt
James Cameron
Kirk Cobain
Linda Johnson
Code:
$array = import-csv file.txt | ConvertFrom-Csv -Delim `r
foreach ($Data in $array)
{
if (sls $Data Master.txt -quiet)
{Add-Content file.txt $Data}
}
It never created the document
Import-Csv takes a CSV and outputs PSCustomObjects. It's intended for when the file has a header row, and it reads that as the properties of the objects. e.g.
FirstName,LastName
James,Cameron
Kirk,Cobain
# ->
#{FirstName='James';LastName='Cameron'}
#{FirstName='Kirk';LastName='Cobain'}
etc.
If your file has no header row, it will take the first row and then ruin everything else afterwards. You need to provide the -Header 'h1','h2',... parameter to fix that. So you could use -Header Name, but your data only has one property, so there's not much benefit.
ConvertFrom-Csv is intended to do the same thing, but from CSV data in a variable instead of a file. They don't chain together usefully. It will try, but what you end up with is...
A single object, with a property called '#{James=Kirk}' and a value of '#{James=Linda}', where 'James' was taken from line 1 as a column header, and the weird syntax is from forcing those objects through a second conversion.
It's not at all clear why you are reading in from file.txt and adding to file.txt. But since you don't have a CSV, there's no benefit from using the CSV cmdlets.
$lines = Get-Content file.txt
$master = Get-Content master.txt
foreach ($line in $lines)
{
if ($master -contains $line)
{
Add-Content file2.txt $line
}
}
or just
gc file.txt |? { sls $_ master.txt -quiet } | set-content file2.txt
Auto-generated PS help links from my codeblock (if available):
gc is an alias for Get-Content (in module Microsoft.PowerShell.Management)
? is an alias for Where-Object
sls is an alias for Select-String (in module Microsoft.PowerShell.Utility)
Set-Content (in module Microsoft.PowerShell.Management)
I have a colon-delimited CSV like so,
Mailbox:Users
AcmeCorp:("jsmith","trex")
XyzCorp:("sjobs","bfranklin")
It is then added to a variable:
$file = import-csv file.csv -delimiter :
Now, I work with it:
foreach ($record in $file) {
$record.Users | % { get-aduser $_ }
}
write-host in the foreach loop reports $record.Users is ("jsmith","trex")
However, get-aduser (or other cmdlets) complains that it cannot find an object with identity '("jsmith","trex")'.
How do you prevent foreach from adding single quotes to parameter?
I've already tried Users like "sjobs","bfranklin" but import-csv strips the double quotes off of sjobs
Or better, how do you pass a list of users to foreach?
PowerShell version 4
The quotes are not being added by PS. They are right there in your file. Here is a snippet to give you a start in the right direction:
$file = Import-csv file.csv -delimiter ':'
foreach($row in $file){
foreach($user in $row.Users.split(',')){
Get-ADUser ($user.replace('(','').Replace('"','').replace(')',''))
}
}
I think the issue here is that you think that you are importing an array of strings as the value of Users, but you in fact are just importing a single string. There are a couple of options here, using the split method as you have already discovered:
$file = import-csv file.csv -delimiter ':'
ForEach($Record in $File){
$Record.Users.Trim('()').Split(',') | ForEach{
Get-ADUser $_.Trim('"')
}
}
So the $Record.Users.Trim('()') removes the parenthesis from the string. Then it uses .Split(',') to split the string into an array of strings. Then it passes that to an inner ForEach loop when gets the ADUser from each string, after removing the quotes from around it (with .Trim('"')).
Alternatively you could have one user per line, so your CSV would appear like:
Mailbox:User
AcmeCorp:jsmith
AcmeCorp:trex
XyzCorp:sjobs
XyzCorp:bfranklin
Then after importing the CSV you could just group by the mailbox if needed, say, to add users per mailbox or something:
$File = Import-CSV C:\Path\To\File.csv -delimiter ':'
$MBGroups = $File | Group Mailbox
ForEach($Record in $MBGroups){
$Mailbox = $Record.Name
$Users = $Record.Group | ForEach{Get-ADUser $_.User}
$Users | ForEach{Set-ADUser -mail ($_.samaccountname+"#"+$Mailbox+".com")}
}
I have a CSV text file separated with ; and it's in the format as:
USER_EMPLOYEE_ID;SYSTEM1;USERNAME1
The first column is an identity and the following pairs of columns are user's account on different active directories. I have placed garbage data but the idea is there.
ay7suve0001;ADDPWN;ay7suve0001
AAXMR3E0001;ADDPWN;AAXMR3E0001
ABABIL;ADDPWN;ABABIL
ABDF17;ADDPWN;ABDF17;
ABKMPPE0001;ADDPWN;ABKMPPE0001
ABL1FL;ADDPWN;ABL1FL
AB6JG8E0004;ADDPWN;AB6JG8E0004;
ACB4YB;ADDPWN;ACB4YB
ACK7J9;ADDPWN;ACK7J9
ACLZFS;ADDPWN;ACLZFS;
ACQXZ3;ADDPWN;ACQXZ3
Now there is a requirement that I have to append a fixed string like #ADDPWN.com to all the USERNAME1 values. Some records are having a ; and some don't.
Is there a quick way to append the #ADDPWN.com to each line taking care of:
any ;
any already #ADDPWN.com
From PowerShell?
Import-Csv is your friend. The following should get you on the right track.
Import-Csv "import.csv" -Delimiter ';' |
foreach {
if ($_.username1 -notlike '*#ADDPWN.com') { $_.username1 += '#ADDPWN.com' }
$_
} |
Export-Csv "export.csv" -Delimiter ';'
This assumes the first line of your csv file is your header line. If it's not, you can pass -Header 'USER_EMPLOYEE_ID','SYSTEM1','USERNAME1' as another parameter to Import-Csv.
Export-Csv adds some extra stuff like quotes around parameters, so you may need to play with the output format if you don't want that.
For another explanation how this works, check out Changes last name, first name to first name, last name in last column CSV powershell
This was a solution that worked for me.........
#opens list of file names
$file2 ="F:\OneDrive_Biz\PowerApps\SecurityCameraVideoApp\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://analytics-my.sharepoint.com/personal/gpowell_analytics_onmicrosoft_com/Documents/PowerApps/SecurityCameraVideoApp/Video_Files/" + $x[$i]
}
$x
#remove all files in target directory prior to saving new list
get-childitem -path C:\_TEMP\file_list_names.csv | remove-item
Add-Content -Path C:\_TEMP\file_list_names_url.csv -Value $x