try catch block inside nested foreach loop - powershell

I will upload file under folder onTeams with PowerShell. I am using some try/catch block inside if/else statement. How can we improve my script? Or what do you recommend? I want to know is whether there is any way to make this code run better. I'm new to Powershell, so I don't know what looks like bad code or good code.
Let's say, I've run my script in November 2022. It will create a folder called 2022-10 under "/sites/Team/Shared Documents/General/Documents/2022"
Or I've run my script in February 2023. Firstly, it will create called 2023 mail folder for new year under "/sites/Team/Shared Documents/General/Documents/ Then it will create folder called 2023-01 under "/sites/Team/Shared Documents/General/Documents/2023"
And so on.
My script:
#Config Variables
$SiteURL = "https://company.sharepoint.com/sites/Team"
$SourceFilePath ="C:\Documents\report.csv"
$DestinationFolderPath = "/sites/Team/Shared Documents/General/Documents" #Server Relative URL
Try {
#Connect to PnP Online
Connect-PnPOnline -Url $SiteURL -ClientId "47bf0ca0-1d8a-xxxx-xxx-xxxx" -Tenant 'tenant.onmicrosoft.com' -Thumbprint <Thumbprint>
}
catch {
write-host "Error: $($_.Exception.Message)" -foregroundcolor Red
}
$year= get-date -Format yyyy
$FolderURL = $DestinationFolderPath + "/" + $year
#Try to Get the Folder
$Folder = Get-PnPFolder -Url $FolderURL -ErrorAction SilentlyContinue
#sharepoint online powershell To check if folder exists
If($Folder -ne $null)
{
Write-Host -f Green "Folder exists!"
Try{
$d = (get-date).AddMonths(-1).ToString("yyyy-M")
$FolderPATHLastMonth = $DestinationFolderPath + "/" + $year
Add-PnPFolder -Name $d -Folder $FolderPATHLastMonth
$DestinationFolderPath = $FolderPATHLastMonth + "/" + $d
Add-PnPFile -Path $SourceFilePath -Folder $DestinationFolderPath -ErrorAction Stop
}
catch{
echo $_.Exception
}
}
Else
{
Write-Host -f Yellow "Folder does not exists!"
Try{
Add-PnPFolder -Name $year -Folder $DestinationFolderPath
$d2 = (get-date).AddMonths(-1).ToString("yyyy-M")
$FolderPATHLastMonth = $DestinationFolderPath + "/" + $year
Add-PnPFolder -Name $d2 -Folder $FolderPATHLastMonth
$DestinationFolderPath = $FolderPATHLastMonth + "/" + $d2
Add-PnPFile -Path $SourceFilePath -Folder $DestinationFolderPath -ErrorAction Stop
}
catch{
echo $_.Exception
}
}

Related

Powershell - When watching folder for new file created - if statement inside "Register-ObjectEvent" is not firing

Goal: File watcher watches the staging folder for new files. If the new file name contains "JDE_Reimb" then move the file into another folder "$reimb_jde_path" ,also renaming the new file.
Issue: The If statement is not firing me at all. Up to creating the $fullpath works, but my If statement is not executing. Any ideas why? Also I need to watch this folder for 2 other file which contain specific string in the file name. What is the best way to accomplish this in one script?
$reimbFile = "JDE_Reimb"
$reimb_jde_path = "\\rootfolder\reimbfolder"
$staging_folder_path = "\\rootfolder\stagingfolder\" #"
$filter = "*.txt"
$watcherCRExport_Staging = New-Object IO.FileSystemWatcher $staging_folder_path, $filter -Property #{
IncludeSubdirectories = $false
}
Register-ObjectEvent $watcherCRExport_Staging Created -SourceIdentifier foldertest -Action {
$text = $eventArgs.Name
Write-Host $text# Write-Host $eventArgs.ChangeType
$fullpath = Join-Path -Path $staging_file_path -ChildPath $text# Write-Host "Full path is: $fullpath"
If($text.Contains($reimbFile)) {
$newtext = $text.Substring(0, $text.IndexOf("_") + 1 + $text.Substring($text.IndexOf("_") + 1).IndexOf("_"))# Write-Host "Created: $($newtext)"
$newfilename = $newtext + ".txt"
$nextpath = Join-Path -Path $reimb_jde_path -ChildPath $newtext
Copy-Item-Path $fullpath -Destination $nextpath
Write-Host "---------------------------------"
Write-Host $newfilename
Write-Host $fullpath
Write-Host $nextpath
Write-Host "Reimbursement Done copying"
Write-Host "---------------------------------"
}
Else {
Write-Host "No Match!"
}
}

