Azure Automation - Copy Files from one Sharepoint site to another - powershell

I would like to create a workflow that automatically copies files which were uploaded to a Sharepoint-Site onto another SharePoint-Site (for file exchange with customers). Therefore I created a Logic App that triggers a Runbook with following content:
param(
[Parameter (Mandatory = $true)][string]$FilePath,
[Parameter (Mandatory = $true)][string]$FileName
)
$Client = "C:\Modules\User\Microsoft.SharePoint.Client\Microsoft.SharePoint.Client.dll"
$ClientRT = "C:\Modules\User\Microsoft.SharePoint.Client\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path $Client
Add-Type -Path $ClientRT
Creds = Get-AutomationPSCredential -Name "SharepointCreds"
#Set parameter values
$TargetSiteURL="https://domain.SharePoint.com/sites/site1"
$SourceSiteURL="https://domain.Sharepoint.com/sites/site2"
#Set Source and Destination File URL
$SourceFileURL="/sites/Sitename1/$Filepath/$FileName"
$TargetFileURL="/sites/Sitename2/$Filepath/$FileName"
#Setup Credentials to connect
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Creds.UserName, $Creds.Password)
#Setup the contexts
$SourceCtx = New-Object Microsoft.SharePoint.Client.ClientContext($SourceSiteURL)
$SourceCtx.Credentials = $Credentials
$TargetCtx = New-Object Microsoft.SharePoint.Client.ClientContext($TargetSiteURL)
$TargetCtx.Credentials = $Credentials
#Get the Source File
$FileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($SourceCtx, $SourceFileURL)
#Copy File to the Target location
[Microsoft.SharePoint.Client.File]::SaveBinaryDirect($TargetCtx, $TargetFileURL, $FileInfo.Stream,$True)
Anyways I keep receiving following error: Cannot send a content-body with this verb-type
How can I resolve this issue? Is there a better approach?

In sharepoint, we could use the MoveCopyUtil Class to copy file between sites
For example:
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SourceSiteURL)
$Ctx.Credentials = $Credentials
#Copy the File
$MoveCopyOpt = New-Object Microsoft.SharePoint.Client.MoveCopyOptions
$Overwrite = $True
[Microsoft.SharePoint.Client.MoveCopyUtil]::CopyFile($Ctx, $SourceFileURL, $TargetFileURL, $Overwrite, $MoveCopyOpt)
$Ctx.ExecuteQuery()
Reference: https://www.sharepointdiary.com/2017/02/sharepoint-online-copy-file-between-document-libraries-using-powershell.html#ixzz7CSvEyjEc

Related

How to download two different files in powershell

