I have a csv file that has multiple lines of text and columns. I want to write a script that will assign each column a variable from a single row one at a time and move to the next row. Basically, what should happen is that the first column should be stored as URL, the second as list and the third as field and then perform these tasks. Then move to the next row.
$web = Get-SPWeb (Your site URL)
$list = $web.Lists[“Your List Name”]
$field = $list.Fields[“Your Column Name”]
$field.AllowDeletion = “true”
$field.Sealed = “false”
$field.Delete()
$list.Update()
$web.Dispose()
I can do it line by line, but I would like to find out a better way to do this. I've tried writing code a number of ways, but I can't figure out how to do this with a "foreach" loop. Please help.
Without knowing the format of the CSV fields, it's hard to say for sure but something like this might work in terms of adapting your code (assuming here you have csv column names of URL, List and Column):
$csv = import-csv C:\yourpath\yourfile.csv
$csv | select * | foreach {
$web = Get-SPWeb ($_.URL)
$list = $web.Lists[$_.List]
$field = $list.Fields[$_.Column]
$field.AllowDeletion = “true”
$field.Sealed = “false”
$field.Delete()
$list.Update()
$web.Dispose()
}
I can't test the sharepoint elements but importing the csv (if it has a header row) then iterating through each object/row using a foreach loop will work.
Importance of header row is that Import-CSV will automatically create a NoteProperty named for each heading that you can then use to access that value in the current object/row.
Related
I have only one excel file, the file has multiple spreadsheets, I loop through all the spreadsheets and find the rows whose column1 and column2 satisfy my criteria, and if it does, copy the rows to a new excel workbook, I need to copy the first row that specifies what the column names are as well, but right now I'm ignoring this to simplify the problem.
I looked up online, and found a post similar to my question, I modified the code according to my situation, here's the code:
$WindowsFolder = "C:\Users\wanlingjiang\Downloads\xlsx\"
# Create a new datatable to copy data into.
$dtExcel = New-Object System.Data.DataTable
# Counter used to only create data columns on the first index in the loop.
$count = 1
# Get all spreadsheet objects from the current folder.
$SpreadSheets = Get-ChildItem $WindowsFolder -File -Verbose
# Loop through each of the spreadsheet objects returned.
foreach ($SpreadSheet in $SpreadSheets) {
# Index the counter.
try{
# Import the data from the source spreadsheet into datatables.
$dts = Get-TablesFromXLSXWorkbook -InputFileName $SpreadSheet.FullName -Verbose -ErrorAction Stop
# We only need to work with the first datatable imported from each spreadsheet.
$Rows = $dts[0].Rows
# Create the data columns within the target datatable
# using the column headers from the current spreadsheet.
if($count -eq 1) {
foreach ($item in $dts.Columns) {
$dtExcel.Columns.Add($item.ColumnName) | Out-Null
}
$count++
}
# Loop through each row of data returned from the current spreadsheet.
foreach ($row in $Rows) {
# Determine if the 'Column1' column in the current row equals 'Criteria1' and if the 'Column2' column in the current row starts with 'Criteria2'.
# If yes, copy the data row to the target datatable.
if($row.'Column1' -eq 'Criteria1' -and $row.'Column2' -like 'Criteria2*') {
$dr = $dtExcel.NewRow()
$dr.ItemArray = $row.ItemArray.Clone()
$dtExcel.Rows.Add($dr)
}
}
} catch {
Write-Warning -Message "Something happened. Write a good error message."
}
}
# Export the target datatable to a new Excel spreadsheet.
New-XLSXWorkbook -InputTables $dtExcel -OutputFileName 'C:\Users\wanlingjiang\Downloads\xlsx\Output.xlsx' -Open
It is not working, the error message says:
New-XLSXWorkbook : The term 'New-XLSXWorkbook' is not recognized as the name of a cmdlet, function, script file, or operable program.
I removed the last line, and tried to debug, it stopped at this line:
$dts = Get-TablesFromXLSXWorkbook -InputFileName $SpreadSheet.FullName -Verbose -ErrorAction Stop
Do I need to install something? Please help. Thank you!
I have here my XML, CSV and Excel files.
I'm trying to get all the Numbers from the "Key" of my XML file.
$DocNo = $XML.Settings.Setting.Key
then get all the Corresponding File Name of that Numbers from my CSV file.
Foreach ($Line in $CSVContent) {
# (-split) the Array of Strings by Separating them from ","
$LineSplit = $Line -split ","
# Find the $Line that has the Value of $DocNo
If ($LineSplit -like $DocNo) {
# Store the String Value of $DocNo in "$FileNames"
$FileNames = $LineSplit
}
}
Write-Host $FileNames
then use the $FileNames as the File Name to be opened as a workbook.
# For every Number of Key
ForEach($Files in $DocNo){
# Open their Excel Workbook (INSERT THE FILENAME OF THE FILE NO. FROM CSV)
$WorkBook = $Excel.Workbooks.Open($Files.$FileNames)
}
The problem is there's no value showing in my $FileNames.
I can display the $FileNames but I have to specifically call them one by one.
Any suggestions and help will be appreciated :)
In the first block of code, $LineSplit is the result of using -split on a line from a CSV file. $LineSplit is an array, in your case the array contains two elements for each line from the CSV file:
$LineSplit[0] = '1'
$LineSplit[1] = 'File1.xlsx'
The square bracket notation allows you to select an element from the array by its position in the array, starting from zero.
The issue with the first block of code is that a condition ($LineSplit -like $DocNo) is comparing an array to an array using the like operator, I'm not sure what that will do but it's hard to follow. I would consider recoding it as follows:
if ($LineSplit[0] -in $DocNo)
This asks if the first column of the CSV row is in the list pulled from your XML file, then proceed.
The next issue is the building of the $FileNames variable. Each time this statement is executed in your code:
$FileNames = $LineSplit
The two element array $LineSplit representing the current CSV row, split by comma, overwrites the value of $FileNames. By the end of the loop, this only contains the last CSV line which matched the condition. This should be recoded as an array. Before the loop set up an empty array:
$FileNames = #()
Now, during the loop when the condition is met:
$FileNames += $LineSplit[1]
Recalling that $LineSplit[1] contains the filename, as it is the second element of the CSV row when split by comma. By the end of the loop the $FileNames variable should contain an array of files that are in both the CSV and the XML. The += bit is an operator that adds new elements without overwriting.
Finally, the second block of code is close, but not quite there. The loop runs through the values in $DocNo, which according to your screenshot are:
1,2,3,4,5,6
These values are placed into the $Files variable for each loop - and then the $File.$FileNames syntax is incorrect, it is attempting to retrieve a property from the numbers retrieved from the $DocNo values. The values are just integers, so there is no $FileNames property to retrieve. The loop should run through the list we already constructed
ForEach ($File in $FileNames) {
# Open their Excel Workbook (INSERT THE FILENAME OF THE FILE NO. FROM CSV)
$WorkBook = $Excel.Workbooks.Open($File)
}
Final tip, use Write-Host to display the value of variables as you go, e.g.
Write-Host $LineSplit[0]
I'm working on a PS script to take a row of data from an Excel spreadsheet and populate that data in certain places in a Word document. To elaborate, we have a contract tracking MASTER worksheet that among other things contains data such as name of firm, address, services, contact name. Additionally, we have another TASK worksheet in the same workbook that tracks information such as project owner, project name, contract number, task agree number.
I'm writing a script that does the following:
Ask the user through a message box what kind of contract is being written ("Master", or "Task")
Opens the workbook with the appropriate worksheet opened ("Master" tab or "Task" tab)
Asks the user through a VB InputBox from which Excel row of data they want to use to populate the Word contract
Extracts that row of data from Excel
Outputs certain portions of that row of data to certain location in a Word document
Saves the Word document
Opens the Word document so the user can continue editing it
My question is this - using something like PSExcel, how do I extract that row of data out to variables that can be placed in a Word document. For reference, in case you're going to reply with a snippet of code, here are what the variables are defined as for the Excel portion my script:
$Filepath = "C:\temp\ContractScript\Subconsultant Information Spreadsheet.xlsx"
$Excel = New-Object -ComObject Excel.Application
$Workbook = $Excel.Workbooks.Open($Filepath)
$Worksheet = $Workbook.sheets.item($AgreementType)
$Excel.Visible = $true
#Choosing which row of data
[int]$RowNumber = [Microsoft.VisualBasic.Interaction]::InputBox("Enter the row of data from $AgreementType worksheet you wish to use", "Row")
Additionally, the first row of data in the excel worksheets are the column headings, in case it matters.
I've gotten this far so far:
import-module psexcel
$Consultant = new-object System.Collections.Arraylist
foreach ($data in (Import-XLSX -path $Filepath -Sheet $AgreementType -RowStart $RowNumber))
{
$Consultant.add($data)'
But I'm currently stuck because I can't figure out how to reference the data being added to $consultant.$data. Somehow I need to read in the column headings first so the $data variable can be defined in some way, so when I add the variable $consultant.Address in Word it finds it. Right now I think the variable name is going to end up "$Consultant.1402 S Broadway" which obviously won't work.
Thanks for any help. I'm fairly new to powershell scripting, so anything is much appreciated.
I have the same issue and searching online for solutions in a royal PITA.
I'd love to find a simple way to loop through all of the rows like you're doing.
$myData = Import-XLSX -Path "path to the file"
foreach ($row in $myData.Rows)
{
$row.ColumnName
}
But sadly something logical like that doesn't seem to work. I see examples online that use ForEach-Object and Where-Object which is cumbersome. So any good answers to the OP's question would be helpful for me too.
UPDATE:
Matthew, thanks for coming back and updating the OP with the solution you found. I appreciate it! That will help in the future.
For my current project, I went about this a different way since I ran into lack of good examples for Import-XLSX. It's just quick code to do a local task when needed, so it's not in a production environment. I changed var names, etc. to show an example:
$myDataField1 = New-Object Collections.Generic.List[String]
$myDataField2 = New-Object Collections.Generic.List[String]
# ...
$myDataField10 = New-Object Collections.Generic.List[String]
# PSExcel, the third party library, might want to install it first
Import-Module PSExcel
# Get spreadsheet, workbook, then sheet
try
{
$mySpreadsheet = New-Excel -Path "path to my spreadsheet file"
$myWorkbook = $mySpreadsheet | Get-Workbook
$myWorksheet = $myWorkbook | Get-Worksheet -Name Sheet1
}
catch { #whatever error handling code you want }
# calculate total number of records
$recordCount = $myWorksheet.Dimension.Rows
$itemCount = $recordCount - 1
# specify column positions
$r, $my1stColumn = 1, 1
$r, $my2ndColumn = 1, 2
# ...
$r, $my10thColumn = 1, 10
if ($recordCount -gt 1)
{
# loop through all rows and get data for each cell's value according to column
for ($i = 1; $i -le $recordCount - 1; $i++)
{
$myDataField1.Add($myWorksheet.Cells.Item($r + $i, $my1stColumn).text)
$myDataField2.Add($myWorksheet.Cells.Item($r + $i, $my2ndColumn).text)
# ...
$myDataField10.Add($myWorksheet.Cells.Item($r + $i, $my10thColumn).text)
}
}
#loop through all imported cell values
for ([int]$i = 0; $i -lt $itemCount; $i++)
{
# use the data
$myDataField1[$i]
$myDataField2[$i]
# ...
$myDataField10[$i]
}
Using Powershell, I need to loop through each cell of a column and check to see if that value exists in another loop through of .txt files, in any of the files then populate an additional column(s) in the spreadsheet indicating which .txt files contain the value(s)
So far, I have a Powershell script which looks through a set of files from a selected destination. The script allows you to choose filename and extension and content. This part is good because I want to be able to loop through a selection of files, but I want the $SearchText value that it looks for in the files, to be looped through, changing one by one to each value in column A of a Worksheet I have in Excel. Once it finds the value in any of the selected files that are being looped through, it'll add a column to the Worksheet giving the file name it has been found in. If it's found in more than one file, it'll add columns for each it finds.
clear;
$Files = "";
$FileNameEnds = "";
$FileExt = ".txt";
$SearchText = "";
Foreach ($file in [System.IO.Directory]::GetFiles($Files,"*"+"$FileNameEnds."+$FileExt, [System.IO.SearchOption]::AllDirectories))
{
$Textfile = [System.IO.File]::ReadAllLines($file);
$FileContains = $false;
foreach ($line in $Textfile.Split([System.Environment]::NewLine))
{
if($line.Contains($SearchText))
{
$FileContains = $true;
}
}
if ($FileContains)
{
Write-Host "Contains:" $file;
Write-Host $FileContains
}
}
Write-Host "Done";
I want a successful double loop, one for setting the $SearchText value to each of the cells in a column from an Excel Worksheet I have, one by one, then use that value to search through a loop of files in a given destination, which is the bit I already have code for.
I have two CSV files: File1.csv has one column with 4000+ rows. File2.csv has 200 columns with 10000+ rows of content. I want to add the one column in file1.csv as an additional column on File2.csv. I am OK adding it to the end (rightmost) of the existing file. I have found several options online, but none has worked as desire. I can get it done with the Input-CSV cmdlet and adding a Property but that is taking more than ~1 hour to execute. Is there any way to do this without having to convert the CSV content into PSobjects? I have used Get-Content and Set-Content in the past, but that will append one file to the bottom of the other one. Is there any way I could do something similar but appending to the right of the existing file?
Here is the piece of code that has gotten me closer to what I need. The problem with this one is Excel is not saving or closing. Any ideas on how this problem can be solved either by fixing the code below or an easier/more efficient way to do it?
$source = "C:\Users\Desktop\Script_Development\04-16-2015\Bit.csv"
$dest = "C:\Users\Desktop\Script_Development\04-16-2015\MergedwithHeader_04-16-2015.csv"
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $false
$Workbooksource = $excel.Workbooks.open($source)
$Worksheetsource = $Workbooksource.WorkSheets.item("Bit")
$Worksheetsource.activate()
$range = $Worksheetsource.Range("A1").EntireColumn
$range.Copy() | out-null
$Workbookdest = $excel.Workbooks.open($dest)
$Worksheetdest = $Workbookdest.Worksheets.item("MergedwithHeader_04-16-2015")
$Range = $Worksheetdest.Range("FT1")
$Worksheetdest.Paste($range)
$Workbookdest.SaveAs("C:\Users\Desktop\Script_Development\04-16-2015\MergedwithHeader_04-16-2015.xls")
$Excel.quit()
The following code will loop through the lines of a file. You could use this to read each line into an ArrayList.
$FileData = Get-Content "$Filename"
foreach ($i in $FileData)
{
DoSomethingWithLine($i)
}
Then you loop through the other file, and combine each line with a line that is stored in the ArrayList, concatenating it with the necessary commas and quotes, and append each line to a new file using Add-Content.
There would be numerous other and more sophisticated ways to do this.