Uploading bulk files from local system to SharePoint online using PowerShell script throwing an error you cannot call null valued expression

My requirement is to upload multiple files using PowerShell script to SharePoint online.
while uploading files to a folder in the SharePoint document library, it showing me this error.
I am extracting only file name before uploading and create a folder with that filename and want to upload the file in that particular folder using PowerShell script .
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
### Variables for Processing
$WebUrl = "https://tanviteddu.sharepoint.com/sites/Powershell/"
$LibraryName ="Documents"
$ListURL="/sites/Powershell/Shared Documents/Reports"
$SourceFolder="C:\Hari Priya"
#Setup Credentials to connect
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName,(ConvertTo-SecureString $Password -AsPlainText -Force))
#Set up the context
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$Context.Credentials = $Credentials
#Get the Library
$Library = $Context.Web.Lists.GetByTitle($LibraryName)
#upload each file from the directory
Foreach ($File in (dir $SourceFolder -File))
{
$fn=(Split-path -Path $file -Leaf).Split(".")[0];
Try
{
#Set up the context
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
$Context.Credentials = $credentials
#Get the List Root Folder
$ParentFolder=$Context.web.GetFolderByServerRelativeUrl($ListURL)
#sharepoint online powershell create folder
$Folder = $ParentFolder.Folders.Add($fn)
$ParentFolder.Context.ExecuteQuery()
Write-host "New Folder Created Successfully!" -ForegroundColor Green
}
catch
{
write-host "Error: $($_.Exception.Message)" -foregroundcolor Red
}
#Get the file from disk
$FileStream = ([System.IO.FileInfo] (Get-Item $File.FullName)).OpenRead()
$FinalUrl=$ListURL+"\"+$fn+"\"+$file
#Upload the File to SharePoint Library
$FileCreationInfo = New-Object
Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $File
$FileUploaded = $FinalUrl.RootFolder.Files.Add($FileCreationInfo)
#powershell to upload files to sharepoint online
$Context.Load($FileUploaded)
$Context.ExecuteQuery()
#Close file stream
$FileStream.Close()
write-host "File: $($File) has been uploaded!"
}
While uploading, it is showing the error as below:
You cannot call a method on a null-valued expression.
At line:26 char:5
+ $FileUploaded = $FinalUrl.RootFolder.Files.Add($FileCreationInfo)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeExceptio
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cannot find an overload for "Load" and the argument count: "1".
At line:28 char:5
+ $Context.Load($FileUploaded)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Please help me out
The below is working code - upload files from local drive to SharePoint online using PowerShell CSOM:
#Load SharePoint CSOM Assemblies
#Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
#Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
cls
$fileName = "File_Uploading_Report"
#'yyyyMMddhhmm yyyyMMdd
$enddate = (Get-Date).tostring("yyyyMMddhhmmss")
#$filename = $enddate + '_VMReport.doc'
$logFileName = $fileName +"_"+ $enddate+"_Log.txt"
$invocation = (Get-Variable MyInvocation).Value
$directoryPath = Split-Path $invocation.MyCommand.Path
$directoryPathForLog=$directoryPath+"\"+"LogFiles"
if(!(Test-Path -path $directoryPathForLog))
{
New-Item -ItemType directory -Path $directoryPathForLog
#Write-Host "Please Provide Proper Log Path" -ForegroundColor Red
}
#$logPath = $directoryPath + "\" + $logFileName
$logPath = $directoryPathForLog + "\" + $logFileName
$isLogFileCreated = $False
#DLL location
$directoryPathForDLL=$directoryPath+"\"+"Dependency Files"
if(!(Test-Path -path $directoryPathForDLL))
{
New-Item -ItemType directory -Path $directoryPathForDLL
#Write-Host "Please Provide Proper Log Path" -ForegroundColor Red
}
#DLL location
$clientDLL=$directoryPathForDLL+"\"+"Microsoft.SharePoint.Client.dll"
$clientDLLRuntime=$directoryPathForDLL+"\"+"Microsoft.SharePoint.Client.dll"
Add-Type -Path $clientDLL
Add-Type -Path $clientDLLRuntime
#Files to upload location
$directoryPathForFileToUploadLocation=$directoryPath+"\"+"Files To Upload"
if(!(Test-Path -path $directoryPathForFileToUploadLocation))
{
New-Item -ItemType directory -Path $directoryPathForFileToUploadLocation
#Write-Host "Please Provide Proper Log Path" -ForegroundColor Red
}
#Files to upload location ends here.
function Write-Log([string]$logMsg)
{
if(!$isLogFileCreated){
Write-Host "Creating Log File..."
if(!(Test-Path -path $directoryPath))
{
Write-Host "Please Provide Proper Log Path" -ForegroundColor Red
}
else
{
$script:isLogFileCreated = $True
Write-Host "Log File ($logFileName) Created..."
[string]$logMessage = [System.String]::Format("[$(Get-Date)] - {0}", $logMsg)
Add-Content -Path $logPath -Value $logMessage
}
}
else
{
[string]$logMessage = [System.String]::Format("[$(Get-Date)] - {0}", $logMsg)
Add-Content -Path $logPath -Value $logMessage
}
}
#The below function will upload the file from local directory to SharePoint Online library.
Function FileUploadToSPOnlineLibrary()
{
param
(
[Parameter(Mandatory=$true)] [string] $SPOSiteURL,
[Parameter(Mandatory=$true)] [string] $SourceFilePath,
[Parameter(Mandatory=$true)] [string] $File,
[Parameter(Mandatory=$true)] [string] $TargetLibrary,
[Parameter(Mandatory=$true)] [string] $UserName,
[Parameter(Mandatory=$true)] [string] $Password
)
Try
{
$securePassword= $Password | ConvertTo-SecureString -AsPlainText -Force
#Setup the Context
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SPOSiteURL)
$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $securePassword)
$list = $ctx.Web.Lists.GetByTitle($TargetLibrary)
$ctx.Load($list)
$ctx.ExecuteQuery()
$tarGetFilePath=$siteURL+"/"+"$TargetLibrary"+"/"+$File
$fileOpenStream = New-Object IO.FileStream($SourceFilePath, [System.IO.FileMode]::Open)
$fileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$fileCreationInfo.Overwrite = $true
$fileCreationInfo.ContentStream = $fileOpenStream
$fileCreationInfo.URL = $File
$uploadFileInfo = $list.RootFolder.Files.Add($FileCreationInfo)
$ctx.Load($uploadFileInfo)
$ctx.ExecuteQuery()
Write-host -f Green "File '$SourceFilePath' has been uploaded to '$tarGetFilePath' successfully!"
}
Catch
{
$ErrorMessage = $_.Exception.Message +"in uploading File!: " +$tarGetFilePath
Write-Host $ErrorMessage -BackgroundColor Red
Write-Log $ErrorMessage
}
}
#Variables
$siteURL="https://globalsharepoint.sharepoint.com/sites/TestSite/"
$listName="TestDocumentLibrary"
$fromDate="2019-10-28"
$toDate="2019-11-09"
$filesFolderLoaction=$directoryPathForFileToUploadLocation;
$userName = "YourSPOAccount#YourTenantDomain.com"
$password = "YourPassWord"
$securePassword= $password | ConvertTo-SecureString -AsPlainText -Force
#Variables ends here.
$filesCollectionInSourceDirectory=Get-ChildItem $filesFolderLoaction -File
$uploadItemCount=1;
#Extract the each file item from the folder.
ForEach($oneFile in $filesCollectionInSourceDirectory)
{
try
{
FileUploadToSPOnlineLibrary -SPOSiteURL $siteURL -SourceFilePath $oneFile.FullName -File $oneFile -TargetLibrary $listName -UserName $UserName -Password $Password
$fileUploadingMessage=$uploadItemCount.ToString()+": "+$oneFile.Name;
Write-Host $fileUploadingMessage -BackgroundColor DarkGreen
Write-Log $fileUploadingMessage
$uploadItemCount++
}
catch
{
$ErrorMessage = $_.Exception.Message +"in: " +$oneFile.Name
Write-Host $ErrorMessage -BackgroundColor Red
Write-Log $ErrorMessage
}
}
Write-Host "========================================================================"
Write-Host "Total number of files uploaded: " $filesCollectionInSourceDirectory.Count
Write-Host "========================================================================"
Reference URL:
https://global-sharepoint.com/powershell/upload-files-to-sharepoint-online-document-library-using-powershell-csom/

