Extracting attachments from SharePoint online using PowerShell - powershell

Currently I am trying to extract attachments from a list on SharePoint online. I found a code online that is supposed to do this but i get an error. The code that I found is a follows:
$webUrl = "https://mm.sharepoint.com/teams/pj-b0000"
$library = "Photos"
#Local Folder to dump files
$tempLocation = "C:\Users\C\Documents\temp"
$s = new-object Microsoft.SharePoint.SPSite($webUrl)
$w = $s.OpenWeb()
$l = $w.Lists[$library]
foreach ($listItem in $l.Items)
{
Write-Host " Content: " $listItem.ID
$destinationfolder = $tempLocation + "\" + $listItem.ID
if (!(Test-Path -path $destinationfolder))
{
$dest = New-Item $destinationfolder -type directory
}
foreach ($attachment in $listItem.Attachments)
{
$file = $w.GetFile($listItem.Attachments.UrlPrefix + $attachment)
$bytes = $file.OpenBinary()
$path = $destinationfolder + "\" + $attachment
Write "Saving $path"
$fs = new-object System.IO.FileStream($path, "OpenOrCreate")
$fs.Write($bytes, 0 , $bytes.Length)
$fs.Close()
}
}
but i get this error:
new-object : Cannot find type [Microsoft.SharePoint.SPSite]: verify that the assembly containing this type is loaded.
At C:\Users\C\Documents\SPListExtract.ps1:5 char:6
+ $s = new-object Microsoft.SharePoint.SPSite($webUrl)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
You cannot call a method on a null-valued expression.
At C:\Users\C\Documents\SPListExtract.ps1:6 char:1
+ $w = $s.OpenWeb()
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cannot index into a null array.
At C:\Users\C\Documents\SPListExtract.ps1:7 char:1
+ $l = $w.Lists[$library]
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
so i edited that code a bit but i only get the item in the list and not the attachments that are in the items. The code that i wrote is as follows:
Connect-PnPOnline -Url 'https://mm.sharepoint.com/teams/pj-b0000' -UseWebLogin
$tempLocation = "C:\Users\C\Documents\temp"
$list = Get-PnPListItem -List 'Photos'
foreach ($listItem in $list)
{
Write-Host " Content: " $listItem.ID
$destinationfolder = $tempLocation + "\" + $listItem.ID
if (!(Test-Path -path $destinationfolder))
{
$dest = New-Item $destinationfolder -type directory
}
foreach ($attachment in $listItem.Attachments)
{
$file = $w.GetFile($listItem.Attachments.UrlPrefix + $attachment)
$bytes = $file.OpenBinary()
$path = $destinationfolder + "\" + $attachment
Write "Saving $path"
$fs = new-object System.IO.FileStream($path, "OpenOrCreate")
$fs.Write($bytes, 0 , $bytes.Length)
$fs.Close()
}
}
I see my problem is the inside foreach loop for the $file variable I think. Would someone be able to help me with this?
Much thanks in advance.

The first line in your errors implies you do not have the assembly loaded:
new-object : Cannot find type [Microsoft.SharePoint.SPSite]: verify that the assembly containing this type is loaded.
These assemblies are only installed on a SharePoint server:
https://social.technet.microsoft.com/Forums/en-US/4a78ed2c-efde-40fa-800c-c4ecfa68a7c4/cannot-find-type-microsoftsharepointspsite-when-running-sharepoint-powerscript-in-a-windows-10?forum=sharepointdevelopment

Related

Cannot bind argument to parameter 'Path' because it is null. Parameter does not seem to be null at all