I have this simple script that is working and I'm able to download a csv file From my SharePoint site but I'm just wondering how can I modify it so that I can download another file that is located in another path and save it in the same local folder as soon as the first one is complete downloading?.
Basically this is what I'm trying to do
Download this first
$SourceFile="/sites/msteams/ReportsFull/OneDrive.csv"
Download this second, save in the same folder with the first one
$SourceFile="/sites/msteams/Shared%20Documents/OneDriveInventory/ActiveLitHoldWithOneDrive.csv"
\#Set parameter values
$SiteURL="https://companyName.sharepoint.com"
$SourceFile="/sites/msteams/ReportsFull/OneDrive.csv"
$TargetFile="C:\\Users\\AS\\Downloads\\New folder\\LegalDoc.docx"
Function Download-FileFromLibrary()
{
param
(
\[Parameter(Mandatory=$true)\] \[string\] $SiteURL,
\[Parameter(Mandatory=$true)\] \[string\] $SourceFile,
\[Parameter(Mandatory=$true)\] \[string\] $TargetFile
)
Try {
#Setup Credentials to connect
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Global:adminUPN, $Global:adminPwd)
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Credentials
#sharepoint online powershell download file from library
$FileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($Ctx,$SourceFile)
$WriteStream = [System.IO.File]::Open($TargetFile,[System.IO.FileMode]::Create)
$FileInfo.Stream.CopyTo($WriteStream)
$WriteStream.Close()
Write-host -f Green "File '$SourceFile' Downloaded to '$TargetFile' Successfully!" $_.Exception.Message
}
Catch {
write-host -f Red "Error Downloading File!" $\_.Exception.Message
}
}
\#Call the function to download file
Download-FileFromLibrary -SiteURL $SiteURL -SourceFile $SourceFile -TargetFile $TargetFile
You've got the right code, just need to call the function twice
$sourceFile1 = '/sites/msteams/ReportsFull/OneDrive.csv'
$targetFile1 = 'C:\\Users\\AS\\Downloads\\New folder\\LegalDoc.docx'
Download-FileFromLibrary -SiteURL $SiteURL -SourceFile $SourceFile1 -TargetFile $TargetFile1
$sourceFile2 = '/sites/msteams/Shared%20Documents/OneDriveInventory/ActiveLitHoldWithOneDrive.csv'
$targetFile2 = 'C:\\Users\\AS\\Downloads\\New Folder\\NewFile2.docx'
Download-FileFromLibrary -SiteURL $siteUrl -SourceFile $sourceFile2 -TargetFile $targetFile2```

EWS powershell folder binding with EWSid : converted folderid doesn't match the EWSid when retrieving the folder

I'm trying to move items between non-wellknown folders to consolidate two hierarchy branches in an Exchange Online Archive mailbox. I've gotten the mailboxFolderStatistics, converted the FolderID (OWAid) to EWSid, and I'm trying to compare it to the list of EWSids retrieved when binding to the ArchiveMsgFolderRoot, and getting a list of all the folders. I'm finding that the converted FolderIDs are not the same as what's retrieved by the bind. I was trying to get the folder stats, convert the FolderID, and bind to the folders using those converted FolderIDs, but can't find the folders. I'm going to try to do this a different way at this point (Glen's FolderIdFromPath function), but I don't understand why the converted and retrieved EWSids are different.
This is how I'm converting the FolderIDs, and how I'm retrieving the folders. The same folder in the $FolderStats and $MailboxFolderList do not have the same ID.
# Function to convert the OWAid to EWSid
function ConvertId{
param (
$OwaId = "$( throw 'OWAId is a mandatory Parameter' )"
)
process{
$aiItem = New-Object Microsoft.Exchange.WebServices.Data.AlternateId
$aiItem.Mailbox = $Mailbox
$aiItem.UniqueId = $OwaId
$aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::OwaId
$convertedId = $service.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EwsId)
return $convertedId.UniqueId
}
} # function ConvertId END
# Mailbox to act against
$Mailbox = "UserA#domain.com"
# Import Web Services Module
Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
# Load the System.Web assembly
Add-Type -AssemblyName System.Web
# EWS service setup: Create the service object to access the Archive mailbox
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList Exchange2013_SP1
$service.Credentials = new-object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $Credential.UserName, $Credential.GetNetworkCredential().Password
$service.Url= new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx")
$service.TraceEnabled = $True
$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$Mailbox)
# Import the latest Archive mailbox folderstats
$FolderStats = Import-Csv "C:\MBstats_4-1-2019.csv" | select *, EWSid
# Convert the OWAid(mailboxFolderStatistics) to EWSid
foreach($FolderStat in $FolderStats)
{
$UrlEncodedId = [System.Web.HttpUtility]::UrlEncode($FolderStat.FolderId.ToString())
$FolderStat.EWSid = new-object Microsoft.Exchange.WebServices.Data.FolderId((Convertid $UrlEncodedId))
}
# Bind to the Archive mailbox root
$ArchiveMailboxRoot = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.Webservices.Data.WellKnownFolderName]::ArchiveMsgFolderRoot,$Mailbox)
$BindArchiveMailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$ArchiveMailboxRoot)
# Create search criteria
$FolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(10000)
$FolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep
# Get all Archive mailbox folders
$MailboxFolderList = $BindArchiveMailboxRoot.FindFolders($FolderView)
When you converting an Id from an Archive folder you need to set the IsArchive property to True on the AlternateId Object eg maybe do
# Function to convert the OWAid to EWSid
function ConvertArchiveId{
param (
$OwaId = "$( throw 'OWAId is a mandatory Parameter' )"
)
process{
$aiItem = New-Object Microsoft.Exchange.WebServices.Data.AlternateId
$aiItem.Mailbox = $Mailbox
$aiItem.UniqueId = $OwaId
$aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::OwaId
$aiItem.isArchive = $true
$convertedId = $service.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EwsId)
return $convertedId.UniqueId
}
} # function ConvertId END

powershell script to Check if a folder exist in SharePoint with CSOM

I have a powershell script which i got somewhere from the internet that creates a folder in SharePoint. It works as it can create a folder when i tested it but, i would like like to know how can i modify this script to check if the folder that i am creating does not exist yet? can someone please help?
function CreateFolder {
param
(
$SPSite,
$SiteUrl,
$FolderName,
$User,
$Password
)
$ErrorActionPreference = "Stop"
$DocLibName = "Documents"
$FullSPPath = $SPSite+ $SiteUrl
#Connect Office 365 SharePoint Online Site
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SPSite)
$Creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User,$Password)
$Context.Credentials = $Creds
$List = $Context.Web.Lists.GetByTitle($DocLibName)
$Context.Load($List)
#Get the List Root Folder
$ParentFolder=$Context.web.GetFolderByServerRelativeUrl($FullSPPath)
#Create New Folder
$Folder = $ParentFolder.Folders.Add($FolderName)
$ParentFolder.Context.Load($Folder)
$ParentFolder.Context.ExecuteQuery()
Write-host "New Folder Created Successfully!"
}
You can do pretty much the same as what you are doing to get the rootfolder. So if the new folder is called NewFolder in the root of your library it would look like:
$newFolder = $Context.Web.GetFolderByServerRelativeUrl("/sites/site/library/NewFolder")
$context.Load($newFolder)
$context.ExecuteQuery()
Now all you need to do is check the exists property on the Folder object:
if (!$newFolder.Exists) {
#do stuff here
}

Create Folder in DocLib of a Teamsite - Office 365 - Sharepoint Online

I want to create an example folder in a Document Library of a created Teamsite on Sharepoint Online using Powershell but am running into an error.
After I have created the Teamsite I use the following script:
#Retrieve list
$DocLibName = "Dokumente"
$FolderTitle = "Beispiel"
$List = $ctx.Web.Lists.GetByTitle($DocLibName)
$folder = $list.AddItem("", [Microsoft.SharePoint.SPFileSystemObjectType]::Folder)
$folder["Title"] = $FolderTitle
$folder.Update();
$ctx.Load($List)
$ctx.ExecuteQuery()
Error Message
The type [Microsoft.SharePoint.SPFileSystemObjectType] was not found : Make sure that the assembly that contains this type is loaded.
Line:79 Char:1
+ $ Folder = $ List.addItem ("" [Microsoft.SharePoint.SPFileSystemObjectType ] :: Folde ...
It is not possible to use an index to a null array.
Line:80 Char:1
+ $ Folder ["Title"] = $FolderTitle
It is not possible to call a method for an expression of the NULL .
Line:81 Char:1
+ $Folder.Update();
How can this be resolved?
You are getting this error since Microsoft.SharePoint.SPFileSystemObjectTypetype belongs to SharePoint Server Side API which is not compatible with Office 365.
Below is demonstrated how to create a folder in SharePoint Online site via PowerShell (utilizes SharePoint CSOM API)
Function Create-Folder()
{
Param(
[Parameter(Mandatory=$True)]
[Microsoft.SharePoint.Client.Folder]$ParentFolder,
[Parameter(Mandatory=$True)]
[String]$FolderName
)
$folder = $ParentFolder.Folders.Add($folderName)
$ParentFolder.Context.Load($folder)
$ParentFolder.Context.ExecuteQuery()
return $folder
}
Function Get-Context($Url,$Username,$Password){
$SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($url)
$ctx.Credentials = $credentials
return $ctx
}
Usage
$Url = "https://contoso.sharepoint.com/"
$UserName = "jdoe#contoso.onmicrosoft.com"
$Password = ""
$TargetFolderName = "Archive2016"
$ctx = Get-Context -Url $Url -Username $Username -Password $Password
$parentFolder = $ctx.Web.Lists.GetByTitle("Documents").RootFolder
$folder = Create-Folder -ParentFolder $parentFolder -FolderName $TargetFolderName
Write-Host "Folder [$TargetFolderName] has been created succesfully. Url: $($folder.ServerRelativeUrl)"
For creating a folder hierarchy the following script could be utilized:
Function Create-FolderHierarchy()
{
Param(
[Parameter(Mandatory=$True)]
[Microsoft.SharePoint.Client.Folder]$ParentFolder,
[Parameter(Mandatory=$True)]
[String]$FolderUrl
)
$folderNames = $FolderUrl.Trim().Split("/",[System.StringSplitOptions]::RemoveEmptyEntries)
$folderName = $folderNames[0]
$curFolder = $ParentFolder.Folders.Add($folderName)
$ParentFolder.Context.Load($curFolder)
$ParentFolder.Context.ExecuteQuery()
if ($folderNames.Length -gt 1)
{
$curFolderUrl = [System.String]::Join("/", $folderNames, 1, $folderNames.Length - 1)
return Create-FolderHierarchy -ParentFolder $curFolder -FolderUrl $curFolderUrl
}
return $curFolder
}
If you are interested in scenario for uploading files while preserving a folder structure, take a look at How to: Upload files into Office 365 via PowerShell post, it contains ready made script for that purpose.

Creating a directory on remote FTP using powershell

I"m able to put a file up to a remote FTP with a modified version of...
$File = "D:\Dev\somefilename.zip"
$ftp = "ftp://username:password#example.com/pub/incoming/somefilename.zip"
"ftp url: $ftp"
$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)
"Uploading $File..."
$webclient.UploadFile($uri, $File)
I'm running into the problem that I"m trying to upload a file to a directory that doesn't exist, the put fails. So I need to create the target directory first. GET-MEMBER doesn't seem to show any methods I can invoke to create a directory, only file operations.
I use function Create-FtpDirectory
function Create-FtpDirectory {
param(
[Parameter(Mandatory=$true)]
[string]
$sourceuri,
[Parameter(Mandatory=$true)]
[string]
$username,
[Parameter(Mandatory=$true)]
[string]
$password
)
if ($sourceUri -match '\\$|\\\w+$') { throw 'sourceuri should end with a file name' }
$ftprequest = [System.Net.FtpWebRequest]::Create($sourceuri);
$ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::MakeDirectory
$ftprequest.UseBinary = $true
$ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)
$response = $ftprequest.GetResponse();
Write-Host Upload File Complete, status $response.StatusDescription
$response.Close();
}
Taken from Ftp.psm1 where you can find also other functions for FTP.
To others: sorry for not following well known verb-noun pattern. ;)