Skip to content

Commit a6a4326

Browse files
author
Vadim
committed
Add SharePoint examples: retention labels, file version policy, quota management, search admin diagnostics
1 parent 64e08f9 commit a6a4326

5 files changed

Lines changed: 394 additions & 2 deletions

File tree

examples/sharepoint/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@ prints clear output.
3131
| [`propertybag/`](./propertybag/) | Custom key-value pairs on webs |
3232
| [`permissions/`](./permissions/) | Grant, revoke, break inheritance |
3333
| [`recyclebin/`](./recyclebin/) | Restore deleted items |
34-
| [`search/`](./search/) | KQL queries, filters, refinement |
34+
| [`compliance/`](./compliance/) | Retention labels, compliance tags on sites/lists/files |
35+
| [`search/`](./search/) | KQL queries, filters, refinement, crawl diagnostics, admin |
3536
| [`sharing/`](./sharing/) | Sharing links, anonymous access |
3637
| [`sitedesigns/`](./sitedesigns/) | Site designs and site scripts |
3738
| [`sites/`](./sites/) | Create (modern/classic/communication), manage admins |
3839
| [`sitescripts/`](./sitescripts/) | Site script JSON actions |
3940
| [`taxonomy/`](./taxonomy/) | Term store, term sets, managed metadata |
4041
| [`teams/`](./teams/) | Teams via SharePoint API (limited) |
41-
| [`tenant/`](./tenant/) | Tenant admin, site collections, licensing |
42+
| [`tenant/`](./tenant/) | Tenant admin, site collections, licensing, quotas, version policy |
4243
| [`userprofile/`](./userprofile/) | Profile properties, followers, OneDrive URL |
4344
| [`users/`](./users/) | Current user, site users, search |
4445
| [`views/`](./views/) | List views, default and custom |
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""
2+
Compliance tags (retention labels) — list available tags, check
3+
applied tags on lists and items, and set retention compliance tags.
4+
5+
Compliance teams use this for data retention governance across
6+
SharePoint sites: apply "Keep for 7 years" or "Delete after 30 days"
7+
labels to lists and documents.
8+
9+
Requires delegated permission ``Sites.ReadWrite.All`` for read
10+
operations; ``Sites.FullControl.All`` to set compliance tags.
11+
12+
https://learn.microsoft.com/en-us/sharepoint/dev/apis/rest-api/compliance/compliance-tag-rest-api
13+
"""
14+
15+
import sys
16+
17+
from office365.sharepoint.client_context import ClientContext
18+
from tests import test_site_url, test_client_id, test_client_secret, test_tenant
19+
20+
TAG_NAME = "Financial Records" # Name of a compliance tag to apply
21+
22+
23+
def main():
24+
ctx = ClientContext(test_site_url).with_client_secret(test_tenant, test_client_id, test_client_secret)
25+
26+
# -- Step 1: list all available compliance tags in the site --
27+
web = ctx.web.get().execute_query()
28+
site = ctx.site.get().execute_query()
29+
30+
tags = site.get_available_tags().execute_query()
31+
print(f"Available compliance tags ({len(tags.value)}):\n")
32+
33+
for tag in tags.value:
34+
display_name = tag.TagName or tag.DisplayName or "(unnamed)"
35+
auto_delete = tag.AutoDelete or False
36+
block_delete = tag.BlockDelete or False
37+
block_edit = tag.BlockEdit or False
38+
print(f" {display_name:40s} "
39+
f"auto_delete={auto_delete} "
40+
f"block_delete={block_delete} "
41+
f"block_edit={block_edit}")
42+
43+
# -- Step 2: get compliance tag on a target list --
44+
target_list = ctx.web.lists.get_by_title("Documents")
45+
try:
46+
tag_info = target_list.get_compliance_tag().execute_query()
47+
if tag_info and tag_info.value:
48+
t = tag_info.value
49+
print(f"\nList 'Documents' compliance tag: {t.TagName or t.DisplayName or '(none)'}")
50+
else:
51+
print(f"\nList 'Documents' has no compliance tag set.")
52+
except Exception as e:
53+
print(f"\n (compliance tag read not available: {e})")
54+
55+
# -- Step 3: apply a compliance tag to a list --
56+
# Find the tag ID from available tags
57+
target_tag = None
58+
for tag in tags.value:
59+
name = tag.TagName or tag.DisplayName or ""
60+
if TAG_NAME.lower() in name.lower():
61+
target_tag = tag.tagId
62+
break
63+
64+
if target_tag:
65+
print(f"\nApplying compliance tag '{TAG_NAME}' to 'Documents' list...")
66+
target_list.set_compliance_tag(tag_id=target_tag).execute_query()
67+
print(" ✓ Compliance tag applied.")
68+
else:
69+
print(f"\n Tag '{TAG_NAME}' not found among available tags — skipping apply.")
70+
if tags.value:
71+
first_tag = tags.value[0]
72+
print(f" To try with a different tag, change TAG_NAME to: {first_tag.TagName or first_tag.DisplayName}")
73+
74+
# -- Step 4: apply a compliance tag with hold to a specific file --
75+
if target_tag:
76+
try:
77+
list_items = target_list.items.top(1).get().execute_query()
78+
if list_items:
79+
item = list_items[0]
80+
item.set_compliance_tag_with_hold(target_tag).execute_query()
81+
print(f" ✓ Compliance tag with hold applied to item: {item.properties.get('Title', item.id)}")
82+
except Exception as e:
83+
print(f" (item tag apply not available: {e})")
84+
85+
86+
if __name__ == "__main__":
87+
main()
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""
2+
Search administration — crawl diagnostics, popular queries, search
3+
service configuration, and manual suggestions.
4+
5+
Provides search admins with tools to:
6+
- Check search service configuration (search center URL, result URL)
7+
- View crawl status and unsuccessful URLs
8+
- Export popular tenant queries
9+
- Export and update manual query suggestions
10+
11+
Requires delegated permission ``Sites.ReadWrite.All`` for most
12+
operations; ``Sites.FullControl.All`` for configuration updates.
13+
14+
https://learn.microsoft.com/en-us/sharepoint/dev/general-development/search-in-sharepoint
15+
"""
16+
17+
import sys
18+
19+
from office365.sharepoint.client_context import ClientContext
20+
from office365.sharepoint.search.administration.document_crawl_log import DocumentCrawlLog
21+
from tests import test_site_url, test_client_id, test_client_secret, test_tenant
22+
23+
24+
def main():
25+
ctx = ClientContext(test_site_url).with_client_secret(test_tenant, test_client_id, test_client_secret)
26+
27+
search_svc = ctx.search
28+
29+
# -- Step 1: query search service configuration --
30+
center_url = search_svc.search_center_url().execute_query()
31+
result_url = search_svc.results_page_address().execute_query()
32+
33+
print("Search service configuration:\n")
34+
print(f" Search center URL: {center_url.value or '(not set)'}")
35+
print(f" Results page address: {result_url.value or '(default)'}\n")
36+
37+
# -- Step 2: export popular tenant queries --
38+
popular = search_svc.export_popular_tenant_queries(count=10).execute_query()
39+
if popular and popular.value:
40+
print(f"Popular tenant queries (top {len(popular.value)}):")
41+
for i, q in enumerate(popular.value, 1):
42+
query_text = q.properties.get("queryText", q.properties.get("QueryText", "?"))
43+
count_val = q.properties.get("count", q.properties.get("Count", "?"))
44+
print(f" {i:2d}. {query_text:45s} count={count_val}")
45+
else:
46+
print("(No popular tenant query data available)")
47+
print()
48+
49+
# -- Step 3: export manual query suggestions --
50+
suggestions = search_svc.export_manual_suggestions().execute_query()
51+
if suggestions and suggestions.value:
52+
suggested_queries = suggestions.value.properties.get("suggestedQueries", [])
53+
print(f"Manual query suggestions ({len(suggested_queries)}):")
54+
for sq in suggested_queries[:5]:
55+
print(f" - {sq}")
56+
else:
57+
print("(No manual suggestions configured)")
58+
print()
59+
60+
# -- Step 4: document crawl log diagnostics --
61+
try:
62+
crawl_log = DocumentCrawlLog.create(ctx)
63+
print("Document crawl log:")
64+
# Get crawled URLs (first page)
65+
urls = crawl_log.get_crawled_urls().execute_query()
66+
if urls and urls.value:
67+
data = urls.value
68+
if hasattr(data, "rows") and data.rows:
69+
print(f" Crawl log entries: {len(data.rows)}")
70+
for row in data.rows[:5]:
71+
print(f" URL: {row[0] if len(row) > 0 else '?'}")
72+
else:
73+
print(f" Crawl log entries: {len(urls.value)}")
74+
else:
75+
print(" (no crawl log data)")
76+
77+
# Get unsuccessful crawls
78+
failed = crawl_log.get_unsuccesful_crawled_urls().execute_query()
79+
if failed and failed.value:
80+
data = failed.value
81+
if hasattr(data, "rows") and data.rows:
82+
print(f" Unsuccessful URLs: {len(data.rows)}")
83+
for row in data.rows[:5]:
84+
print(f" URL: {row[0] if len(row) > 0 else '?'} "
85+
f"error: {row[1] if len(row) > 1 else '?'}")
86+
except Exception as e:
87+
print(f" (crawl diagnostics not available: {e})")
88+
89+
90+
if __name__ == "__main__":
91+
main()
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""
2+
File version policy — manage tenant-wide version limits, expiration,
3+
and auto-deletion settings.
4+
5+
Version bloat is one of the most common storage problems in SharePoint.
6+
This example shows how to:
7+
- Read current tenant file version policy
8+
- Set version expiration and delete job options
9+
- Get per-library version policy settings
10+
- Clear the policy back to tenant defaults
11+
12+
Requires delegated permission ``Sites.FullControl.All``.
13+
14+
https://learn.microsoft.com/en-us/sharepoint/dev/apis/rest-api/tenant/SetFileVersionPolicy
15+
"""
16+
17+
import sys
18+
19+
from office365.sharepoint.client_context import ClientContext
20+
from office365.sharepoint.tenant.administration.tenant import Tenant
21+
from tests import test_admin_site_url, test_client_id, test_client_secret, test_tenant
22+
23+
# Example library to check per-library policy (replace with actual URL)
24+
LIBRARY_URL = "https://contoso.sharepoint.com/sites/TeamSite/Shared%20Documents"
25+
26+
27+
def main():
28+
ctx = ClientContext(test_admin_site_url).with_client_secret(test_tenant, test_client_id, test_client_secret)
29+
tenant = Tenant(ctx)
30+
31+
# -- Step 1: get current tenant file version policy --
32+
policy_result = tenant.get_file_version_policy().execute_query()
33+
policy_xml = policy_result.value if policy_result.value else "(empty — no custom policy set)"
34+
print(f"Tenant file version policy:\n{policy_xml}\n")
35+
36+
# -- Step 2: set a file version policy (commented by default) --
37+
# The policy is defined as XML. A typical policy:
38+
#
39+
# <FileVersionPolicy>
40+
# <MajorVersionLimit>500</MajorVersionLimit>
41+
# <MajorWithMinorVersionsLimit>500</MajorWithMinorVersionsLimit>
42+
# <Expiration>
43+
# <Interval>180</Interval>
44+
# <DeleteAfter>AfterInterval</DeleteAfter>
45+
# </Expiration>
46+
# <DeleteJobInterval>7</DeleteJobInterval>
47+
# </FileVersionPolicy>
48+
#
49+
# MajorVersionLimit: max major versions kept (0 = unlimited)
50+
# MajorWithMinorVersionsLimit: max versions including minors
51+
# Expiration.Interval: delete versions older than N days
52+
# Expiration.DeleteAfter: "AfterInterval" or "Never"
53+
# DeleteJobInterval: how often the timer job runs (days)
54+
55+
new_policy = """<FileVersionPolicy>
56+
<MajorVersionLimit>500</MajorVersionLimit>
57+
<MajorWithMinorVersionsLimit>500</MajorWithMinorVersionsLimit>
58+
<Expiration>
59+
<Interval>180</Interval>
60+
<DeleteAfter>AfterInterval</DeleteAfter>
61+
</Expiration>
62+
<DeleteJobInterval>7</DeleteJobInterval>
63+
</FileVersionPolicy>"""
64+
65+
# Uncomment to apply:
66+
# tenant.set_file_version_policy(policy_xml=new_policy).execute_query()
67+
# print("✓ Tenant file version policy updated.")
68+
69+
# -- Step 3: get per-library version policy --
70+
try:
71+
from office365.sharepoint.tenant.administration.policies.list_parameters import SPOListParameters
72+
list_params = SPOListParameters(
73+
listUrl=LIBRARY_URL,
74+
listType="DocumentLibrary",
75+
)
76+
lib_policy = tenant.get_file_version_policy_for_library(
77+
site_url="https://contoso.sharepoint.com/sites/TeamSite",
78+
list_params=list_params,
79+
).execute_query()
80+
81+
if lib_policy and lib_policy.value:
82+
p = lib_policy.value
83+
print(f"\nLibrary file version policy:")
84+
print(f" MajorVersionLimit: {p.MajorVersionLimit}")
85+
print(f" MajorWithMinorVersionsLimit: {p.MajorWithMinorVersionsLimit}")
86+
print(f" Expiration interval: {p.ExpirationInterval} days")
87+
print(f" Delete after: {p.DeleteAfter}")
88+
except Exception as e:
89+
print(f"\n (per-library policy not available: {e})")
90+
91+
# -- Step 4: clear file version policy back to defaults --
92+
# tenant.clear_file_version_policy().execute_query()
93+
# print("\n✓ File version policy cleared.")
94+
95+
96+
if __name__ == "__main__":
97+
main()

0 commit comments

Comments
 (0)