Replace column values with Powershell - csv

I'm trying to cycle through a csv and replace any values in a column named Enabled from True to A.
Import-Csv .\test.csv | Where-Object {$_.Enabled -eq 'True'} --> what goes here to replace 'True' with 'A'?

Where-Object acts like a filter, so the columns that get passed to the rest of the pipeline will only be the ones where Enabled is True; which will prevent you from including the others in your output file (I'm assuming you want to have a complete file at the end).
So I would recommend using ForEach-Object and then modifying based on a condition inside there, but still passing each object through (modified or not):
Import-Csv .\test.csv | ForEach-Object {
if ($_.Enabled -eq 'True') {
$_.Enabled = 'A'
}
$_
} | Export-Csv .\test-modified.csv -NoTypeInformation

Briantist's answer works just fine. If you really wanted to get crazy with it you could create an Excel comobject, select the workbook/sheet, then select the "enabled" entire column, snip out empty cells/column header, then loop through and essentially do the same thing as what briantist said, although this way you can do things like add conditional formatting, etc. Just depends what all you are trying to do

Related

ConvertFrom-Json output doesn't work for Select-Object

I am using PowerShell 4 to make a series of web requests. From one call I get a generic array - for the sake of discussion it looks like this
$data = '[{"Id":"1","Name":"One"},{"Id":"2","Name":"Two"}]'
I am trying to parse this data to pull out the Name properties. However, when I use the following call it writes a line with Name and no information under it:
$data | ConvertFrom-Json | Select-Object Name
But if I save the object to an intermediate object like this it works:
$o1 = $data | ConvertFrom-Json
$o1 | Select-Object Name
I get the proper output.
The object types are different but I don't understand why. Here's output from relevant Get-Member calls:
$test | ConvrtFrom-Json | gm
TypeName: System.Object[]
and
$o1 | gm
TypeName: System.Management.Automation.PSCustomObject
Can anyone help me understand what I'm doing wrong in terms of my collection management? I'd like to be able to do this in one statement.
It seems like the parentheses are needed for some mysterious reason, as OP pointed out in the comment. Adding parentheses was the fix for me as well.
I am not sure why this breaks without parens, but I can confirm that code without parens is not an issue when executed in powershell core.

Powershell file URL / file filtering

I am trying to generate an html page with file index. This approach worked seamlessly:
$htmlout = Get-ChildItem -Path "$SearchPath" -Filter "$fileType" -Recurse |
Select #{Name="Link";Expression={("<a rel=" + $_.FullName + " href=file:///" + $_.FullName + ">$_</a>")}}
The Link column had file names only (i.e. test.txt) and displayed file content when clicking on it. Then we've got an additional requirement to skip old files. The script is now:
$htmlout = Get-ChildItem -Path "$SearchPath" -Recurse -include ("$fileType") | Where-Object {$_.LastWriteTime -ge "01/01/2014"} |` Select #{Name="Link";Expression={("<a rel=" + $_.FullName + " href=file:///" + $_.FullName + ">$_</a>")}}
It still works, but Link column now displays the entire file path + file name (i.e. \fileserver\folder1\folder2\test.txt).
Adding >$_.Name< does not work here.
I am trying to understand why the same URL line behaves differently after filter change.
Background
As far as I can tell, there is a discrepancy with the interaction between the .ToString() method and the DefaultDisplayProperty of objects returned by Get-ChildItem.
The behavior manifests when both of the following conditions are true:
- The -filter parameter is being used.
- The value of the -Path parameter resolves to a single directory, whether or not -Recurse is used.
Under the above circumstances, the .ToString() method implemented by PowerShell uses the Name property as default, rather than FullName as is the case in all other scenarios.
My guess is that this inconsistency is due to the underlying object types returned by the FileSystem provider when -Filter is used, rather than the objects PowerShell returns when it handles the search/filter itself (as is the case with -Include).
Observation
When you wrap your $_ pipeline object variable in double quotes, PowerShell's type-conversion implicitly calls the .ToString() method and you get the resulting name variation.
Solution
To correct your issue, you could simply use -Filter in both code examples and get the desired output, however, that is prone to cause problems sooner or later.
The more appropriate way to negate the problem is to properly use a PowerShell sub-expression within the double-quoted strings.
To create a sub-expression, simply wrap the desired code like so: $(). This creates a separation between which characters are code and which are part of the string; in your case allowing you to use the member access operator .. The method also alleviates the need to do string concatenation with the + operator.
Solution Code:
$HTMLOut = Get-ChildItem -Path $SearchPath -Recurse -Include $FileType | Where-Object {$_.LastWriteTime -ge "01/01/2014"} | Select #{Name="Link";Expression={("<a rel=$($_.FullName) href=file:///$($_.FullName)>$($_.Name)</a>")}}

Replace headers on export-csv from selectable list using powershell

fairly new to powershell and I have given myself a bit of a challenge which I think should be possible, I'm just not sure about the best way around it.
We have a user who has a large number of columns in a csv (can vary from 20-50), rows can vary between 1 and 10,000. the data is say ClientName,Address1,Address2,Postcode etc.. (although these can vary wildly depending on the source of the data - external companies) This needs importing into a system using a pre-built routine which looks at the file and needs the database column headers as the csv headers. so say ClientDisplay,Ad_Line1,Ad_Line2,PCode etc..
I was thinking along the lines of either a generic powershell 'mapping' form which could read the headers from ExternalSource.csv and either a DatabaseHeaders.csv (or a direct sql query lookup) display them as columns in a form and then highlight one from each column and a 'link' button, once you have been through all the columns in ExternalSource.csv a 'generate csv' button which takes the mapped headers an appends the correct data columns from ExternalSource.csv
Am I barking up the wrong tree completely trying to use powershell? at the moment its a very time consuming process so just trying to make life easier for users.
Any advice appreciated..
Thanks,
Jon
You can use the Select-Object cmdlet with dynamic columns to shape the data into the form you need.
Something like:
Import-Csv -Path 'source.svc' |
Select-Object Id, Name, #{ Name='Ad_Line1'; Expression={ $_.Address1 } } |
Export-Csv -Path 'target.csv'
In this example, the code #{ Name='Ad_Line1'; Expression={ $_.Address1 } } is a dynamic column, that creates a column with name AD_Line1' and the value ofAddress1`
It is possible to read the column mappings from a file, you will have to write some code to read the file, select the properties and create the format.
A very simple solution could be to read the Select-Object part from another script file, so you can differentiate that part for each import.
A (simple, naive, low performant) solution could look like this (untested code):
# read input file
$input = Import-Csv -Path $inputFile
# read source, target name columns from mapping file
$mappings = Import-Csv -Path $mappingFile | Select Source, Target
# apply transformations
$transformed = $input
foreach($mapping in $mappings) {
# collect the data, add an extra column for each mapping
$transformed = $transformed | Select-Object *, #{ Name = $mapping.Target; Expression = { $_.$($mapping.Source) } }
}
#export transformed data
$transformed | Export-Csv -Path $outputFile
Alternatively; It is possible to convert the data into XML with Import-Csv | Export-CliXml, apply an Xslt template on the Xml to perform a transformation, and save the Xml objects into Csv again with Import-CliXml | Export-Csv.
See this blog by Scott Hansleman on how you can use XSLT with PowerShell.

Can I assign Variables from selected Row using out-gridview -passthru

I'm very new to PowerShell and I'm trying to build on older batch files that I made into PowerShell and add some features.
At the moment I have a CSV file which I've used in the pass as a sort of "environment" file, previously I would do batch jobs against this CSV file.
I have a line
Import-Csv "csvfile" | select-object -property * | out-gridview -passthru
The CSV file is built something like:
Name,location,folder
Test,e,Testsite
Test1,c,windows
test2,c,temp
Basically I want to select one of the grows and click Okay and assign the 3 items to variables.. $foldername,$driveLetter,$destinationDirectory
I've looked high and low and I can't seem to manage it I did find one example on StackOverflow which I shamelessly copied, massaged and got to work ... but that gridview is prebuilt by the OP of that post and doesn't have things like the piping to grid-view.-Passthru has (Filter & scroll bar) but I was able to assign variables using this method but my CSV is pretty huge and I want to be able to have it auto size itself and filter / scroll.
You need to use the -OutPutMode Single option of Out-Gridview to restrict selection to a single item from the gridview.
Import-Csv "csvfile" |
select-object -property * |
out-gridview -OutputMode Single -Title 'Select a row' |
ForEach-Object {
$foldername,$driveLetter,$destinationDirectory = $_.Name,$_.location,$_.folder
}

How to replace multiple values in a CSV or html file with PowerShell?

I wrote a script to read a list of folder objects into an xml file showing the properties for the folder. It also creates another xml file at a later point in time. After the delta xml file is created, I import both xml files and compare them based on the folder name to display which folders have been deleted or removed and save the results in html format to a file for viewing. Everything works well, but I want to replace some of the values in the results. The compare-object cmd-let lets me display some attributes, but tells what side the change was on by putting => for a folder added in the delta file or <= for a folder removed in the delta file. I really would like to replace the column name of SideIndicator and the replace the => or <= values with something more intuitive. I played around with useing -Replace {$_ $original, $newvalue} type method. I found guidance on Hey Scripting Guy blog and some other examples around, but none seemed to do what I want. What is the best way to approach this? Currently I'm not storing the compared results, just formatting and converting to HTML. Any advice is appreciated. I can post the code if needed, but it is about 60 lines long and I'm really looking for the best way to accomplish this, not neccesarily someone to write the code.
Thanks!
If you just want to replace column names in the output display, you can create a custom table:
http://gallery.technet.microsoft.com/scriptcenter/ed188912-1a20-4be9-ae4f-8ac46cf2aae4
That is one approach, but I ended up modifying the html report by doing the following:
(Get-Content $WorkingDirectory\FolderAudit_$UseDateTime.htm) |
Foreach-Object {$_ -replace "SideIndicator", "Change Status"} |
Set-Content $WorkingDirectory\FolderAudit_$UseDateTime.htm
(Get-Content $WorkingDirectory\FolderAudit_$UseDateTime.htm) |
Foreach-Object {$_ -replace "=>", "New"} |
Set-Content $WorkingDirectory\FolderAudit_$UseDateTime.htm
(Get-Content $WorkingDirectory\FolderAudit_$UseDateTime.htm) |
Foreach-Object {$_ -replace "<=", "Removed"} |
Set-Content $WorkingDirectory\FolderAudit_$UseDateTime.htm
It didn't seem to work well as one statement that replaced the three different pieces I was looking for. Eventually I'll play around with it and streamline it some, but for now it does what I want.