Refresh Excel dataset in SharePoint Online with PowerShell 403 error - excel

I have been attempting to implement a PowerShell script that will access an Excel workbook, check it out, refresh the dataset in the workbook and finally check it back in again.
I've combined this with a task in Windows Task Scheduler to run the script daily from a server with a user account that has access to the SharePoint Online site.
My issue is that the script will not run. When I view the Windows Event logs I can see it is getting a 403 error
The script was taken from the document found here document:
Link to download document
The the task gets the following script and the location of the Excel Workbook from arguments in the action config of the task (detailed in the document above)
try
{
# Creating the excel COM Object
$xl = New-Object -ComObject Excel.Application;
# Setting up Excel to run without UI and without alerts
$xl.DisplayAlerts = $false;
$xl.Visible = $false;
}
Catch
{
Write-EventLog -EventId "5001" -LogName "Application" -Message "Failed to start Excel" -Source "Application"
Exit
}
foreach ($i in $args)
{
write-host "handling $i"
try
{
# Allow update only if we can perform check out
If ($xl.workbooks.CanCheckOut($i))
{
# Opening the workbook, can be local path or SharePoint URL
$wb = $xl.workbooks.open($i);
# Perform the check out
$xl.workbooks.checkout($i)
# Calling the refresh
$wb.RefreshAll();
# Saving and closing the workbook
$wb.CheckInWithVersion();
# in case you are not using checkout/checkin perform a save and close
#$wb.Save();
#$wb.Close();
#Release Workbook
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb)
}
else
{
write-host "Check out failed for: $i"
Write-EventLog -EventId "5001" -LogName "Application" -Message "Workbook can't be checked out $i" -Source "Application"
}
}
catch
{
Write-EventLog -EventId "5001" -LogName "Application" -Message "Failed refreshing the workbook $i $_" -Source "Application"
}
}
#Quiting Excel
$xl.quit();
#Release Excel
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
Am I missing something here?
Thanks in advance and please let me know if more info is required.
EDIT: The script works if run manually from cmd with the correct arguments. Problem seems to be that Task Scheduler cannot access PowerShell.