How to run powershell cmdlets one after the other

I have a sharepoint 2010 list designed with custom solution. It has 3 level folder hierarchy. In the last folder level multiple documents are present as attachments. I want to get all the document attachments from that folder and store it in my local drive, so that it can be migrated to a different platform.
Number of Attachments are around 350000.
My Tasks are:
Creating Folder in my drive.
Getting Attachment ids and create folder with id name, as inputs from a txt file.
Map network drive
Copy attachment from network drive to local folder.
Delete network drive.
These 5 steps are to be repeated for around 350000 attachments.
Kindly let me know if cmdlets can be executed properly one after the other.
$idsFile = "H:\D\Temp\testingid.txt"
$FileStore = "H:\D\Temp\Attachments"
foreach ($line in Get-Content $idsFile) {
$FileCount = 1
$thisappid = $line.Split("`t")
Write-Host $thisappid.GetValue(0)
$FPath = $FileStore + '/' + $thisappid.GetValue(1)
Write-Host $FPath
if (!(Test-Path $FPath)) {
Write-Host "Creating folder.."
$F1 = New-Item -Path $FileStore -Name $thisappid.GetValue(1) -ItemType "directory"
Write-Host $F1
$F2 = New-Item -Path $F1 -Name $thisappid.GetValue(0) -ItemType "directory"
} else {
Write-Host "Folder" $thisappid.GetValue(1) "Already exists"
$SPath = $FileStore + '/' + $thisappid.GetValue(1) + '/' + $thisappid.GetValue(0)
Write-Host $SPath
if (!(Test-Path $SPath)) {
$F2 = New-Item -Path $SPath -Name $thisappid.GetValue(0) -ItemType "directory"
Write-Host $F2
} else {
Write-Host "Folder" $thisappid.GetValue(0) "already exists"
Write-Host "Move to Next.."
}
}
Write-Host $thisappid.GetValue(0)
$id = $thisappid.GetValue(0) -as [int]
Write-Host $id
Write-Host $id.GetType()
net use Y: \\domainName/sites/SiteName/Lists/MyList/Attachments/$id
/Persistent:Yes
Start-Sleep -s 10
$name = Get-ChildItem -Path Y:\ -Name
Start-Sleep -s 10
Copy-Item -Path Y:\$name -Destination $dest
Start-Sleep -s 10
net use Y: /delete /y
Start-Sleep -s 10
$FileCount = $FileCount+1
Write-Host $FileCount
}

