Issue with Powershell Excel attempting to cast .csv Values - excel

At this point, I believe it may be a file I/O issue.
While utilizing a Powershell script invoking Excel methods to go through a .csv file from a website, powershell is attempting to cast placeholders for data that is too long for a cell "#######" instead of the date and time contained within the 'cell' (search engines may need 'pound sign' or 'hashtag' to reach this result).
Below is the offending portion of the script.
[DateTime]$S = $sheet.Cells.Item($rowS+$i,$colS).text
[DateTime]$G = $sheet.Cells.Item($rowG+$i,$colG).text
[DateTime]$A = $sheet.Cells.Item($rowA+$i,$colSWScan).text
The data should exist as MM/DD/YYYY HH:MM, but is being read by Powershell/PSExcelModule as #######, which is what is displayed with the Excel GUI when opening the file.
This is only a portion of what the entire script does. Any suggestions on how to resolve the error while maintaining usage of PSExcel-Module would be most helpful.
Stackoverflow seems to have an issue with me posting the verbose error message, and this is my first post. Let me know if that would be helfpul with troubleshooting.
Edit for comment #1:
# Create an instance of Excel.Application and Open Excel file
$objExcel = New-Object -ComObject Excel.Application
# Open the file
$workbook = $objExcel.Workbooks.Open($file)
# Activate the first worksheet
$sheet = $workbook.Worksheets.Item($sheetName)
$objExcel.Visible=$false
After getting my head out of 'Excelland', I realized it may be easier to re-write the script to utilize the .csv organization (the original imported file for the script was a .xlsx), but I am admittedly unfamiliar with .csv scripting. However, the original question still stands while I re-write the code as I may need to switch back to .xlsx imported documents. Thank you for the suggestion J E Carter II.
Answer:
$objExcel.Cells.EntireColumn.AutoFit()
Credit to J E Carter II

When you open an excel file as an object under windows, you're launching excel.
You might be able to add the following commands to your excel object handle to get the data to represent correctly.
$objExcel.Cells.Select
$objExcel.Cells.EntireColumn.AutoFit
Do this before getting values from cells. If that doesn't work, let me know and I can find some csv handling examples.
Those might work better on the $workbook object. I can't remember which is implicit when recording a macro (which is how I got those).
It's also possible you may need to precede those two lines with something like
$workbook.Sheets("sheetname").Select

Related

Matlab writematrix in Excel gives error: Name cannot be the same as built-in name

I want to copy an Excel file to a different path through Matlab and then write in it also using Matlab. Somehow I get the error: Name cannot be the same as built-in name.
As I want to write multiple times in the file, I don't want to solve this problem manuelly each time, I want the code to run through without me having to do something constantly.
Is there any way I can solve this problem all at once through code? Does this happen because I copy the Excel file first?
The code looks like this:
path_source_template1 = 'Blabla1\Template1.xlsx';
timestamp = datestr(now);
timestamp = strrep(timestamp, ':', '-');
timestamp = strrep(timestamp, ' ', '-');
path_output = fullfile('Blabla2\',timestamp);
mkdir(fullfile(path_output));
path_output_template1 = strcat(path_output,'\Template1.xlsx');
copyfile(path_source_template1,path_output_template1);
Then I want to write in the Template1.xlsx:
writematrix(test,path_output_template1,'Sheet','Test','Range','A1',UseExcel=true,AutoFitWidth=false);
Then I get this error:
enter image description here
The input to the writematrix file uses the name, value format, so in this line:
writematrix(test,path_output_template1,'Sheet','Test','Range','A1',UseExcel=true,AutoFitWidth=false);
you should have:
..., 'Sheet','Test','Range','A1','UseExcel', true,'AutoFitWidth', false);
Disclaimer: I haven't tested this, but I'm fairly certain this will fix your problem.
The correct call to the writematrix would be:
writematrix(test,path_output_template1, 'Sheet','Test','Range','A1', 'UseExcel', true,'AutoFitWidth',false);
When writing datetime data to a spreadsheet file, you must set both 'PreserveFormat' and the 'UseExcel' Name-Value pair to true to preserve the existing cell formatting. You can check the documentation writematrix.
In order to answer to the error I tested the code locally in Matlab 2019b and works well setting the test variable in this example way: test = magic(5);.
Maybe the error could be in the data that you use in test variable or in that if you run the code iteratively very fast the path_output could exist, One way to improve this could be with a more accurate timestamp.

