Issue

While using the older version of the OneDrive for Business sync client we ran into an issue where metadata was not maintained when documents were synced to the cloud (this has been fixed with the newer versions of ODFB client). This article may be a bit dated, however, if you want to change the metadata of documents stored in SharePoint Online, lucky you, because the steps are outlined in this blog post.

Update: Now that the new version of the ODFB client maintains the metadata for date created when syncing a file to the cloud, this script is not needed for the issue listed above.

Credit for Code

To give credit where credit is due, I used the code from the following location.

http://blog.blksthl.com/2015/02/24/office-365-guide-series-manage-files-and-folders-with-powershell-and-csom

Solution

By adding a simple foreach command to the script, removing some of the code, and calling information from a CSV file, I could update the create date in SharePoint Online for multiple files.

Create a directory under C:\Temp\CreateDate and C:\Temp\CreateDate\Log

Create a CSV file named Users.CSV under C:\Temp\CreateDate with the following information:

UPN Date File
User1@domain.com 1/1/2017 12:00 document.docx
User1@domain.com 1/1/2017 12:00 document2.docx
  • UPN – User’s UPN
  • Date – Date you want to change the Created Date to
  • File – The file path and name of the file you want to change

Note: Make sure you load the script into PowerShell ISE. The code changes you need to make will be based on the line number within the script.

Change line 4 to your admin URL

Change line 5 to your My Site URL

Change line 8 to the administrator account


Lines 92 & 93 are used to convert the UPN to match the UPN used within SharePoint Online.

Converts User1@domain.com to user1_domain_com

Line 95 converts spaces to %20 (example Doc 1 to Doc%201)

So, a couple important notes so far:

  • Updating the creation date does not change the person associated with the file
  • Folders with spaces or special characters will require HTML variables ‘ ‘ =  %20
  • A new version of the file is created when you change the date
  • The file’s recently changed date is updated to reflected when the script was executed

Results

I updated the User.csv file.

Notice the version (10.0) and created date (1/15/2015) for New-Document.docx. Also the modified time was 23 minutes ago.

After the script has completed running, the modified time will be updated since it is a new version.

The version has been update, 11.0, and created date has changed to, 1/8/2015.

Even though the document is a new version, the content of the document is the same and accessible from Word.

Log file information:

Once the MetaData has been updated,  eDiscovery searches can be performed on the updated date created time.

Script


$PasswordFile = "C:\temp\CreateDate\cred.txt"
$path = "c:\temp\CreateDate\users.csv"
$AdminURI = ""
$URL1 = ""
$URL3 = "/personal/"
$URL4 = "/Documents/"
$SPOUser = ""


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"

#Function to create the log file
function log
{
	param (
		[String]$text,
		[Switch]$fout
	)
	ac $logfile $text
	if ($showConsoleOutput)
	{
		if ($fout)
		{
			Write-Host $text -ForegroundColor Red
		}
		else
		{
			Write-Host $text -ForegroundColor Green
		}
	}
}
log -text "-----$(Get-Date) Services - $($env:USERNAME) on $($env:COMPUTERNAME) starting-----"


#Check if a log file is created or prompt the administrator for the password
$PasswordFileCheck = Test-Path $PasswordFile
If ($PasswordFileCheck -eq $False)
{
	Read-Host -Prompt "<text>" -AsSecureString | ConvertFrom-SecureString | Out-File "C:\temp\CreateDate\cred.txt"
	log -text "Created a password file under C:\temp\CreateDate"
}
Else
{
	log -text "Password file already created under C:\temp\CreateDate"
}

# Connect to Office 365 services
$Pass = Get-Content $PasswordFile | ConvertTo-SecureString
$Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $SPOUser, $Pass

#Connect to Azure AD
Import-Module MSOnline
$Connect = Connect-MsolService -Credential $cred -ErrorAction SilentlyContinue -ErrorVariable ProcessError
If ($ProcessError)
{
	log -text "------ Didn't Connect to Office 365 services"
}
Else
{
	log -text "Connected to Office 365 Services"
}

# Connect to SharePoint Online
$cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($SPOUser, $Pass) -ErrorAction SilentlyContinue -ErrorVariable ProcessError1
If ($ProcessError1)
{
	log -text "------ Didn't Connect to SharePoint Online services"
}
Else
{
	log -text "Connected to SharePoint Online Services"
}

# Add the path of the User Profile Service to the SPO admin URL, then create a new webservice proxy to access it
$proxyaddr = "$AdminURI/_vti_bin/UserProfileService.asmx?wsdl"
$UserProfileService = New-WebServiceProxy -Uri $proxyaddr -UseDefaultCredential False
log -text "Profile Service ------ $UserProfileService"
$UserProfileService.Credentials = $cred

# Set variables for authentication cookies
$strAuthCookie = $cred.GetAuthenticationCookie($AdminURI)
$uri = New-Object System.Uri($AdminURI)
$container = New-Object System.Net.CookieContainer
$container.SetCookies($uri, $strAuthCookie)
$UserProfileService.CookieContainer = $container

$loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
$loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")



$User = Import-csv -path $path
Foreach ($Users in $User)
{
	
	$File = $users.File
	$ItemCreated = $users.Date
	$UPN = $Users.UPN
	
	$UPN1 = ($upn).Replace("@", "_")
	$URL2 = ($UPN1).Replace(".", "_")
	
	$File = ($File).Replace(" ", "%20")
	
	
	$SPOODfBUrl = "$URL1$URL2"
	$FileRelativeUrl = "$URL3$URL2$URL4$File"
	log -text "File being updated ------ $FileRelativeUrl"
	$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SPOODfBUrl)
	#$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($SPOUser,$Pass)
	$Context.RequestTimeout = 16384000
	$Context.Credentials = $Cred
	$Context.ExecuteQuery()
	$Web = $Context.Web
	$Context.Load($Web)
	$Context.ExecuteQuery()
	$SPODocLibName = "Documents"
	$SPOList = $Web.Lists.GetByTitle($SPODocLibName)
	$Context.Load($SPOList.RootFolder)
	$Context.ExecuteQuery()
	
	
	$FolderRelativeUrl = $SPOList.RootFolder.ServerRelativeUrl
	$FileName = $LocalFile.Name
	$FileUrl = $FolderRelativeUrl + "/" + $FileName
	#[Microsoft.SharePoint.Client.File]::SaveBinaryDirect($Web.Context, $fileUrl, $LocalFile.OpenRead(), $true)
	$SPOFolder = $SPOList.RootFolder
	$CurrentFile = $Context.web.GetFileByServerRelativeUrl($FileRelativeUrl)
	$Context.Load($CurrentFile)
	$Context.ExecuteQuery()
	$ListItem = $CurrentFile.ListItemAllFields;
	#$ListItem["Editor"] = $SPOItemModifier; # Get object from ResolveUser
	#$Listitem["Author"] = $SPOItemOwner; # Get object from ResolveUser
	$Listitem["Created"] = $ItemCreated;
	log -text "File Date being updated to ------ $ItemCreated"
	#$Listitem["Modified"] = $ItemModified;
	$ListItem.Update()
	$Context.Load($CurrentFile)
	$Context.ExecuteQuery()
}