I am trying to run the following Powershell script via the Task Scheduler but although it gives me a successful run (0x0), nothing happens. If I run the script manually from the same machine as a standard user the script executes without any issue.
$folderpath = "\\shared_path\excel.xls"
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
$xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlOpenXMLWorkbook
write-host $xlFixedFormat
$excel = New-Object -ComObject excel.application
$excel.visible = $false
$filetype ="*xls"
Get-ChildItem -Path $folderpath -Include $filetype -recurse |
ForEach-Object `
{
$path = ($_.fullname).substring(0, ($_.FullName).lastindexOf("."))
$workbook = $excel.workbooks.open($_.fullname)
$path += ".xlsx"
$excel.DisplayAlerts = $false;
$workbook.saveas($path, $xlFixedFormat)
$workbook.close()
}
$excel.Quit()
$excel = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
Just to clarify, I have tried different options in task scheduler such as running it under arguments like "-WindowStyle Hidden -NonInteractive -ExecutionPolicy Bypass -File "C:\Temp\powershell.ps1" or SYSTEM and currently logged on user but nothing made a difference.
My system is a domain joined Windows 10 with unrestricted access to the shared location (Everyone access)
Any ideas?
I usually configure Task Scheduler to run a PowerShell script with the following settings:
New Action
Action: "Start a program".
Program/script: "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
Add arguments (optional): .\ScriptName.ps1 -Arg1 Value1
Start in (optional): Path\to\Script\Directory
Related
I have a software that just allows me to download my data in xls files but I want to use it as an xlsx file.
Currently I have an excel macro when I click on a button it converts all my xls files in xlsx but I want to automate this task so I don't have to open the excel file and click on the button.
I was thinking of a script that start when I log in windows or something like that, and it converts automatically my xls file when I download it. But I'm not very good with scripts so anyone can help me with that ? It's on windows 7 and 10.
Thank you for your help.
Edit:
Here is my Powershell script, now I have to automate it so that it runs automatically when I download a new .xls file, I know I can use the task scheduler but how can I do that automation on en event like adding a new xls file to a folder ? Or maybe we can do it in powershell ?
My script:
$xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlOpenXMLWorkbook
write-host $xlFixedFormat
$excel = New-Object -ComObject excel.application
$excel.visible = $false
$folderpath = "C:\Users\Mgtspare\Downloads\"
$filetype ="*xls"
Get-ChildItem -Path $folderpath -Include $filetype -recurse |
ForEach-Object `
{
$path = ($_.fullname).substring(0, ($_.FullName).lastindexOf("."))
"Converting $path"
$workbook = $excel.workbooks.open($_.fullname)
$path += ".xlsx"
$workbook.saveas($path, $xlFixedFormat)
$workbook.close()
remove-item $_.fullname
}
$excel.Quit()
$excel = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
UPDATE:
I changed my script to have a new script faster and I put a watcher so I run the script when a new xls file is downloaded, I will use task manager to run this script when I log in windows so it can watch without doing anything.
Here is my new script:
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Users\Mgtspare\Downloads"
$watcher.Filter = "*.xls"
$watcher.IncludeSubdirectories = $false
$watcher.EnableRaisingEvents = $true
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = {
$watcher.Path *.xls | rename-item -newname { [io.path]::ChangeExtension($_.name, "xlsx") }
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher "Created" -Action $action
while ($true) {sleep 5}
Issue:
My script run in the ISE but when i want to run it in cmd or with the right click on my script file and run with with powershell I have this issue
You must provide a value expression on the right-hand side of the '*' operator.
The below script automatically runs each morning with Task Manager
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Users\Mgtspare\Downloads"
#$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = {
Get-ChildItem -Path C:\Users\Mgtspare\Downloads *.xls | rename-item -newname { [io.path]::ChangeExtension($_.name, "xlsx") }
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher 'Created' -SourceIdentifier 'FileCreated' -Action $action
while ($true) {sleep 1000}
I've written a code that tries to go through my company server and set all the excel files, under a certain folder, to shared so that multiple people can edit them at once. This has been a problem for a very long time here and I thought I had a nice code to fix this but I can't seem to access the property correctly. Can anyone help?
$ErrorActionPreference = "Stop"
$root = "P:\A N G"
$excelFiles = Get-ChildItem -path $root -File "*.xlsx" -Recurse
foreach ($excelFile in $excelFiles.FullName)
{
$excel = New-Object -ComObject Excel.Application
$excelWorkBook = $excel.Workbooks.Open($excelFile)
if (!$excelWorkBook.MultiUserEditing)
{
Write-Host $excelFile
$excelWorkBook._SaveAs([Microsoft.Office.Interop.Excel.XlSaveAsAccessMode]::xlShared)
$excelWorkBook.Close
}
}
With some help from a friend I managed to come up with a solution actually.
$ErrorActionPreference = "Stop"
$root = "P:\A N G"
$excelFiles = Get-ChildItem -path $root -File "*.xlsx" -Recurse
foreach ($excelFile in $excelFiles.FullName)
{
$excel = New-Object -ComObject Excel.Application
$excelWorkBook = $excel.Workbooks.Open($excelFile)
if (!$excelWorkBook.MultiUserEditing)
{
Write-Host $excelWorkBook.FullName
$accessMode = [Microsoft.Office.Interop.Excel.XlSaveAsAccessMode]::xlShared
$xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlWorkbookDefault
$excelWorkBook.SaveAs($excelWorkBook.FullName,$xlFixedFormat,$null,$null,$null,$null,$accessMode,$null,$null,$null,$null,$null)
$excelWorkBook.Close
}
}
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
I have some PowerShell scripts that invoke SQL commands, take the results and put them into a CSV file, then the CSV file is put into an excel workbook and it's emailed out to a distribution list. I had no issues running these reports through Windows Scheduled tasks on my older Windows 2008 server running SQL 2008. But I have migrated over to Windows 2016 running SQL 2016. Now when I run this process through Scheduled tasks I get the following error:
Unable to get the Open property of the Workbooks class
At C:\PowerShell\scrpits\ArtiReport3.ps1:607 char:1
+ $workbook = $excel.Workbooks.Open($csvFilePath)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
If I run the PowerShell script manually I have no issues and everything runs fine. I'm using the same login to run the scripts manually as I do through scheduled tasks. Here is the script.
$query = "*SQL Query runs here*"
#Edit these peramters for the server this will be running on#
$smtpServer = "*server*";
$smtpFrom = "I3Reports#server.com";
$smtpTo = "*email list here*”
$messageSubject = "I3 Report";
#create anonymus loging for sending e-mail#
$User = "anonymous";
$PWord = ConvertTo-SecureString -String "anonymous" -AsPlainText -Force
$Creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $pword
$date = (Get-Date).AddDays(-1).ToString('yyyy-MM-dd')
$date = $date+"_I3Report.xls";
$csvFilePath = "c:\Scripts\queryresults.csv"
$excelFilePath = "c:\scripts\$date"
$instanceName = "*server*"
Import-Module "sqlps"
$results = Invoke-Sqlcmd -QueryTimeout 7200 -Query $query -ServerInstance $instanceName
# Output to CSV
$results | export-csv $csvFilePath -Delimiter " " -NoTypeInformation
#this line will remove all the quotation marks from the csv file
(Get-Content $csvFilePath) | % {$_ -replace '"', ""} | out-file -FilePath $csvFilePath -Force
# Convert CSV file to Excel
$excel = New-Object -ComObject excel.application
$excel.visible = $False
$excel.displayalerts=$False
$workbook = $excel.Workbooks.Open($csvFilePath) #<-- Program fails here
$workSheet = $workbook.worksheets.Item(1)
#$workSheet.cells.item(3,3) = "HOPLA"
#for freezing pane#
$workSheet.application.activewindow.splitcolumn = 0
$workSheet.application.activewindow.splitrow = 1
$workSheet.Range("A2").application.activewindow.freezepanes = $true
$resize = $workSheet.UsedRange
$resize.EntireColumn.AutoFit() | Out-Null
$xlExcel8 = 43
$workbook.SaveAs($excelFilePath, $xlExcel8)
$workbook.Close()
$excel.quit()
$excel = $null
send-mailmessage -from $smtpFrom -to $smtpTo -subject "$messageSubject" -body "Attachment" -Attachments $excelFilePath -smtpServer $smtpServer -Credential $creds;
As mentioned this works when I run it in PowerShell manually, but through scheduled tasks it gets that error and it references the section I noted in the code. I've been working on this for days and I can't seem to figure out what is causing the issue. Any help or suggestions is welcomed. Thanks for taking the time.
I found the solution to this problem here
Powershell Excel Automation - Save/Open fails in Scheduled Task
Creating the folders and gaining access to the directories that they are in did it for me.
I am trying to create automatically a report out of an excel file. I already analyzed one specific file and the report is saved local.
Now I want to use this macro to run it on other files. Therefore I have to change the path in the powershell.
Now I want to run the macro automatically (let`s say at 1am) with powershell.
$excel = New-Object -comobject Excel.Application
$wbPersonalXLSB = $excel.workbooks.open("C:\Users\fami\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB")
$FilePath = "C:\Users\fami\Desktop\example.xls"
$workbook = $excel.Workbooks.Open($FilePath)
$excel.Visible = $false
$worksheet = $workbook.worksheets.item(1)
$excel.Run("PERSONAL.XLSB!run")
$wbPersonalXLSB.Close()
$workbook.save()
$workbook.close()
$excel.quit()
Only the $FilePath needs to be variable.
You just need to use a Parameter for the $FilePath variable instead of hard coding it. Like this:
param([string]$FilePath)
$excel = New-Object -comobject Excel.Application
$wbPersonalXLSB = $excel.workbooks.open("C:\Users\fami\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB")
$workbook = $excel.Workbooks.Open($FilePath)
$excel.Visible = $false
$worksheet = $workbook.worksheets.item(1)
$excel.Run("PERSONAL.XLSB!run")
$wbPersonalXLSB.Close()
$workbook.save()
$workbook.close()
$excel.quit()
Then you would schedule the script and specify the -FilePath paramater like so:
powershell.exe -file C:\folder\yourscript.ps1 -FilePath "C:\Users\fami\Desktop\example.xls"
EDIT: To read a list of files from a text file (with one file on each line) would be this.
param(
[string]$FileList,
[string]$PersonalXLSB="C:\Users\fami\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB",
[string]$RunMacro="PERSONAL.XLSB!run"
)
$Files = Get-Content $FileList
foreach ($FilePath in $Files) {
$excel = New-Object -comobject Excel.Application
$wbPersonalXLSB = $excel.workbooks.open($PersonalXLSB)
$workbook = $excel.Workbooks.Open($FilePath)
$excel.Visible = $false
$worksheet = $workbook.worksheets.item(1)
$excel.Run($RunMacro)
$wbPersonalXLSB.Close()
$workbook.save()
$workbook.close()
$excel.quit()
}
I've also moved the PersonalXLSB and Macro to Params, as they have a value set this will be used as default if you don't specify anything else. It's most basic form is like this:
powershell.exe -file C:\folder\yourscript.ps1 -FileList "C:\folder\name.text"
You can change the other params like this:
powershell.exe -file C:\folder\yourscript.ps1 -FileList "C:\folder\name.text" -RunMacro="PERSONAL.XLSB!macroname"
Using Powershell it's rather easy to call Excel macro's from a script, for example with a script like this:
$excel = new-object -comobject excel.application
$excelFiles = Get-ChildItem -Path C:\fso -Include *.xls, *.xlsm -Recurse
Foreach($file in $excelFiles)
{
$workbook = $excel.workbooks.open($file.fullname)
$worksheet = $workbook.worksheets.item(1)
$excel.Run("CreateChart")
$workbook.save()
$workbook.close()
}
$excel.quit()
However, I didn't manage to call a macro with some arguments. Is this possible or is the best way to write a config file that the macro will read when called?
You can run a macro with arguments like this:
$excel.Run('CreateChart', 'arg1', 'arg2', ...)