Checking if a file exists on a remote machine:
#Check if Dir exists on the machine we are copying from
$dir = ($APPROD001Root + $instance + "\" + $type + "\" + $year + "\" + $monthFormatted)
Write-Host $dir
if(Test-Path -Path $dir){
Write-Host ($dir + " exists!")
$files = Get-ChildItem -Path $dir
#Check if the Dir has files in it
if($files.Length -gt 0){
#Check if the folder exists on the machine we are copying towards, if not create it!
$dirReceivingMachine = ($DBStag01Root + $instance + "\" + $type + "\" + $year + "\" + $monthFormatted)
Write-Host $dirReceivingMachine
if($dirReceivingMachine -eq $null){
Write-Host "the path is null..."
}
$folderExists = Invoke-Command -ScriptBlock { Test-Path -Path $dirReceivingMachine } -Session $session
if(!$folderExists){
Write-Host ("folder " + $dirReceivingMachine + " does not yet exist we want to create it!")
#Invoke-Command - ScriptBlock { New-Item -Path $dirReceivingMachine -ItemType Directory } -Session $session
}
The invoke-command that sets the $folderExists always throws
Cannot bind argument to parameter 'Path' because it is null.
+ CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
the output I get in terminal is
D:MyData\2018\09
D:\MyData\2018\09 exists!
D:\MyData\2018\09 Cannot bind argument to
parameter 'Path' because it is null.
+ CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
As you can see the Write-Host "The path is null.." never fires, so the variable I am passing into Test-Path is not null yet PS says it is when invoking the command...
No idea why it does this

Uploading 2 files with same name to FTP using powershell script

I am a beginner at powershell script and I am stuck
I am trying to upload 2 xml files with the same name to FTP, but I am getting the following error
Exception calling "UploadFile" with "2" argument(s): "An
exception occurred during a WebClient request." At
C:\powershell\ExternalWidgets\upload-to-ftp.ps1:51 char:16
+ $webclient.UploadFile($uri.AbsoluteUri, $LocalPath)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException`
Here is the script:
#SET CREDENTIALS
$credentials = new-object System.Net.NetworkCredential($user, $pass)
cd $target
$DirectoryContent = Get-ChildItem -Directory
foreach($item in $DirectoryContent){
cd $item
$currentFolderItems = Get-ChildItem
foreach( $subfolderItem in $currentFolderItems)
{
if ($subfolderItem.name -eq "package.json") {
$subItem = Get-ChildItem -Directory
foreach($subItem in $subItem)
{
if ($subItem.name -eq "coverage") {
$files = Get-ChildItem -Path $subItem
$n = 0
foreach ($file in $files)
{
#rename coverage file
if($file.Name -eq "cobertura-coverage.xml") {
$newFileName=$file.Name.Replace("cobertura-coverage.xml","cobertura-coverage$n.xml")
Rename-Item $file -NewName $newFileName
$newFileName
}
$n++
}
}
}
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object
System.Net.NetworkCredential($user,$pass)
$uri = New-Object System.Uri($ftp + "/" + $folder)
#Delete files from FTP
# $fileUploaded =($uri + "\" + $newFileName)
# $fileUploaded
# Remove-Item $fileUploaded
$LocalPath =($target + "\" + $item + "\" + "coverage" + "\" +
$newFileName).Replace(".\", "").Replace('\', '/')
$webclient.UploadFile($uri, $LocalPath)
#cd..
}
}
cd ..
}
I also get an error when I want to rename one of the files. What step am I missing? Thank you

Moving files older than into subfolders

I'm trying to move old files into folders based on creation date. The setup is that the script should check a folder for files older than 5 years and then put them in folders sorted by year with subfolders for each month.
$SourceDir = "C:\Test"
$DestinationDir = "C:\Archive\Test\"
$limit = (Get-Date).AddYears(-5)
$files = Get-ChildItem $SourceDir * | Where-Object {
!$_.PSIsContainer -and $_.CreationTime -lt $limit
}
foreach ($file in $files) {
$Directory = $DestinationDir + "" + $file.CreationTime.Date.ToString('yyyy') + "\" + $file.CreationTime.Date.ToString('MM-MMM')
if (!(Test-Path $Directory)) {
New-Item $directory -Type Directory
}
Move-Item $file.FullName $Directory
I get this error
PS C:\Scripts> .\SortIntoMonths5Year.ps1
You cannot call a method on a null-valued expression.
At C:\Scripts\SortIntoMonths5Year.ps1:11 char:69
+ $Directory = $DestinationDir + "" + $file.CreationTime.Date.ToString <<<< ('yyyy') + "\" + $file.CreationTime.Date.ToString('MM-MMM')
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Test-Path : Cannot bind argument to parameter 'Path' because it is null.
At C:\Scripts\SortIntoMonths5Year.ps1:13 char:16
+ if (!(Test-Path <<<< $Directory))
+ CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
Move-Item : Cannot bind argument to parameter 'Path' because it is null.
At C:\Scripts\SortIntoMonths5Year.ps1:17 char:10
+ Move-Item <<<< $file.FullName $Directory
+ CategoryInfo : InvalidData: (:) [Move-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.MoveItemCommand
Fixed it myself
$SourceDir = "C:\Test"
$DestinationDir = "C:\Archive\Test\"
$files = get-childitem $SourceDir * | Where-Object {$_.LastWriteTime -lt (Get-Date).AddYears(-5)}
#$files = get-childitem $SourceDir *
foreach ($file in $files)
{
$Directory = $DestinationDir + "" + $file.LastWriteTime.Date.ToString('yyyy') + "\" + $file.LastWriteTime.Date.ToString('MM-MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
Move-Item $file.fullname $Directory
}

Creating a parameter script with PowerShell to be called by another script

I have a PowerShell script that works. For maintenance reasons I want to create another script where I'll put all the parameters that I'll call from my first script.
How can I create and call the parameter file?
Here is my script:
param([string] $dataSource = "server")
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
$Stamp1 = (Get-Date).toString("yyyy-MM-dd")
$Logfile = "E:\PowerShell\Log\file$stamp1.log"
$file = "file$stamp1.csv"
$extractFile = #"
E:\PowerShell\Output\$file
"#
[string]$sqlCommand1 =get-content -path E:\PowerShell\SQL\sql.sql
[string]$sqlCommand =$sqlCommand1
$authentication = ("User Id= user ;Password=pswd;" -f $plainCred.Username, $plainCred.Password)
Add-Type -assemblyname system.data
$factory = [System.Data.Common.DbProviderFactories]::GetFactory ("Teradata.Client.Provider")
$connection = $factory.CreateConnection()
$connection.ConnectionString = "Data Source = $dataSource;Connection Pooling Timeout=300;$authentication"
$connection.Open()
if ($connection.State -eq 'Open') {$logstring ="Connexion réussite"} else { $logstring ="echec Connexion" }
$command = $connection.CreateCommand()
$command.CommandText = $sqlCommand
$adapter = $factory.CreateDataAdapter()
$adapter.SelectCommand = $command
$dataset = new-object System.Data.DataSet
try
{
[void] $adapter.Fill($dataset)
$dataset.Tables | Select-Object -Expand Rows
}
finally
{
$connection.Close()
}
if (!$dataset) {$logstring1 ="extraction vide"} else {$logstring1 ="extraction réussite"}
($DataSet.Tables[0] | ConvertTo-Csv -delimiter ";" -NoTypeInformation ) -replace '"', "" | Out-File $extractFile -Force
$datafileExists = Test-Path $extractFile
if ($datafileExists)
{
$logstring2 ="Fichier data créé"
}
else
{
$logstring2 ="Fichier data non créé"
}
Add-content $Logfile -value ($Stamp+':'+$logstring)
Add-content $Logfile -value ($Stamp+':'+$logstring1)
Add-content $Logfile -value ($Stamp+':'+$logstring2)
I created a file of parameters
$Stamp1 = (Get-Date).toString("yyyy-MM-dd")
$Logfile = "E:\PowerShell\Log\file$stamp1.log"
$file = "file$stamp1.csv"
$extractFile = #"
E:\PowerShell\Output\$file
"#
$authentication = ("User Id= user ;Password=paswd;" -f $plainCred.Username, $plainCred.Password)
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
and I call it from my first script like that :
$ScriptPath = Split-Path $MyInvocation.InvocationName
& "$ScriptPath\param.ps1"
but my variables are not recognised, I have these errors:
Out-File : Cannot bind argument to parameter 'FilePath' because it is null.
At E:\PowerShell\script\Soft.ps1:59 char:104
+ ... "" | Out-File $extractFile -Force
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Out-File], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.OutFileCommand
Test-Path : Cannot bind argument to parameter 'Path' because it is null.
At E:\PowerShell\script\Soft.ps1:61 char:29
+ $datafileExists = Test-Path $extractFile
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
Add-Content : Cannot bind argument to parameter 'Path' because it is null.
At E:\PowerShell\script\Soft.ps1:78 char:14
+ Add-content $Logfile -value ($Stamp+':'+$logstring)
+ ~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Add-Content], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.AddContentCommand
Add-Content : Cannot bind argument to parameter 'Path' because it is null.
At E:\PowerShell\script\Soft.ps1:79 char:13
+ Add-content $Logfile -value ($Stamp+':'+$logstring1)
+ ~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Add-Content], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.AddContentCommand
Add-Content : Cannot bind argument to parameter 'Path' because it is null.
At E:\PowerShell\script\Soft.ps1:80 char:13
+ Add-content $Logfile -value ($Stamp+':'+$logstring2)
+ ~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Add-Content], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.AddContentCommand
IF you use '&' you execute the ps1 and the variables created are available within that scope. you can change the scope like this:
$test # default scope
$global:test # global scope
$script:test # script scope
The better solution is to use '.' in stead of '&' so you 're code from the ps1 is included in the other ps1.
so the scope is in the same because it is in the same script.

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()