Powershell script errors first time but works on second attempt - powershell

I have a powershell script that searches for xls files and converts them to xlsx. Every time I run it for the first time I will get the error
Unable to find type [Microsoft.Office.Interop.Excel.XlFileFormat].
At C:\Users\wpauling\Documents\Quarter Report Scripts\convert.ps1:2 char:18
+ ... xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlOpen ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Microsoft.Offic...el.XlFileFormat:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
However the second time I run it everything works as expected, what is the problem I am going nuts. Here is my script
#Converts xls into xlsx
$xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlOpenXMLWorkbook
write-host $xlFixedFormat
$excel = New-Object -ComObject excel.application
$excel.visible = $false
$folderpath = "C:\Users\user1\Documents\Q4"
$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()

Start the script with the line
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
Hope that helps.
p.s. Much less descriptive of course, but you can also use the numeric enum value 51 for the variable and not use the Add-Type.
See: XlFileFormat enumeration

Related

Powershell - Saving downloaded file on network share

The PS1 needs to download an XML file from a remote HTTP server and save it on a network share.
Summary of the script is as follows
$timer = (Get-Date -Format yyyyMMdd_hhmmss)
$storageDir = "\\10.16.99.99\what\ever\Folder"
$filename1 = "John_" + "$timer.xml"
$webclient = New-Object System.Net.WebClient
$url1 = "http://whateverURL/John.xml"
$file1 = "$storageDir\$filename1"
$webclient.DownloadFile($url1,$file1)
$source = "\\10.16.99.99\what\ever\Folder"
$target = "\\10.16.99.99\what\ever\TargetFolder"
$files = get-childitem $source -Recurse
foreach ($file in $files){
if ($file.LastWriteTime -ge (get-date).AddMinutes(-10)){
$targetFile = $target + $file.FullName.SubString($source.Length)
New-Item -ItemType File -Path $targetFile -Force
Copy-Item $file.FullName -destination $targetFile
Start-Sleep -s 3
}
}
When I run the script, I get following error through PowerShell CMD
Exception calling "DownloadFile" with "2" argument(s): "An exception occurred during a WebClient
request."
At D:\StagisEE\GlobalListing\GL_download.ps1:318 char:3
+ $webclient.DownloadFile($url1,$file1)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
Therefore I added the following lines to see what the variables are that will be used in the webClient command
Write-Host $url1
Write-Host $file1
Which gave me the following, additional, results
http://whateverURL/John.xml
\\10.16.99.99\what\ever\Folder\John_20191224_103412.xml
My question is why that the webClient is failing while the variables seems to be ok?
Or is he struggling due to the network location?

Extract Data from .txt files and export it to a .csv file #powershell

I am a beginner in Powershell, and I need some help. Thanks in advance
Requirement:
Get files inside a folder by browsing with a Folderbrowser.
Get the data inside the different .txt files.
Paste it into a single sheet of a .csv table.
Add-Type -AssemblyName System.Windows.Forms
$FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
[void]$FolderBrowser.ShowDialog()
$Selection = $FolderBrowser.SelectedPath
$input = Get-ChildItem $Selection
$objects = ForEach($record in $data)
{
$props = #{}
foreach($input in $Selection)
{
$records +=Get-Content $data
$props.Add($records)
}
}
$AllFilesData = New-Object -TypeName PSObject -Property $props
$path = $Selection+"\"+"AllFilesTogether.csv"
$objects | Select-Object AllFilesData| Export-Csv -NoTypeInformation -Path $path
Error:
Get-Content : Cannot find path
'D:\users\F14897c\sd_conex_france_20170107002029.txt' because it does
not exist.
At line:14 char:15
+ $records +=Get-Content $data
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (D:\users\F14897...70107002029.txt:String) [Get-Content],
ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand Cannot
find an overload for "Add" and the argument count: "1".
At line:16
char:9
+ $props.Add($records)
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
A single-column CSV file is just a list of strings, so your script can be simplified immensely:
Add-Type -AssemblyName System.Windows.Forms
$FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
[void]$FolderBrowser.ShowDialog()
$Selection = $FolderBrowser.SelectedPath
Get-ChildItem $Selection -Filter *.txt |Get-Content |Out-File (Join-Path $Selection AllFilesTogether.csv)
You obviously aren't giving the whole code, as $data in the ForEach loop is never defined. Regardless, the reason why you are getting the errors is that you need to change:
$records +=Get-Content $data
to
$records +=Get-Content $data.FullName
Assuming that $data is the result of a Get-ChildItem.
Also, you are trying to add to a hash table with 1 argument, which isn't going to fly either. You will need to supply a key value pair. If you are only going to use one column, then declare an array with #() instead of a Hash table.

Convert Excel formats to pdf - Powershell