How to have Autohotkey write metadata, then extract that metadata for use in renaming the file

I'm automating a process with Autohotkey where I'm renaming old.xlsx to document_archived_on_%Timestring, then renaming current.xlsx to old.xlsx, then renaming newest_document.xlsx to current.xlsx.
That part was straightforward and works fine.
I want to add a metadata comment to newest_document.xlsx that says "data_as_of_%Timestring%". Later, I want to rename old.xlsx to "document_%metadata%.xlsx.
The simple, working script below:
; Take newest report, rename it to current. Take Current Report and move it to Old
; Take oldest report and archive it.
; Archive old report
FormatTime, Timestring, , yyyyMMdd
FileMove, G:\TPO_Project_DB\Old Data\old.xlsx, G:\TPO_Project_DB\Old Data\Eng_const_rpt_data_as_of_%Timestring%.xlsx
; Rename and move "current.xlsx" to "old.xlsx"
FileMove, G:\TPO_Project_DB\Current Data\current.xlsx, G:\TPO_Project_DB\Old Data\old.xlsx
; Rename and move newest report to current
FileMove, C:\TPOReports\Combined_eng_const_*, G:\TPO_Project_DB\Current Data\current.xlsx
I was able to find a lot of information about reading the meta properties, but regarding writing to these..., well, I didn't find much. I didn't find a full solution, that is, examples of working code, but there may be at least two ways to do this.
Firstly, here are some reference links for reading the meta properties. If the links become dead, searching for "FGP - FileGetProperties" should yield similar results.
How to Access a file's metadata
[Function] FGP - FileGetProperties
One method of writing to Excel's meta properties is to use COM. This likely isn't preferred as it would involve opening the file, writing the property, then saving - which may also be slow. For example, the code below (writes to the "Comments" meta property) took 4.2s to execute - though, only 0.4s after the Excel instance was created - so you may want to create the application object once until you've changed all the Excel file you need.
f1::
sFilePath := A_Desktop . "\test.xls"
oExcel := ComObjCreate( "Excel.Application" )
oExcel.Workbooks.Open( sFilePath )
oExcel.ActiveWorkbook.BuiltinDocumentProperties( "Comments" ).Value := "Test text"
oExcel.ActiveWorkbook.Save
oExcel.Quit
Return
The other method involves using DSOFile.dll which can be found here, https://support.microsoft.com/en-us/help/224351/the-dsofile-dll-files-lets-you-edit-office-document-properties-when-yo
I know nothing about this or how to use it, but it was designed for manipulating Office products' properties and is likely much quicker than opening each file as shown in my code snippet above. Additionally, it might also not change the "Date modified" value.

matlab error when using xlsread in a loop

