XML File Mapping to get CSV Value then Open Excel using PowerShell - excel

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]

Related

Filter an Excel workbook on all the sheets with criteria on two columns, when the rows satisfy my criteria, copy the rows to a new excel workbook

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!

How to read values from Worksheet and check their existence in a .txt file

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.

Writing from Powershell to Excel: How to set the cell format for the value?

I am reading values from different Excel files, and composing a new one containing information from all the others. While doing that, Excel seems to automatically change '.' to a comma ','. How do I prevent that?
I am using Powershell ISE on Win10 and Office365. I tried reading and writing 'value2' and 'text' and writing those. I tried casting the value2 to string when I write it. This did not work. The variables in Powershell hold the correct values as strings. The moment I save the new Excel file, the correct format is gone.
Example: Value is "123.456". I can read it, the Powershell variable shows "123.456". I write it to Excel and open the Excel afterwards, it reads:
123,456 and interprets it as number instead of a text.
How I read the value
[...]
$tmp += ($worksheet.cells.item($intRow,$col).value2)
How I write the value (I tried "value", and "text" for both)
[...]
elseif($value -eq 6){
$sheet.Cells.item($intRow,$columncounter).value2 = ($tmp[$value]).ToString()
}
[...]
This is how I open the excel file for writing:
$objExcel=New-Object -ComObject Excel.Application
$objExcel.Visible=$false
$resultbook = $objExcel.Workbooks.Add()
$sheet = $resultbook.ActiveSheet
$sheet.Name = "Data"
This is how I save the excel file
$resultbook.SaveAs($name)
$resultbook.close()
Expected: Input == Output, example: 1234.5678 --> 1234.5678
Actual Result: Input != Output, example 1234.5678 --> 1234,5678
It works fine for all other strings, texts, numbers except those containing dots.
I presume there must be a way to specify the cell format in the target file, however I did not find any documentation on that.

Copying an entire column from one CSV file to another using Powershell

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.

Powershell Column Removal Script - SharePoint

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.

Resources