One of my favorite sites – “Birds of Kazakhstan” (btw – site I support, to the best of my ability) has migrated again… The new Url is: https://kz.birding.day/
Meantime, at the moment, the site hosted 100+ members, who created 2400+ blog posts, uploaded 250K pictures of 500 photographed species out of 524 registered in Kazakhstan.
I have been involved in a birdwatching community web project for a long time. At the moment it has 250k pictures, 2500 blog posts from community members.
The site is a custom development – written by Askar Issabekov with php and MySQL and hosted under Dreamhost dedicated server.
Initially the migration plan was
get and configure new hosting
copy php scripts and media files
backup/restore MySQL databases
update hosts files and ensure everything works good
set source site in “maintenance” mode
put notification on the site header
set databases in read-only mode
backup/restore MySQL databases again
copy media files delta
set databases in r/w mode
ensure everything works good
change DNS from old host to new host
Some more data:
MySQL database: 120 MB
It turned out that
Source host uses Apache and target host uses Nginx
phpMyAdmin cannot import database from SQL backup
So we ended up the following
backup and document existing environment
get and configure new hosting
ensure php version is the same
copy php scripts and media files
remove all .htaccess and update nginx config files accordingly, e.g. Index etc.
fix files permissions (chmod)
backup/restore MySQL databases
if the database is big
– consider splitting database – a few tables each backup/restore
– consider zipping database while export-import
if phpMyAdmin fails – use command-line mysql
update database connections (user names, passwords, database names and hosts) as temporary measure – it is possible to allow access to old host databases from new host ip
update hosts files and ensure everything works good
set source site in “maintenance” mode
put notification on the site header
set databases in read-only mode
backup/restore MySQL databases again
set databases in r/w mode
copy media files delta
ensure everything works good
change DNS from old host to new host
Question: to avoid hassles with hosts files – is it possible to use a different real target name, then after verifying everything works good – change name
I have created a user “Robert Dylan” and never used name “Bob”, but search understands that I’m looking for Robert Dylan when I’m searching for Bob or Bob Dylan or Bobby.
Important thing – result is shown under “All” and “People” verticals.
I know Microsoft claimed m365 search is backed by Turing technology – it understands you, answers your question but not just blindly display keyword occurences (announcement at Ignite Spring, more on Ignite Fall 2021)… So is that it?
But the same trick did not work with Dick for Richard or (of course) Syd for Roger Barrett:
How do we know when the SharePoint site was last updated?
We have multiple “when the site was modified last time” properties – e.g. some we can retrieve with SharePoint CSOM:
Site LastContentModifiedDate
Web LastItemModifiedDate
Web LastItemUserModifiedDate
Also we can get
MS Graph site object with LastModifiedDateTime property
get usage reports via Microsoft Graph (activity reports), and
use “Last activity” field via Admin Center GUI
On the other hand – we can view and modify site in multiple ways – visit site home page, open and/or update document/list item, change site/library settings, configure site permissions, assign site sensitivity label, setup site property and so on.
Question: which site “last modified” or “last activity” properties reflect what events/actions?
This might be important if we think of retention policies, or any kind of clean-up processes… Let say, we are getting report on abandoned sites (inactive sites), but we are also assigning sites sensitivity labels, or we are updating site custom properties (e.g. for adaptive scopes), we have an ownerless groups policy working etc.
What if we assign site sensitivity label to an old inactive (5 years old) site – would it affect retention policy since site was updated this way?
Results
So i did some tests and based on detailed results below, it seems like
Web LastItemModifiedDate is triggered when user just visited site (but property LastItemUserModifiedDate is not triggered)
If a document or list Item updated by user or app – all properties are triggered
MS Graph site property LastModifiedDateTime, root web property LastItemModifiedDate and Site LastContentModifiedDate – same values
If site custom property is updated – it does not affect any site “last modified” property
The same for sensitivity label updated by app – it does not affect any site “last modified” property
The same for Microsoft ownerless groups policy – when user accept or decline group membership – no site “last modified” properties are changed (the same is true for Microsoft 365 group last modified date/time property).
Please refer to the table below
Detailed test results
Test results if the event triggers property update:
Event
Last Content Modified Date
Last Item Modified Date
Last Item User Modified Date
Graph Last Modified DateTime
GUI Last activity
Page viewed by user
Yes
Yes
No
Yes
Home Page viewed by user
Site Page viewed by user
Document or list item updated by user
Yes
Yes
Yes
Yes
Document or list item updated by app
Yes
Yes
Yes
Yes
Site config settings updated by user
Site config settings updated by app
Site custom property updated by app
No
No
No
No
Site Sensitivity label updated by user via SharePoint
Yes
No
No
No
Site/Group Sensitivity label updated by user via Teams
Site/Group Sensitivity label updated by user via Azure
No
No
No
No
Site Sensitivity label updated by app
No
No
No
No
Site collection admin updated by user
Yes
Yes
No
Yes
Site collection admin updated by app
Yes
Yes
No
Yes
SharePoint group membership updated by user
Yes
Yes
No
Yes
Standalone Site connected to a group by user
Yes
Yes
Yes
Yes
Add Microsoft Teams to Site by User
Yes
Yes
Yes
Yes
Update m365 group membership via M365 admin console by admin
Yes
Yes
No
Yes
Update m365 group membership via Azure by admin
Update m365 group membership via Teams by user
No
No
No
Yes
Update m365 group membership via App
Accept group ownership invitation sent by ownerless groups policy
No
No
No
No
Decline group ownership invitation sent by ownerless groups policy
Using Path property in Microsoft 365 Search Query was kind of ambiguous. But now Microsoft implemented update and clarified some details. So below are some tips and tricks on filtering by site Url (path) in query field in Microsoft 365 Search verticals.
Path filter with trailing slash (“/”)
In November 2022 Microsoft rolled out an update for multiple search features, including checks on the path managed property for a trailing slash. Previously path filters were valid with and without trailing slashes.
Consider the following scenario.
Given the path filter with the contain operator (“:”)
SPSiteUrl and Path properties use different matching strategies. When using contains operator (colon sign “:”) – SPSiteUrl will match the full value, while Path will do a “starts with” match.
DepartmentId
DepartmentId is a search managed property used under Hub sites and propagated through all associated sites content.
That means if we want to scope down search to hub site with it’s content – we can use DepartmentId property, e.g.
DepartmentId=4965d9be-929b-411a-9281-5662f5e09d49
instead of iteration through all hub sites and using path: property.
where you can use objects: “Site Url”, “Site Name” and “Refinable String 0″..”Refinable String 99”. Conditions would be “is equal to”, “is not equal to”, “starts with” and “not starts with”. Or you can select “Advanced query builder” and enter KQL query.
Advanced query builder
Advanced query builder allows us to use more site properties then “Site Url”, “Site Name” and “Refinable Strings” and more conditions than “is (not) equal to” and “(not) starts with”.
E.g. we can use “Title”, “Created”, “Modified” site properties and “=”,”:”,”<“, “>”, “<=”, “>=” conditions.
Working queries examples:
created>=2022-07-21
modified>1/31/2023
created>12/31/2021 AND modified>=7/31/2022
created<=2020-11-15 OR modified>2023-02-06 (?)
created<=2020-1-15 OR modified>2023-01-31 (?)
created<=11/15/2020 OR modified>1/31/2023
title:test
SiteTitle:test
RefinableString09:Test*
RefinableString09<>Test
RefinableString09=Birding AND RefinableString08<>Included
Not working queries examples:
site:https://contoso.sharepoint.com/sites/test*
RefinableString11 = Birds # (do not use spaces in advanced query)
Path:https://contoso-my.sharepoint.com
Template:STS
Template:"SITEPAGEPUBLISHING#0"
Template:SITEPAGEPUBLISHING*
? RefinableString09<>Birding AND RefinableString08:Official
modified>31/1/2023 (should be like modified>2023-01-31
)
Query against custom site property (aka property bag value)
You can create custom site property and assign value to the property with Set-PnPAdaptiveScopeProperty or Set-PnPPropertyBagValue. Property must be with “Indexed” parameter. Once the property is set up, m365 search crawls site and creates crawled property. Then you map crawled property to some pre-created refinable string managed property. You can assign alias to this managed property.
In my test scenario I used RefinableString09 with alias SiteCustomSubject.
Site property value
Query
result
Birding
RefinableString09:Bird
does not work
Birding
SiteCustomSubject:Bird
does not work
Birding
RefinableString09:Bird*
works
Birding
SiteCustomSubject:Bird*
does not work
Birding
RefinableString09:Birding
works
Birding
SiteCustomSubject:Birding
does not work
Birding
RefinableString09:Birding*
works
Birding
RefinableString09=Birding
works
Birding
RefinableString09=Bird
does not work
Birding
RefinableString09=Bird*
does not work
Birding
SiteCustomSubject=Birding
does not work
RefinableString09<>Birding
works
RefinableString09=Birding AND RefinableString08<>Included
works
Query against multi-value property.
Site property value
Query
result
TestA TestB
RefinableString09:TestA
works
TestA TestB
RefinableString09 = ‘TestA TestB’
does not work
TestA TestB
??? RefinableString09=’Test10 Test5′
does not work
TestA TestB
RefinableString09:TestB
?
TestA,TestB
RefinableString09:Test*
works
TestA,TestB
RefinableString09=Test*
does not work
TestA,TestB
RefinableString09:Test
does not work
TestA,TestB TestA;TestB TestB TestA TestA TestB
RefinableString09:TestB
works
TestA, TestB TestB,TestA TestA TestB
RefinableString09=TestA
does not work
TestA,TestB
(basic) RefinableString09 starts with test
works
Some more findings
Modify adaptive scope
If you need to modify adaptive scope – you’d better delete it and create a new one. The reason – if you want to validate what sites are included in scope with GUI – via button “Scope details” – you want to see only sites that are in scope, but that’s not the case when you modify the scope, because if you modify the scope – you’d see sites that are not in scope with “Removed” status.
Alternatively you can use filter to filter out removed from scope sites.
what else?
What is the takeaway from this for SharePoint administrators? We would be asked to configure SharePoint the way compliance…
That’s a very common problem in SharePoint world. You are looking for a site owner but there is no tool available for regular user to find who owns the site.
Scenarios.
You get a link to some SharePoint site, but you do not have access to it. You requested access but nobody has responded. You need to find who is the site owner.
After many years working with SharePoint I wrote a lot of PowerShell scripts that help me support, troubleshoot, administer and secure SharePoint. So I’m sharing my scripts with you.
This PowerShell script pulls all tenant sites and all sites owners. The script require app authentication with Sites.FullControl.All and Directory.Read.All permissions. PnP.PowerShell for PowerShell 7 is used.
The script generates two reports
Owners report: one user per line, include: Site Url, Title, Owner e-mail, name and type
Sites report: one site per line, include: Site Url, Title, list of owners e-mails