#Module name: O365AntiCryptoLocker #Author: Jos Lieben (OGD) #Date: 08-06-2016 #Script help: www.liebensraum.nl #Purpose: restores the previous version of any Sharepoint Online document library's files #Requirements: #Sharepoint Client components: https://www.microsoft.com/en-us/download/details.aspx?id=42038 #Powershell 4 #.NET 4.5 #run “Set-Executionpolicy Unrestricted” in an elevated powershell window #Windows 7+ or Windows Server 2008+ ######## Param( [Parameter(Mandatory=$true,Position=1)] [String]$siteURL, #URL to your site (Sharepoint Online or Onedrive for Business mysite) [Parameter(Mandatory=$true,Position=2)] [String]$login, [Parameter(Mandatory=$true,Position=3)] [String]$password, [Parameter(Mandatory=$true,Position=4)] [String]$libraryTitle ) $logfile = ($env:APPDATA + "\O365AntiCryptoLocker.log") #Logfile to log to $scriptName = "O365AntiCryptoLocker" $scriptVersion = "v0.1" function log{ param ( [String]$text, [Switch]$fout, [Switch]$append ) if($append){$text = "$text, $($Error[0])"} ac $logfile $text if($fout){ Write-Host $text -ForegroundColor Red }else{ Write-Host $text -ForegroundColor Green } } function Pause{ Read-Host 'Press Enter to continue...' | Out-Null } function endScript{ Read-Host 'Script has finished, press Enter to exit...' | Out-Null Exit } log -text "-----$(Get-Date) $scriptName $scriptVersion - $($env:USERNAME) on $($env:COMPUTERNAME) starting-----" #Load WPF Framework (.NET) try{ Add-Type -AssemblyName PresentationCore,PresentationFramework,WindowsBase,system.windows.forms log "WPF assemblies: OK" } catch { $OUTPUT= [System.Windows.Forms.MessageBox]::Show("Failed to load Windows Presentation Framework assemblies, install .NET 4 or higher", "$scriptName $scriptVersion" , 0) log -text "Failed to load Windows Presentation Framework assemblies, install .NET 4 or higher" -fout -append endScript } #Load sharepoint libraries try{ [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles") | Out-Null log -text "Sharepoint Client Libraries: OK" } catch { $OUTPUT= [System.Windows.Forms.MessageBox]::Show("Please install the Sharepoint 2013 Client Components from https://www.microsoft.com/en-us/download/details.aspx?id=42038", "$scriptName $scriptVersion" , 0) log -text "Failed to load Sharepoint Extensions, please install the Sharepoint 2013 Client Components from https://www.microsoft.com/en-us/download/details.aspx?id=42038" -fout -append endScript } #Connect to SPOnline log -text "Connecting to Sharepoint Online..." $client = New-Object Microsoft.SharePoint.Client.ClientContext($siteURL) #build Credential Object $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force $client.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($login,$secpasswd) #Connect try{ $client.Load($client.Web) $client.ExecuteQuery() log -text "Connection to Sharepoint Online: OK" }catch{ log -text "Failed to connect to Sharepoint Online" -fout -append endScript } #Load target library try{ $library=$client.Web.Lists.GetByTitle($libraryTitle) $client.Load($library) $client.ExecuteQuery() log -text "$libraryTitle found" }catch{ log -text "Failed to find $libraryTitle" -fout -append endScript } #Load all files in library try{ $fileQuery = New-Object Microsoft.SharePoint.Client.CamlQuery $fileQuery.ViewXml =""; $files=$library.GetItems($fileQuery) $client.Load($files) $client.ExecuteQuery() log -text "Processing $($files.Count) files in $libraryTitle...." }catch{ log -text "Failed to load files in $libraryTitle" -fout -append endScript } #loop over returned files and restore the latest previous version if available foreach($file in $files){ #skip folders, only act on files if($file.FileSystemObjectType -eq "folder"){continue} #retrieve file metadata $fileInfo = $client.Web.GetFileByServerRelativeUrl($file["FileRef"]) try{ $client.Load($fileInfo) $client.ExecuteQuery() $fileVersions = $fileInfo.Versions $client.Load($fileVersions) $client.ExecuteQuery() }catch{ log -text "ERROR, skipping $($file["FileRef"])" -fout -append continue } #process previous versions if($fileVersions.Count -gt 0){ #loop over versions to get the latest [DateTime]$latestFileVersionDateTime = "01-01-1900 01:01:01" [String]$latestFileVersionLabel = "" foreach($fileVersion in $fileVersions){ if($fileVersion.Created -gt $latestFileVersionDateTime -and $fileVersion.IsCurrentVersion -eq $False){ $latestFileVersionDateTime = $fileVersion.Created $latestFileVersionLabel = $fileVersion.VersionLabel } } #restore latest version if($latestFileVersionLabel){ try{ $fileVersions.RestoreByLabel($latestFileVersionLabel) $client.ExecuteQuery() log -text "Restored $latestFileVersionLabel ($latestFileVersionDateTime) of $($file["FileRef"])" }catch{ log -text "Failed to restore $latestFileVersionLabel ($latestFileVersionDateTime) of $($file["FileRef"])" -fout -append } }else{ log -text "No usable previous version found for $($file["FileRef"])" -fout } }else{ log -text "No previous versions available for $($file["FileRef"]), it is likely unaffected" continue } } log -text "Finished processing $libraryTitle" endScript