So I got this working finally. Issue was that it wasn't running the script when the option 'User logged on or not' in the general settings of the task was selected. Worked fine when 'User logged on' was selected.
Here are the steps I had to take to get this to run properly.
First the script needed to run from the System32 folder (also specify that directory in the tasks "Start In" box. Also make sure that you are pointing to the 32-bit version of PowerShell since Excel won't work with 64-bit
And second, turns out there is a bug with Excel where you have to create a folder called “Desktop” in the \SysWOW64\config\systemprofile\ and \System32\config\systemprofile\ directories(both folders need to be created if running Excel 64-bit).
This is the final argument string I ended up using: C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe -nologo –noprofile -noninteractive -executionpolicy bypass path\to\script 'path\to\excelworkbook'

Related

Blazor WebAssembly Application fails to load due to integrity errors

We have developed a Blazor WebAssembly Application that has already gone into productive usage for a certain group of customers.
The Application works well in all Browsers with Standard Security settings. However, this morning I got a call from one of the customers, where the Application did not load at all in their Chrome Browser.
I saw the following Errors in the console:
Unknown error occurred while trying to verify integrity.
Failed to load resource: the server responded with a status of 403 (forbidden)
Failed to find a valid digest in the 'integrity' attribute for ressource '<somepath.dll>' with SHA-256 integrity <sha56>. the resource has been blocked
Now my question is, what could cause this? Is this a Browser Security setting, or another security setting e.g on server, in code etc.? How can I fix this?
Here's a picture of the errors mentioned above
The most likely reason why this is happening, is that some Antiviruses block the execution of downloaded .dll files. That's why it is working in some networks, but doesn't in some others.
What you can do, and what is also suggested as a Workaround by microsoft, is to rename all .dll to .bin - and also change the config json. it worked in my case.
I use the following PowerShell function for that:
Function Hide-BlazorDLL {
Param(
[string]$Path = (Get-Location).Path
)
<#
According to the following Links:
https://github.com/dotnet/aspnetcore/issues/19552
https://github.com/dotnet/aspnetcore/issues/5477#issuecomment-599148931
https://github.com/dotnet/aspnetcore/issues/21489
https://gist.github.com/Swimburger/774ca2b63bad4a16eb2fa23b47297e71
#>
# Test if path is correct and accessible
$WorkingDir = Join-Path $Path "_framework"
if (!(Test-Path $WorkingDir)) { Throw "Wrong path $Path. current location must be wwwroot folder of published application." }
# Get All Items
$AllItems = Get-ChildItem $WorkingDir -Recurse
$DLLs = $AllItems | Where-Object { $_.Name -like '*.dll*' }
$BINs = $AllItems | Where-Object { $_.Name -like '*.bin*' }
# End script if no .dll are found
if ($DLLs) {
# Delete all current .bin files
if ($BINs) {
Remove-item $BINs.FullName -Force
}
# Change .dll to .bin on files and config
$DLLs | Rename-item -NewName { $_.Name -replace ".dll\b",".bin" }
((Get-Content "$WorkingDir\blazor.boot.json" -Raw) -replace '.dll"','.bin"') | Set-Content "$WorkingDir\blazor.boot.json"
# Delete Compressed Blazor files
if (Test-Path "$WorkingDir\blazor.boot.json.gz") {
Remove-Item "$WorkingDir\blazor.boot.json.gz"
}
if (Test-Path "$WorkingDir\blazor.boot.json.br") {
Remove-Item "$WorkingDir\blazor.boot.json.br"
}
# Do the same for ServiceWorker, if it exists
$ServiceWorker = Get-Item "$Path\service-worker-assets.js" -ErrorAction SilentlyContinue
if ($ServiceWorker) {
((Get-Content $ServiceWorker.FullName -Raw) -replace '.dll"','.bin"') | Set-Content $ServiceWorker.FullName
Remove-Item ($ServiceWorker.FullName + ".gz")
Remove-Item ($ServiceWorker.FullName + ".br")
}
}
else {
Write-Host "There are no .dll Files to rename to .bin"
}
}
Basically you need to navigate to the wwwroot folder of your published application and run the function there. e.g:
PS D:\inetpub\wwwroot\<appname>\wwwroot> Hide-BlazorDLL
Solution for me was to delete the obj and the bin folder in both the client and the server project folder
This error for some reason kept happening for me when I tested my application in an anonymous browser window (Google Chrome).
Try using a normal browser window if you're getting integrity errors.
Also, if you're using Cloudflare CDN don't forget to "Purge Everything" in the cache.
We have experienced this issue using Cloudflare auto minify feature. That feature removes any comments from html, js and other files - which some of the blazor .js files seems to contain.
This means that the hash of the file contents no longer matches the hash found in blazor.boot.json -> an integrity issue will be thrown and stop the app from loading.
Disabling the auto minify feature fixed the issue.
Tech Stack:
.NET 6.0.11
I had a similar issue. In the local machine, it is working fine. But when it is deployed through GitHub Actions, I get integrity checks error. I got this issue for Blazor WebAssembly ASP.NET Core Hosted (WebAssemblyPrerendered) project. Here is the fix I followed.
Added the .gitattributes file to the solution root folder.
Added the below code at the end of the file.
# blazor dlls - treat all .dll files as binary
*.dll binary

Error when Running an Excel Macro from a Windows Service Application

I have created a Windows Service Application that does many things but a part of it is producing an error. My service runs a PowerShell script that opens an Excel document (I know Microsoft does not support this, but opening the Excel doc is actually not whats giving me an issue). I get the error below when I try to run a macro on it and I have no idea how to fix it.
Exception calling "Run" with "1" argument(s): "'C:\WINDOWS\system32\PERSONAL.XLSB' could not be found.
Check the spelling of the file name, and verify that the file location is correct.
If you are trying to open the file from your list of most recently used files,
make sure that the file has not been renamed, moved, or deleted."
At line:54 char:1
+ $excel.Run("PERSONAL.XLSB!MacroForSoftwareFeatureLicensesXLS")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I have applied other solutions already like adding a 'Desktop' folder to C:\Windows\System32\config\systemprofile and C:\Windows\SysWOW64\config\systemprofile. This worked for allowing me to open the excel doc.
I have tried putting the PERSONAL.XLSB file in the C:\WINDOWS\system32 folder but this does nothing. Similarly, I also tried putting the PERSONAL.XLSB file in C:\WINDOWS\sysWOW64 but this completely halts my service.
My PowerShell script is the following:
$myLocalXLS = "C:\Users\aUser\Desktop\aFolder\myLocalXLS.xls"
$excel = New-Object -ComObject excel.application
$excel.DisplayAlerts = $FALSE
$myXLSWorkbook = $excel.Workbooks.Open($mylocalXLS)
$excel.Run("PERSONAL.XLSB!MacroForMyLocalXLS")
$myXLSWorkbook.Save()
$excel.DisplayAlerts = $TRUE
$excel.Quit()
I think you actually have to open the PERSONAL.XLSB manually, e.g. something like this worked for me:
$myLocalXLS = "C:\Users\aUser\Desktop\aFolder\myLocalXLS.xls"
$myPersonalXLSB = "C:\Users\aUser\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB"
$excel = New-Object -ComObject excel.application
$excel.DisplayAlerts = $FALSE
$myXLSWorkbook = $excel.Workbooks.Open($mylocalXLS)
$myPersonalWorkbook = $excel.Workbooks.Open($myPersonalXLSB)
$excel.Run("PERSONAL.XLSB!MacroForMyLocalXLS")

"Upload of file '...' was successful, but error occurred while setting the permissions and/or timestamp" when using WinSCP .NET assembly in PowerShell

Exception calling "Check" with "0" argument(s): "Upload of file '2019-06-11.zip'
was successful, but error occurred while setting the permissions and/or
timestamp.
If the problem persists, turn off setting permissions or preserving timestamp.
Alternatively you can turn on 'Ignore permission errors' option.
Permission denied.
Error code: 3
Error message from server: This server does not support operations to modify
file attributes."
At line:12 char:84
+ $session.PutFiles("D:\Users\bin\*.zip", "/Outbox/").Check <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
I keep on getting above error file transferring file from Window Server to Linux. I got the same error when using the WinSCP GUI as well. I asked MFT team and they didn't any set permission. Below are my script for file transferring and some of intro version of software I'm using. Anything I missed out for my script or version of software is too old? I will have an update of server soon but have to wait another 2 yrs. This task will be set as scheduler to transfer file daily to MFT server.
Version of software:
Use .NET 4.0
Use PowerShell v2.0
Window Server 2008
Placed private.ppk, WinSCPNet.dll and WinSCP.exe at same folder
#Load WinSCP .NET assembly
Add-Type -Path "D:\Users\WinSCPnet.dll" -Verbose
$session = New-Object WinSCP.Session
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.Protocol = [WinSCP.Protocol]::Sftp
$sessionOptions.HostName = "[Linux server IP]"
$sessionOptions.UserName = "[username]"
$sessionOptions.PortNumber = "[linux port number]"
$sessionOptions.Password = ""
$sessionOptions.SshPrivateKeyPath = "D:\Users\bin.ppk"
$sessionOptions.SshHostKeyFingerprint = "ssh-rsa 2048 ....="
try {
# Open the WinSCP.Session object using the WinSCP.SessionOptions object.
$session.Open($sessionOptions)
# Upload
$session.PutFiles("D:\Users\bin\*.zip", "/Outbox/").Check()
} finally {
# Disconnect, clean up
$session.Dispose()
}
The error is documented here:
https://winscp.net/eng/docs/message_preserve_time_perm
Your server does not support updating timestamps of uploaded remote files. So you need to instruct WinSCP not to attempt it:
$transferOptions = New-Object WinSCP.TransferOptions
...
$transferOptions.PreserveTimestamp = $False
$session.PutFiles("D:\Users\bin\*.zip", "/Outbox/", $False, $transferOptions).Check()

SharePoint script fails when run as a Visual Studio post-deployment command

I have written a script that inserts some test data into a document library. I intend to use it as a post-deployment step in Visual Studio 2010, so that the library is not empty after a retract & deploy.
The relevant portions of the script are:
Install.ps1:
$scriptDirectory = Split-Path -Path $script:MyInvocation.MyCommand.Path -Parent
. "$scriptDirectory\Include.ps1"
$webUrl = "http://localhost/the_site_name"
$web = Get-SPWeb($webUrl)
...
Include.ps1:
function global:Get-SPSite($url)
{
return new-Object Microsoft.SharePoint.SPSite($url)
}
function global:Get-SPWeb($url,$site)
{
if($site -ne $null -and $url -ne $null){"Url OR Site can be given"; return}
#if SPSite is not given, we have to get it...
if($site -eq $null){
$site = Get-SPSite($url);
...
}
It works fine when run as follows from the command line, even immediately after a Visual Studio re-deploy:
powershell \source\ProjectFiles\TestData\Install.ps1
However, it does not work when I use the exact same command as a post-deployment command line in the SharePoint project's properties in Visual Studio:
Run Post-Deployment Command:
New-Object : Exception calling ".ctor" with "1" argument(s): "The Web applicati
on at http://localhost/the_site_name could not be found. Verify that you have t
yped the URL correctly. If the URL should be serving existing content, the syst
em administrator may need to add a new request URL mapping to the intended appl
ication."
At C:\source\ProjectFiles\TestData\Include.ps1:15 char:18
+ return new-Object <<<< Microsoft.SharePoint.SPSite($url)
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvoca
tionException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.Power
Shell.Commands.NewObjectCommand
Interestingly, I can reproduce the error on the command line if I run:
c:\windows\Syswow64\WindowsPowerShell\v1.0\powershell \source\ProjectFiles\TestData\Install.ps1
However, the post-deployment command fails even if I explicitly run \windows\System32\WindowsPowerShell\v1.0\powershell and \windows\Syswow64\WindowsPowerShell\v1.0\powershell.
Update: Solution found
I seem to be having a similar problem to the one discussed here:
http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/faa25866-330b-4e60-8eee-bd72dc9fa5be
I cannot access a 64-bit SharePoint API using 32-bit clients. Because Visual Studio is 32-bit, the post-deployment action will run in a 32-bit process and will fail. There is, however, a 64-bit MSBuild. If we let it run the PowerShell script, all is fine.
Wrap the script in an MSBuild file such as this:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Install" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Install">
<Exec Command="powershell .\Install" />
</Target>
</Project>
Then, set the post-deployment command line to:
%WinDir%\Microsoft.NET\Framework64\v4.0.30319\MSBuild $(SolutionDir)\ProjectFiles\TestData\Install.msbuild
Use
%WINDIR%\SysNative\WindowsPowerShell\v1.0\powershell.exe
It’s important that you use the virtual path of %WINDIR%\SysNative and not the actual
path of C:\Windows\System32. The reason for this is that Visual Studio 2010 is a 32-bit
application that needs to call the 64-bit version of powershell.exe to successfully load the
Microsoft.SharePoint.Powershell snap-in.
(c)"Inside Microsoft SharePoint 2010", Microsoft Press, Mar 2011
I had same situation, I needed the Post Deployment powershell script to create dummy data for lists on my local instance. I tried several other ways even using the MSBuild with the .msbuild file as suggested above, but i could not all the variables and had to hard code the file with path and url, this is not what i wanted.
I finally figured out a way to explicitly calling the 64-Bit powershell.exe
I know the 64-bit file has to be there on hard dirve. I know that WinSXS folder has all the files. So quick search for powershell.exe in C:\Windows\winsxs folder i got two files so i grabbed the path for one in amd64 folder.
This is what i have as command in post deployment option
C:\Windows\winsxs\amd64_microsoft-windows-powershell-exe_31bf3856ad364e35_6.1.7600.16385_none_c50af05b1be3aa2b\powershell.exe -command "&{$(ProjectDir)PowerShell\dataload.ps1 -xmlPath "$(ProjectDir)PowerShell\dataload.xml" -webUrl "$(SharePointSiteUrl)"}"
I hope this will help someone in future.
Visual Studio is a 32-bit application, so in 64-bit Windows it runs in a simulated 32-bit environment.
Strangely, the 32-bit environment is called "WoW64" (when 32-bit Windows did this for 16-bit apps, it was called "WoW16". The "WoW" part means "Windows on Windows".
It's similarly strange that "System32" didn't become "System64" with 64-bit Windows. The "32" is from the 16-bit -> 32-bit transition, to differentiate from "System". Whatever, that's legacy/compatibility for you.
In WoW64, everything looks like a 32-bit Windows.
For example, c:\windows\system32 just points to c:\windows\syswow64. 32-bit applications can't (easily) reach anything 64-bit.
It is possible to use PowerShell Remoting to get a 64-bit PowerShell session from a 32-bit environment.
PS>gci env:PROCESSOR_ARCH*
Name Value
---- -----
PROCESSOR_ARCHITECTURE x86
PROCESSOR_ARCHITEW6432 AMD64
PS>Invoke-Command -ConfigurationName Microsoft.PowerShell -ComputerName LOCALHOST { gci env:PROCESSOR_ARCH* }
Name Value PSComputerName
---- ----- --------------
PROCESSOR_ARCHITECTURE AMD64 localhost
I have success doing this as a post deployment command:
%comspec% /c powershell -File "c:\foo\bar.ps1"

Run powershell commands in C#

RunspaceConfiguration psConfig = RunspaceConfiguration.Create();
Runspace psRunspace = RunspaceFactory.CreateRunspace(psConfig);
psRunspace.Open();
using (Pipeline psPipeline = psRunspace.CreatePipeline())
{
// Define the command to be executed in this pipeline
Command command = new Command("Add-spsolution");
// Add a parameter to this command
command.Parameters.Add("literalpath", #"c:\project3.wsp");
// Add this command to the pipeline
psPipeline.Commands.Add(command);
// Invoke the cmdlet
try
{
Collection<PSObject> results = psPipeline.Invoke();
Label1.Text = "hi"+results.ToString();
// Process the results
}
catch (Exception exception)
{
Label1.Text = exception.ToString();// Process the exception here
}
}
It is throwing the exception:
System.Management.Automation.CommandNotFoundException: The term 'add-spsolution' is not recognized as the name of a cmdlet, function, script file, or operable program.
Any suggestions why?
Add this command first:
Add-PSSnapin Microsoft.SharePoint.Powershell -EA 0
You must use the import-module command to load the correct module for sharepoint. Use get-module to find available modules.
To do this programmatically, see my post on the subject:
http://www.nivot.org/2010/05/03/PowerShell20DeveloperEssentials1InitializingARunspaceWithAModule.aspx
-Oisin
I have this issue recently. In my case I was neither able to see the added solution nor able to add solution. So first I remove solution using below PowerShell Command:
(Get-SPSolution -Identity "YourSolution.wsp").Delete()
Then I was able to add my new code solution.
Also make sure you are runing "Add-SPSolution" command from Web Applications, which is running on IIS, and NOT with standard Visual Studio server (when you press F5).

Resources