My question's about the error at saving file at this convert script:
https://github.com/idf/batch_dump/blob/master/office_convert.ps1
#Error
Exception when calling "InvokeMember" with "6" argument (s): "Object does not match destination type."
In the line: 28 character: 1
+ $workbook = $objExcel.Workbooks.PSBase.GetType().InvokeMember('Open', ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : TargetException
saving C:\Test\CD_FEV_1.pdf
You can not call a method on a null value expression.
In the line: 30 character: 1
+ $workbook.ExportAsFixedFormat($xlTypePDF, $filepath, $xlQualityStanda ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You can not call a method on a null value expression.
In the line: 31 character: 1
+ [void]$workbook.PSBase.GetType().InvokeMember('Close', [Reflection.Bi ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
As i haven't experience in powershell i don't understand the metod they call at script.
I'm still new to powershell myself, so can't answer specifically what was causing the error, however I think I found the solution. It seemed to be with only the Excel conversion. The Word and PPT conversions worked flawless. I've changed the code for that portion and it seems to be working now:
$folderpath = $(get-location)
Add-type -AssemblyName office
#Convert Word formats to pdf
$wdFormatPDF = 17
$word = New-Object -ComObject word.application
$word.visible = $false
$fileTypes = "*.docx","*doc"
$wordFiles = Get-ChildItem -path $folderpath -include $fileTypes -Recurse
foreach ($d in $wordFiles) {
$path = ($d.fullname).substring(0,($d.FullName).lastindexOf("."))
"Converting $path to pdf ..."
$doc = $word.documents.open($d.fullname)
$doc.saveas([ref] $path, [ref]$wdFormatPDF)
$doc.close()
}
$word.Quit()
#Convert Excel formats to pdf
$xlFixedFormat = "Microsoft.Office.Interop.Excel.xlFixedFormatType" -as [type]
$excelFiles = Get-ChildItem -Path $folderpath -include *.xls, *.xlsx -recurse
$objExcel = New-Object -ComObject excel.application
$objExcel.visible = $false
foreach($wb in $excelFiles)
{
$filepath = Join-Path -Path $folderpath -ChildPath ($wb.BaseName + ".pdf")
$workbook = $objExcel.workbooks.open($wb.fullname, 3)
$workbook.ActiveSheet.PageSetup.Orientation = 2
$objExcel.PrintCommunication = $false
$workbook.ActiveSheet.PageSetup.FitToPagesTall = $false
$workbook.ActiveSheet.PageSetup.FitToPagesWide = 1
$objExcel.PrintCommunication = $true
$workbook.Saved = $true
"saving $filepath"
$workbook.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $filepath)
$objExcel.Workbooks.close()
}
$objExcel.Quit()
#Convert Powerpoint formats to pdf
$ppFormatPDF = 2
$ppQualityStandard = 0
$p = new-object -comobject powerpoint.application
$p.visible = [Microsoft.Office.Core.MsoTriState]::msoTrue
$ppFiletypes = "*.pptx","*ppt"
$ppFiles = Get-ChildItem -path $folderpath -include $ppFiletypes -Recurse
foreach ($s in $ppFiles) {
$pppath = ($s.fullname).substring(0,($s.FullName).lastindexOf("."))
"Converting $pppath to pdf ..."
$ppt = $p.presentations.open($s.fullname)
$ppt.SavecopyAs($pppath, 32) # 32 is for PDF
$ppt.close()
}
$p.Quit()
$p = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()

Trying to upload files to subfolder in Sharepoint Online via Powershell

I am new to Powershell and I am trying to upload files from a local folder into Sharepoint online. I seem to get the files into the library, but not into the second subfolder where i want them.
Script so far:
#Specify tenant admin and site URL
$User = "admin#contoso.no"
$SiteURL = "https://contoso.sharepoint.com"
$Folder = "E:\LocalFolder"
$DocLibName = "Libraryname"
$FolderName = "Folder/SubFolder"
#Add references to SharePoint client assemblies and authenticate to Office 365 site – required for CSOM
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
$Password = "password" | ConvertTo-SecureString -AsPlainText -Force
#Bind to site collection
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User,$Password)
$Context.Credentials = $Creds
#Retrieve list
$List = $Context.Web.Lists.GetByTitle($DocLibName)
$Context.Load($List)
$Context.ExecuteQuery()
#Retrieve folder
$FolderToBindTo = $List.RootFolder.Folders
$Context.Load($FolderToBindTo)
$Context.ExecuteQuery()
$FolderToUpload = $FolderToBindTo | Where {$_.Name -eq $FolderName}
#Upload file
Foreach ($File in (dir $Folder -File))
{
$FileStream = New-Object IO.FileStream($File.FullName,[System.IO.FileMode]::Open)
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $File
$Upload = $FolderToUpload.Files.Add($FileCreationInfo)
$Context.Load($Upload)
$Context.ExecuteQuery()
}
If I use &FolderName = "Folder" the script runs fine. But what do i do to get the files into a subfolder? If I set a filepath as FolderName it does not work. I get the following errors:
You cannot call a method on a null-valued expression.
+ $Upload = $FolderToUpload.Files.Add($FileCreationInfo)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cannot find an overload for "Load" and the argument count: "1".
+ $Context.Load($Upload)
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
enter code here
Been stuck on this for days :(
The error You cannot call a method on a null-valued expression. occurs since the $FolderToUpload object is not getting initialized at line:
$FolderToUpload = $FolderToBindTo | Where {$_.Name -eq $FolderName}
when $FolderName object points to sub folder name
The point is that $List.RootFolder.Folders returns only a folders located one level beneath under list or library, hence sub folder could not be referenced this way.
Instead you could consider the following options to reference a sub folder to add a file.
Using FileCreationInformation.Url property
Use FileCreationInformation.Url property to specify the folder url for a uploaded file.
#Retrieve list
$List = $Context.Web.Lists.GetByTitle($DocLibName)
$Context.Load($List.RootFolder)
$Context.ExecuteQuery()
#Upload file(s)
Foreach ($File in (dir $Folder -File))
{
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.Content = [System.IO.File]::ReadAllBytes($File.FullName)
$FileCreationInfo.URL = $List.RootFolder.ServerRelativeUrl + "/" + $FolderName + "/" + $File.Name
$UploadFile = $List.RootFolder.Files.Add($FileCreationInfo)
$Context.Load($UploadFile)
$Context.ExecuteQuery()
}
Using Web.GetFolderByServerRelativeUrl method
Use Web.GetFolderByServerRelativeUrl method to retrieve a folder where file have to be uploaded:
#Retrieve list
$List = $Context.Web.Lists.GetByTitle($DocLibName)
$Context.Load($List.RootFolder)
$Context.ExecuteQuery()
$TargetFolder = $Context.Web.GetFolderByServerRelativeUrl($List.RootFolder.ServerRelativeUrl + "/" + $FolderName);
#Upload file(s)
Foreach ($File in (dir $Folder -File))
{
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.Content = [System.IO.File]::ReadAllBytes($File.FullName)
$FileCreationInfo.URL = $File.Name
$UploadFile = $TargetFolder.Files.Add($FileCreationInfo)
$Context.Load($UploadFile)
$Context.ExecuteQuery()
}
You can also use the Office 365 Import service to bulk upload files to sharepoint online instead of using CSOM scripts.
This uses the new Sharepoint API which provides much faster speeds without any throttling as it uses scalable azure infrastructure.
https://support.office.com/en-us/article/Use-network-upload-to-import-SharePoint-data-to-Office-365-ed4a43b7-c4e3-45c8-94c8-998153407b8a

Open zip files in nested directories fails with "unexpected token" error

I have a script that I am trying to get to sort through a directory and open all the zip files and store the text files all to one directory. Here is the code:
#Script to open zip files in tree
New-Item E:\Files -type directory
Get-ChildItem -Path E:\SNL_Insurance\* -Recurse -Exclude "*.md5"|
ForEach-Object {
$file = $_
write-host $file;
$destination = "E:\Files"
$shell = New-Object -com shell.application
$zip = $shell.NameSpace($file) |
foreach($item in $_.items()){
$shell.Namespace($destination).copyhere($item)
}
}
I think I almost have it, but keep getting this error (any elaboration on piping would be helpful):
Unexpected token 'in' in expression or statement.
At E:\Expand-ZIPFile.ps1:14 char:19
+ foreach($item in <<<< $_.items()){
+ CategoryInfo : ParserError: (in:String) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
EDIT:
Ahh... thanks for that distinction. I made your edits but after each of my "write-host" checks to see the file name I get the following error:
`You cannot call a method on a null-valued expression. At E:\Expand-ZIPFile.ps1:14 char:30 + foreach($item in $zip.items <<<< ()){ + CategoryInfo : InvalidOperation: (items:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
EDIT2: So the original code does copy files to a new directory but also copies the whole zip file over. I tried to add an if statement to only copy files that are .txt but the code just steps through each directory without copying anything. If you have any idea that would be appreciated as I have exhausted all my ideas. Here is the code:
new-Item E:\Files -type directory
Get-Childitem -path E:\SNL_Insurance\* -recurse -exclude "*.md5" |
Foreach-object {
$file = $_
write-host $file;
$destination = "E:\Files"
$shell = new-object -com shell.application
$zip = $shell.NameSpace($file.Fullname)
foreach($item in $zip.items()){
if ($item.Extension -eq ".txt") {
$shell.Namespace($destination).copyhere($item)
}
}
}
You're confusing foreach with ForEach-Object loops. The former neither read from nor do they write to pipelines. Also, $file is a FileInfo object, not a path. The NameSpace method expects a path string, so you need to use $file.FullName.
Replace
$zip = $shell.NameSpace($file) |
foreach($item in $_.items()){
$shell.Namespace($destination).copyhere($item)
}
with
$zip = $shell.NameSpace($file.FullName)
foreach($item in $zip.items()){
$shell.Namespace($destination).copyhere($item)
}