I'm trying to read multiple csv files, in a loop, and then perform some analysis on all o them.
I'm using MatlabR2015b and Excel 2016.
the problem is that at the second call to xlsread I get the following error:
>>xlsread('R:\Experiments\ResoFreq_vis_BEH\TapFlick_vis_BEH\Data\s01_rr\1_fingerTapping_s01_rr.csv')
Error using xlsread (line 251)
No explanation no message, nothing.
after some debugging I've found it fails at the following command:
Excel.workbooks.Open(filename, 0, readOnly);
in the openExcelWorkbook.m file which is somewhere down the stack of xlsread.
I found very few people with the same problem and their solution was to force the EXCEL32 process to close using the following code:
[~, computer] = system('hostname');
[~, user] = system('whoami');
[~, alltask] = system(['tasklist /S ', computer, ' /U ', user]);
excelPID = regexp(alltask, 'EXCEL.EXE\s*(\d+)\s', 'tokens')
for i = 1 : length(excelPID)
killPID = cell2mat(excelPID{i});
system(['taskkill /f /pid ', killPID]);
end
However, this does not work for me.
after somemore digging I tried to manually look at the csv im trying to open, while debugging, meaning after stopping at the breakpoint at the Excel.workbooks.Open call, I used:
actxserver('Excel.Application')
ans.Workbooks.Open(filename)
which gave me the following error:
Error using Interface.000208DB_0000_0000_C000_000000000046/Open
Which is associated to Workbooks when looking at the excel process through the matlab inspector.
That is all the information I've managed to find related to my problem.
the only thing that works for me at the moment is running xlsread, then manually closing the excel process from the task manager, then running it again, until I have all my data, and then analyze, which is not a possible considering the amount of files I need to load.
I cannot use csvread as my files have mixed types, and every other function i've tried does not read the csvs properly
(I have a field which looks like this "[,...,]" and that field keeps getting interpreted as multiple rows in every function except with xlsread)
and thus I feel like I have no option but to fix xlsread somehow.
I would gladly provide anymore information that is necessary to solve this
thanks.
you should use csvread instead of xlsread, becuase xlsread just read .xls and .xlsx files.

Why is perl saving two copies of Excel spreadsheet?