Upload multiple files from multiple folders to SharePoint online using Powershell

Fairly new to both SharePoint online and Powershell and thought this would be a pretty simple task, but I'm reaching out for help.
I have a client who has photos stored in multiple folders in a file share and they want to move this to SharePoint. They want to use the folder name of where the file exits as metadata to make searching easier.
This is the script I am using and not having much luck.
$connection = Connect-PnPOnline https://somecompany.sharepoint.com -Credentials $me -ReturnConnection
$files = Get-ChildItem "F:\some data" -Recurse
foreach ($file in $files)
{Add-PnPFile -Path $file.FullName -Folder Photos -Values #{"Title" = $file.Name;} -Connection $connection}
Issue I am having, is that this does not recurse the folders and comes back with " Local file not found"
If I can get that working, I can move onto getting the current folder name as a variable into metadata.
I'm pretty sure that this will be a simple task for experts, but alas that I am not.Any help will be greatly appreciated.
Thanks
Jassen
This seems to work for me, so will answer this. Happy for comments if there is an easier way or cleaner and also if anyone knows how to go 1 more layer deeper.
$connection = Connect-PnPOnline https://somecompany.sharepoint.com -Credentials $me -ReturnConnection
$LocalFolders = get-childitem -path "c:\test" | where-object {$_.Psiscontainer} | select-object FullName
foreach ($folder in $localfolders) {
$files = get-childitem -Path $folder.FullName -Recurse
foreach ($file in $files) {
$value1 = $file.Directory.Name
Add-PnPFile -Path $file.FullName -Folder Photos -Values #{"Title" = $file.Name;"SubCat" = $value1;} -Connection $connection
}
}
You could try below script, you need install pnp powershell.
function UploadDocuments(){
Param(
[ValidateScript({If(Test-Path $_){$true}else{Throw "Invalid path given: $_"}})]
$LocalFolderLocation,
[String]
$siteUrl,
[String]
$documentLibraryName
)
Process{
$path = $LocalFolderLocation.TrimEnd('\')
Write-Host "Provided Site :"$siteUrl -ForegroundColor Green
Write-Host "Provided Path :"$path -ForegroundColor Green
Write-Host "Provided Document Library name :"$documentLibraryName -ForegroundColor Green
try{
$credentials = Get-Credential
Connect-PnPOnline -Url $siteUrl -CreateDrive -Credentials $credentials
$file = Get-ChildItem -Path $LocalFolderLocation -Recurse
$i = 0;
Write-Host "Uploading documents to Site.." -ForegroundColor Cyan
(dir $path -Recurse) | %{
try{
$i++
if($_.GetType().Name -eq "FileInfo"){
$SPFolderName = $documentLibraryName + $_.DirectoryName.Substring($path.Length);
$status = "Uploading Files :'" + $_.Name + "' to Location :" + $SPFolderName
Write-Progress -activity "Uploading Documents.." -status $status -PercentComplete (($i / $file.length) * 100)
$te = Add-PnPFile -Path $_.FullName -Folder $SPFolderName
}
}
catch{
}
}
}
catch{
Write-Host $_.Exception.Message -ForegroundColor Red
}
}
}
UploadDocuments -LocalFolderLocation C:\Lee\Share -siteUrl https://tenant.sharepoint.com/sites/Developer -documentLibraryName MyDOc4

"A device attached to the system is not functioning " error when using robocopy to move folder in sharepoint

We are using Sharepoint 2010. There is a requirement to archive folders/Subfolders from a given folder to Archive folder which is part of document library. So we used Robocopy from powershell environment. But we're getting error "A device attached to the system is not functioning". ERROR 31 (0x0000001F) Changing File Attributes
Can any one help me what I have to do fix the above error.
Here is my code
$sourceDir = "\\labserver\sites\XXX\YYY Accounts Documents"
$targetDir = "\\labserver\sites\XXXX\Archived YYY Accounts Documents"
$FilePath = "C:\InactiveAccount_SharepointFolder.xlsx"
$sourceDir1= "\\labserver\sites\xxx\yyy Accounts Documents"
$SheetName = "Sheet1"
# Create an Object Excel.Application using Com interface
$objExcel = New-Object -ComObject Excel.Application
# Disable the 'visible' property so the document won't open in excel
$objExcel.Visible = $false
# Open the Excel file and save it in $WorkBook
$WorkBook = $objExcel.Workbooks.Open($FilePath)
$strSheetName = "sheet1"
# Load the WorkSheet 'BuildSpecs'
if ($strSheetName -eq "")
{
$worksheet = $WorkBook.sheets.item(1)
}
else
{
$worksheet = $WorkBook.sheets.item($strSheetName)
}
try {
$intRowMax = ($worksheet.UsedRange.Rows).count
for($intRow = 2 ; $intRow -le $intRowMax ; $intRow++)
{
$isFodlerExists = $worksheet.cells.item($intRow,3).value2
if($isFodlerExists -match "Yes")
{
$accountName = $worksheet.cells.item($intRow,1).value2
#[system.io.directory]::CreateDirectory($tempSource + $accountName)
#write-host $accountName
$sFolder = $sourceDir + "\" + $accountName
$sFolder1 = $sourceDir1 + "\" + $accountName
write-host $sFolder
$tFolder = $targetDir
Add-Content -Path $ErrorLog -Value $sFolder
if((Test-path -Path $sFolder1) -eq $TRUE)
{
try {
#Copy-Item -Path $sFolder -Destination $tFolder -Recurse -force
robocopy $sFolder $tFolder /e /r:2 /log:$ErrorLog /tee
}
Catch {
Add-Content -Path $ErrorLog -Value "Exception write"
$DateTime = (Get-Date).ToShortDateString() + " " + (Get-Date).ToShortTimeString()
$Target = $_.TargetObject
$e = $_
Add-Content -Path $ErrorLog -Value "$DateTime - $e $Target"
#Write-Host "$e $Target"
$ErrorActionPreference = "Continue"
}
if($?)
{
add-content -path $ErrorLog -value ($?)
}
else
{
add-content -path $ErrorLog -value ($?)
}
}
}
#write-host $accountName
}
}
Catch {
Add-Content -Path $ErrorLog -Value "Exception write"
$DateTime = (Get-Date).ToShortDateString() + " " + (Get-Date).ToShortTimeString()
$Target = $_.TargetObject
$e = $_
Add-Content -Path $ErrorLog -force -Value "$DateTime - $e $Target"
#Write-Host "$e $Target"
$ErrorActionPreference = "Continue"
}
$WorkBook.close()
$objExcel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($objExcel)
Can any one help me what I have to do fix the above error.