This is similar to A copy of Excel Addin is created in My Documents after saving, except that I'm working with Perl instead of VBA, and xls files instead of xlsm, and the negative impact of the behavior is different.
I've inherited a Perl script (Perl 5.8.8) that is running on Windows 2003 Server as SYSTEM. After copying an Excel 2003 template file to a unique, fully defined path location, it opens the unique file in Excel using OLE, edits the file, saves the file, and closes the file. What results is the edited file being saved both in the correct, fully-defined path location, and also in the Default User profile's Documents folder.
This causes thousands of these files to accumulate on the C: drive, as every new admin to be hired gets a copy in his Documents folder.
Adding the code that sets the value of $OUT:
if (!$db->Sql("EXEC GetDetails 'name'"))
{
while ($db->FetchRow()>0)
{
#DataIn = $db->Data();
$name = $DataIn[0];
$IN = $DataIn[1];
$OUT = $DataIn[2];
opendir(DIR,"$OUT") || die "$OUT directory does not exist $!\n";
#... loop of proprietary code
#...
#Completed = $db1->Data();
#...
&formatExcelReport #The code that I previously posted
#...
# more proprietary code
# end of loop
} #end of while
}#end of if
The code I originally posted:
# Initialize Excel object
eval {Win32::OLE->new('Excel.Application', 'Quit')};
eval {$Excel = Win32::OLE->GetActiveObject('Excel.Application')};
unless (defined $Excel)
{
$Excel = Win32::OLE->GetActiveObject('Excel.Application')
|| Win32::OLE->new('Excel.Application', 'Quit');
}
$infiles = "Report_Template.xls";
$infiles = $OUT."/".$infiles;
$db6->Sql("EXEC FormatResults '".$Completed[0]."','".$Completed[1]."'");
$row = 2;
$fileName = $Completed[0]."_".$Completed[1];
$uniquefile = $fileName.$printdate.".xls";
# $OUT is a fully defined path on the E: drive
$reportfile = "$OUT"."\\".$uniquefile;
copy($infiles,$reportfile);
$Book = $Excel->Workbooks->Open("$reportfile");
$sheetnum = 1;
my $Sheet = $Book->Worksheets($sheetnum);
# Set Headers
$Header = $Sheet->PageSetup->{'CenterHeader'};
$Header = $Header." Results Test Code: ".$Completed[0]." Worksheet: ".$Completed[1]." Date: ".$headerdate;
$Sheet->PageSetup->{'CenterHeader'}= $Header;
# More file editing
# ...
$Book->Save();
$Book->Close(0);
Win32::OLE->new('Excel.Application', 'Quit');
Is the root of this problem the Save() command? Should I be using SaveAs() instead?
Any other feedback about how Excel is being used welcome, as well.
Thanks!
I don't see what causes this behavior, but here are a few things to try.
The template and the file it is copied to have names
$infiles = $OUT."/".$infiles;
$reportfile = "$OUT"."\\".$uniquefile;
Use the same separator.
Try to suppress some possible setting dictating that another copy be made. Perhaphs
$Excel->Application->{CreateBackup} = 0;
However, this may not be the correct property -- search the VB or Excel documentation for properties that may result in Excel saving an extra copy. (It needn't be "backup".)
Try to create a new file and use SaveAs, as a test to see whether you get two files again. The template copying may be setting it off to Save an extra copy (even though I don't see how). I'd say it's either that, or some general setting that need be turned off.
The rest is the original post, about using SaveAs, whereby I thought that a new file is created
You would use SaveAs to write a new file. See saveas in MSDN library
Saves changes to the workbook in a different file.
Using the save method may result in saving two files fro some reason, as noted in the answer by Borodin. This page also advises to use SaveAs for a new file
The first time you save a workbook, use the SaveAs method to specify a name for the file.
Once you change to using SaveAs there should be a confirmation dialog to deal with. If you want to suppress that you can set a property, with one (or either?) of
$Excel->Application->{DisplayAlerts} = 0;
# or
$Excel->{DisplayAlerts} = 0;
For a number of options, including backups for example, see the Chapter on OLE automation in PERL in a Nutshell.
A note on some other resources. There is a cookbook of sorts in this post on perlmonks. A listing of various operations is given in this SO post.
Finally, I don't know how deep the reasons for using OLE are but if it is only about writing some Excel files there are other modules. For example the very well regarded Spreadsheet::WriteExcel and Excel-Writer-XLSX.
That's very strange Perl code. eval without checking $# afterwards is just wrong -- you need to know if a step of your code has failed for the following steps to make sense
It looks like the problem is in your call to copy($infiles, $reportfile). That will save one copy of the file, while $Book->Save and $Book->Close will save another

Not using colnames when reading .xls files with RODBC

I have another puzzling problem.
I need to read .xls files with RODBC. Basically I need a matrix of all the cells in one sheet, and then use greps and strsplits etc to get the data out. As each sheet contains multiple tables in different order, and some text fields with other options inbetween, I need something that functions like readLines(), but then for excel sheets. I believe RODBC the best way to do that.
The core of my code is following function :
.read.info.default <- function(file,sheet){
fc <- odbcConnectExcel(file) # file connection
tryCatch({
x <- sqlFetch(fc,
sqtable=sheet,
as.is=TRUE,
colnames=FALSE,
rownames=FALSE
)
},
error = function(e) {stop(e)},
finally=close(fc)
)
return(x)
}
Yet, whatever I tried, it always takes the first row of the mentioned sheet as the variable names of the returned data frame. No clue how to get that solved. According to the documentation, colnames=FALSE should prevent that.
I'd like to avoid the xlsReadWrite package. Edit : and the gdata package. Client doesn't have Perl on the system and won't install it.
Edit:
I gave up and went with read.xls() from the xlsReadWrite package. Apart from the name problem, it turned out RODBC can't really read cells with special signs like slashes. A date in the format "dd/mm/yyyy" just gave NA.
Looking at the source code of sqlFetch, sqlQuery and sqlGetResults, I realized the problem is more than likely in the drivers. Somehow the first line of the sheet is seen as some column feature instead of an ordinary cell. So instead of colnames, they're equivalent to DB field names. And that's an option you can't set...
Can you use the Perl-based solution in the gdata instead? That happens to be portable too...

Resources