├── .gitignore ├── Documents ├── Add SPOQA to OneDrive Host Site │ └── Add SPOQA to OneDrive Host Site.md ├── CheckPermissionIssue.md ├── GetFileChanges.md ├── How to collect display url for files and list items │ └── ReadMe.md ├── Installation │ └── ReadMe.md ├── JobTitleSyncIssue.md ├── MissingForms.md ├── OneDriveLockIcon.md ├── Privacy │ └── ReadMe.md ├── ReadMe.md ├── RestoreItems.md ├── SearchSpecificDocument.md ├── SearchSpecificSite.md ├── SupportContacts ├── UneditableClassicWiki.md ├── UserInfoSyncIssue.md └── UserPhotoSync.md ├── KBs ├── List │ └── UpdateListReadWriteSecurity.ps1 ├── Migration │ └── DocumentID │ │ ├── GetDocIDReport.ps1 │ │ ├── ReadMe.md │ │ └── TouchDocumentIds.ps1 ├── ReadMe.md ├── Restore │ └── RestoreWithPNPRESTAPI.ps1 ├── TLS │ ├── TLSDiag.ps1 │ └── TLSSettings.ps1 ├── TermStore │ └── UpdateTermOwner │ │ ├── ReadMe.md │ │ └── UpdateTermOwner.ps1 ├── UAP │ ├── SyncPhotoFromADToSPO(21-Viaent) │ │ ├── ReadMe.md │ │ └── SyncPhotoFromADToSPO(21-Viaent).ps1 │ ├── SyncPhotoFromADToSPO │ │ ├── GetUsersWithOutPictureInSPO.ps1 │ │ ├── ReadMe.md │ │ ├── SPOManagementShellSyncPhotoFromAADToSPOByGraphAPI.ps1 │ │ ├── SyncPhotoFromAADToSPO.ps1 (Archived) │ │ └── SyncPhotoFromAADToSPOByGraphAPI.ps1 │ ├── SyncUserPropertiesFromAADToSPOProfile │ │ ├── ReadMe.md │ │ └── SyncUserPropertiesFromAADToSPOProfile.ps1 │ └── UploadUserPictureToSPO │ │ ├── ReadMe.md │ │ └── UploadUserPictureToSPO.ps1 └── UneditableClassicWiki │ └── ReadMe.md ├── LICENSE ├── Packages ├── HistoryVersions │ ├── spoqa 1.22.12.01.sppkg │ ├── spoqa.1.22.05.25.sppkg │ ├── spoqa1.21.11.06.sppkg │ ├── spoqa1.21.11.29.sppkg │ ├── spoqa1.21.12.06.sppkg │ ├── spoqa1.21.12.17.sppkg │ ├── spoqa1.21.12.28.sppkg │ ├── spoqa1.22.02.25.sppkg │ ├── spoqa1.22.02.26.sppkg │ ├── spoqa1.22.03.07.sppkg │ ├── spoqa1.22.03.12.sppkg │ ├── spoqa1.22.03.26.sppkg │ ├── spoqa1.22.03.28.sppkg │ ├── spoqa1.22.04.02.sppkg │ ├── spoqa1.22.04.05.sppkg │ ├── spoqa1.22.04.12.sppkg │ ├── spoqa1.22.04.16.sppkg │ ├── spoqa1.22.04.20.sppkg │ ├── spoqa1.22.04.22.sppkg │ ├── spoqa1.22.04.25.sppkg │ ├── spoqa1.22.05.10.sppkg │ ├── spoqa1.22.05.20.sppkg │ ├── spoqa1.22.06.01.sppkg │ ├── spoqa1.22.06.27.sppkg │ ├── spoqa1.22.07.13.sppkg │ ├── spoqa1.22.0713.sppkg │ └── spoqa1.22.10.04.sppkg ├── ReadMe.md └── spoqa.sppkg ├── README.md ├── SPFX ├── .yo-rc.json └── SPOQA │ ├── .gitignore │ ├── .vscode │ ├── extensions.json │ ├── launch.json │ └── settings.json │ ├── .yo-rc.json │ ├── PrdBuild.ps1 │ ├── README.md │ ├── SearchSite.md │ ├── asset │ ├── CheckUserProfilePhoto.JPG │ ├── FixedNoCrawl.JPG │ ├── JobTitle.JPG │ ├── NoCrawl.JPG │ └── readme │ ├── config │ ├── config.json │ ├── copy-assets.json │ ├── deploy-azure-storage.json │ ├── package-solution.json │ ├── serve.json │ └── write-manifests.json │ ├── gulpfile.js │ ├── package-lock.json │ ├── package.json │ ├── sharepoint │ └── solution │ │ └── spoqa.sppkg │ ├── src │ ├── index.ts │ └── webparts │ │ ├── Helpers │ │ ├── ContextHelper.ts │ │ ├── FormsHelper.ts │ │ ├── GraphAPIHelper.ts │ │ ├── ItemHelper.ts │ │ ├── ModerationStatusHelper.ts │ │ ├── RemedyHelper.ts │ │ ├── RestAPIHelper.ts │ │ ├── SPOQAHelper.ts │ │ ├── SPOQASpinner.ts │ │ └── SearchHelper.ts │ │ ├── exoQuickAssist │ │ ├── ExoQuickAssistWebPart.manifest.json │ │ ├── ExoQuickAssistWebPart.ts │ │ ├── components │ │ │ ├── ExoQuickAssist.module.scss │ │ │ ├── ExoQuickAssist.tsx │ │ │ ├── IExoQuickAssistProps.ts │ │ │ └── OrganizationSettings │ │ │ │ └── PeopleInsightsQA.tsx │ │ └── loc │ │ │ ├── en-us.js │ │ │ ├── ja-jp.js │ │ │ ├── mystrings.d.ts │ │ │ └── zh-cn.js │ │ ├── sharePointOnlineQuickAssist │ │ ├── SharePointOnlineQuickAssistWebPart.manifest.json │ │ ├── SharePointOnlineQuickAssistWebPart.ts │ │ ├── components │ │ │ ├── ISharePointOnlineQuickAssistProps.ts │ │ │ ├── List │ │ │ │ ├── RepairListForms.tsx │ │ │ │ └── RepairWikiLayout.tsx │ │ │ ├── OneDrive │ │ │ │ └── OneDriveLockIcon.tsx │ │ │ ├── Search │ │ │ │ ├── CrawlLogGrid.tsx │ │ │ │ ├── CrawledPropertyGrid.tsx │ │ │ │ ├── ICrawlLog.ts │ │ │ │ ├── ICrawledProperty.ts │ │ │ │ ├── IManagedProperty.ts │ │ │ │ ├── ManagedPropertyGrid.tsx │ │ │ │ ├── SearchDocument.tsx │ │ │ │ ├── SearchLibrary.tsx │ │ │ │ ├── SearchPeople.tsx │ │ │ │ └── SearchSite.tsx │ │ │ ├── SharePointOnlineQuickAssist.module.scss │ │ │ ├── SharePointOnlineQuickAssist.tsx │ │ │ ├── Site │ │ │ │ ├── GetFilesChange.tsx │ │ │ │ ├── IFile.ts │ │ │ │ ├── IFilesDeltaProps.ts │ │ │ │ ├── IFilesGrid.tsx │ │ │ │ ├── IRestoreItem.ts │ │ │ │ ├── Permission.tsx │ │ │ │ ├── RestoreItems.tsx │ │ │ │ └── RestoreItemsQAGrid.tsx │ │ │ └── UserProfile │ │ │ │ ├── UserInfo.tsx │ │ │ │ ├── UserProfileDepartment.tsx │ │ │ │ ├── UserProfileEmail.tsx │ │ │ │ ├── UserProfileManager.tsx │ │ │ │ ├── UserProfilePhoto.tsx │ │ │ │ └── UserProfileTitle.tsx │ │ └── loc │ │ │ ├── en-us.js │ │ │ ├── ja-jp.js │ │ │ ├── mystrings.d.ts │ │ │ └── zh-cn.js │ │ └── teamsQuickAssist │ │ ├── TeamsQuickAssistWebPart.manifest.json │ │ ├── TeamsQuickAssistWebPart.ts │ │ ├── components │ │ ├── Admin │ │ │ └── TestTeamsQA.tsx │ │ ├── ITeamsQuickAssistProps.ts │ │ ├── TeamsQuickAssist.module.scss │ │ └── TeamsQuickAssist.tsx │ │ └── loc │ │ ├── en-us.js │ │ ├── ja-jp.js │ │ ├── mystrings.d.ts │ │ └── zh-cn.js │ ├── teams │ ├── 6e9d3cc3-8c9d-4d11-893a-50179561b893_color.png │ ├── 6e9d3cc3-8c9d-4d11-893a-50179561b893_outline.png │ ├── 82d9e654-8ffa-45ad-866a-df31c3d5a9b2_color.png │ ├── 82d9e654-8ffa-45ad-866a-df31c3d5a9b2_outline.png │ ├── dbbdda4a-efbb-4e44-8a46-a72a99890e85_color.png │ └── dbbdda4a-efbb-4e44-8a46-a72a99890e85_outline.png │ ├── tsconfig.json │ └── tslint.json ├── Terms of Use ├── Terms of Use.md └── assets ├── ApproveAPI.JPG ├── CheckUserProfilePhoto.JPG ├── Deploy.JPG ├── JobTitle.JPG ├── JobTitleSync.JPG ├── NoCrawl.JPG ├── README.md ├── SearchSpecificDocument.JPG ├── SiteNoCrawl.JPG ├── UploadSolution.JPG └── WebPart.JPG /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Dependency directories 7 | node_modules 8 | 9 | # Build generated files 10 | dist 11 | lib 12 | release 13 | solution 14 | temp 15 | 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # OSX 21 | .DS_Store 22 | 23 | # Visual Studio files 24 | .ntvs_analysis.dat 25 | .vs 26 | bin 27 | obj 28 | 29 | # Resx Generated Code 30 | *.resx.ts 31 | 32 | # Styles Generated Code 33 | *.scss.ts 34 | -------------------------------------------------------------------------------- /Documents/Add SPOQA to OneDrive Host Site/Add SPOQA to OneDrive Host Site.md: -------------------------------------------------------------------------------- 1 | Demo for adding SPOQA to ODB root site for global tenants 2 | 3 | 4 | • First navigate to https://yourDomain-my.sharepoint.com/_layouts/15/ManageFeatures.aspx and activate the Site Pages feature as in screenshot below. 5 | image 6 | 7 | 8 | • After the above step you can go to https://yourDomain-my.sharepoint.com/_layouts/15/viewlsts.aspx?view=14 to have a look. 9 | 10 | image 11 | 12 | 13 | 14 | • Then run the below cmdlets to add AppCatalogto ODB root site ( https://yourDomain-my.sharepoint.com) 15 | Connect-SPOService -url https://m365x026020-admin.sharepoint.com 16 | Add-SPOSiteCollectionAppCatalog -Site https://m365x026020-my.sharepoint.com 17 | image 18 | 19 | 20 | • Go back to https://yourDomain-my.sharepoint.com/_layouts/15/viewlsts.aspx?view=14 21 | • Select Apps for SharePoint > click upload to upload the SPOQA app. 22 | 23 | image 24 | 25 | image 26 | 27 | 28 | • Click Deployon the next screen that pops up. 29 | • Go back to https://yourDomain-my.sharepoint.com/_layouts/15/viewlsts.aspx?view=14 30 | 31 | image 32 | image 33 | 34 | 35 | 36 | • Go back to https://yourDomain-my.sharepoint.com/_layouts/15/viewlsts.aspx?view=14 37 | 38 | image 39 | 40 | • Create a page and add SPOQA webpart in the page. 41 | 42 | image 43 | 44 | image 45 | 46 | -------------------------------------------------------------------------------- /Documents/CheckPermissionIssue.md: -------------------------------------------------------------------------------- 1 | # Permission issue 2 | ## Summary 3 | In daily work we see a lot of customers reported permission issue, so we summary some common scenarios which may cause the performance issue and added the permission check function. 4 | ![image](https://user-images.githubusercontent.com/21354416/184810706-55938c64-fd2f-4328-85c1-3eee517cb75f.png) 5 | 6 | ## Example 7 | a. Specify the user and objects (affected site, library, [full document URL](https://github.com/abrcheng/SharePointOnlineQuickAssist/tree/main/Documents/How%20to%20collect%20display%20url%20for%20files%20and%20list%20items)) which need to be checked, 8 | ![image](https://user-images.githubusercontent.com/21354416/184810516-572b0192-5615-49eb-a0f6-f1e8e7df77b9.png) 9 | 10 | b. Click "Check Issues" button and wait for checking complete 11 | ![image](https://user-images.githubusercontent.com/21354416/160529848-f00bb12f-932a-4bd8-8fe2-dbefc6739467.png) 12 | 13 | c. Click "Show Remedy Steps" button, 14 | ![image](https://user-images.githubusercontent.com/21354416/184810982-1e3f8619-52e8-4958-b6b7-5c7600b29b48.png) 15 | 16 | 17 | d. Open the remedy link in a new tab, 18 | ![image](https://user-images.githubusercontent.com/21354416/160530199-18ec4d8d-d132-4263-b8b2-dd50b6960d92.png) 19 | 20 | ## More Information 21 | The feature diagnoses and fixes the issue as follows: 22 | 1. There isn't any documents without check-in version in the library. 23 | 2. The file can be found. 24 | 3. The user has read permission on the document 25 | 4. The document is not in draft version 26 | 5. The library hasn't been set to only the author can read/write the item 27 | 6. Limited-access user permission lockdown mode of the site collection has been disabled 28 | 7. The affected user has view permission on the library. 29 | 8. The customization of the modern/classic page 30 | -------------------------------------------------------------------------------- /Documents/GetFileChanges.md: -------------------------------------------------------------------------------- 1 | # Get File Changes (New or Update) 2 | ## Summary 3 | This feature helps get all or filtered file changes for a given site 4 | 5 | ## Example 6 | 7 | * Enter the site url to get the changes. Click 'Get Files" and it will start to query. 8 | ![image](https://user-images.githubusercontent.com/79626459/185389396-bec89e6c-76e1-4271-b6e6-3c68e3568afb.png) 9 | 10 | * It shows the changes list with the following format. 11 | ![image](https://user-images.githubusercontent.com/79626459/185389807-38be33d1-4faf-4442-81ff-ea2048c1ce69.png) 12 | 13 | * User can also filter the results by 'Modified User', 'Path', 'Start Date' or 'End Date". 14 | ![image](https://user-images.githubusercontent.com/79626459/185390292-bb9bf6f4-cd73-46fb-933e-9eb6ecbcab86.png) 15 | 16 | * The results can be exported to a CSV file. 17 | ![image](https://user-images.githubusercontent.com/79626459/185390615-f1f7ab00-1716-490b-8e0d-ac3f7b59dc64.png) 18 | 19 | ## More Information 20 | 21 | The feature is based on 'delta query'. Reference: https://docs.microsoft.com/en-us/graph/delta-query-overview 22 | 23 | * It doesn't work for 21V tenants becasue 'delta query' is not supported there. 24 | * It only queries changes for new and update. It doesn't return deleted files. 25 | -------------------------------------------------------------------------------- /Documents/How to collect display url for files and list items/ReadMe.md: -------------------------------------------------------------------------------- 1 | ## Collect display url for a file 2 | The display url for a file in library could be easily collected by clicking the [Copy direct link] button on detail panel. 3 | ![getfilepath](https://user-images.githubusercontent.com/102142347/173496710-a20bc968-5303-4e1b-a088-5c933dc3cdda.gif) 4 | 5 | 6 | ## Collect display url for a list item 7 | To collect display url for a list item, we should collect the direct link in the same way first, and then modified the {id}_.000 to dispform.aspx?ID={id}. 8 | ![getitempath](https://user-images.githubusercontent.com/102142347/173496745-b6eb8eab-4eac-4910-8f05-a7e7ff2d40c8.gif) 9 | 10 | e.g. 11 | 12 | If the direct link to the list item was 13 | 14 | >https://contoso.sharepoint.com/sites/SPOQA/Lists/List1/2_.000 15 | 16 | please change it to 17 | 18 | >https://contoso.sharepoint.com/sites/SPOQA/Lists/List1/dispform.aspx?ID=2 19 | -------------------------------------------------------------------------------- /Documents/Installation/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Deployment Approaches (only need to choice one of below deploy approaches) 2 | ## Deploy the tool from SharePoint Store (need SPO tenant admin to install it) 3 | 1. Open the tenant app manage page https://appsource.microsoft.com/en-us/product/office/WA200004431?tab=Reviews and click "Get it now" button (need sign in by SPO tenant admin) 4 | 5 | ![image](https://user-images.githubusercontent.com/21354416/182510298-a343896c-8ed6-4cd4-b380-61e3c9d05afd.png) 6 | 7 | 2. Click "Get it now" button in the confirmation dialog 8 | 9 | 3. Click the searched "SharePoint Online Quick Assist" and click "Add to app catalog" button 10 | 11 | ![image](https://user-images.githubusercontent.com/21354416/181447089-484ed56a-b2f1-4e95-8c76-7ad97c613492.png) 12 | 13 | 4. Click "Add" button for the "Confirm data access" 14 | 15 | ![image](https://user-images.githubusercontent.com/21354416/181447204-359d1818-1853-4b6a-897b-d4a695e20cb6.png) 16 | 17 | 5. Click "Go to API access page" button 18 | 19 | ![image](https://user-images.githubusercontent.com/21354416/181447325-f52cd82c-ca38-4968-ba70-5045751478db.png) 20 | 21 | 6. Select pending API requests for "SharePoint Online Quick Assist" and click approve button 22 | 23 | ![image](https://user-images.githubusercontent.com/21354416/181447412-1c2ba036-e8fb-4030-ac15-06511b81239d.png) 24 | 25 | 7. Go to the site, site settings, add an app and add "SharePoint Online Quick Assist" 26 | 27 | ![image](https://user-images.githubusercontent.com/21354416/181447526-bf2d3ce3-e5f0-46cc-b548-d8833a01b6c3.png) 28 | 29 | 8. Add the "SharePoint Online Quick Assist" web part into page 30 | 31 | ![image](https://user-images.githubusercontent.com/21354416/181447638-5ab748de-865b-4b7f-a260-f775f7daa0b3.png) 32 | 33 | 9. Welcome to write a review in the reviews page https://appsource.microsoft.com/en-us/product/office/WA200004431?tab=Reviews, 34 | 35 | ![image](https://user-images.githubusercontent.com/21354416/182510583-6b669ef9-d9be-4bb5-b0f9-67349cadd3d4.png) 36 | 37 | 38 | ## Deploy the tool tenant level app catalog *from github* 39 | * Upload SPOQA.sppkg from https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Packages/spoqa.sppkg to your tenant App Catalog 40 | * E.g.: https://<tenant>.sharepoint.com/sites/AppCatalog/AppCatalog 41 | 42 | 43 | * Deploy the app when you see the prompt as follow 44 | 45 | 46 | 47 | * Approve API access requests in SharePoint admin center 48 | * https://<tenant>-admin.sharepoint.com/_layouts/15/online/AdminHome.aspx#/webApiPermissionManagement 49 | 50 | 51 | * Add the web part to a site collection, and test it on a page 52 | 53 | 54 | ## Deploy the tool site collection level app catalog *from github* 55 | Download and install SharePoint Online Management Shell. 56 | * Open it and run the following: (You need Global admin or SharePoint admin rights. ) 57 | * Connect-SPOService https://contoso-admin.sharepoint.com 58 | * Set-SPOSite -Identity https://contoso.sharepoint.com/sites/ASite -DenyAddAndCustomizePages 0 59 | * Add-SPOSiteCollectionAppCatalog -Site https://contoso.sharepoint.com/sites/ASite 60 | * Download the tool https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Packages/spoqa.sppkg. 61 | * Access https://contoso.sharepoint.com/sites/ASite/AppCatalog. 62 | * Click “Upload” and upload “spoqa.sppkg”. 63 | * Click “Deploy” and click “Trust” button. 64 | * Approve API access requests in SharePoint admin center, 65 | https://-admin.sharepoint.com/_layouts/15/online/AdminHome.aspx#/webApiPermissionManagement 66 | * Back to the site https://contoso.sharepoint.com/sites/ASite, click “Add an app”. 67 | * Add “spoqa-client-side-solution”. 68 | * Add a new page in the site and add the web part “SharePoint Online Quick Assist”. “Publish” the page. 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Documents/JobTitleSyncIssue.md: -------------------------------------------------------------------------------- 1 | # Job title sync issue 2 | 3 | ## Summary 4 | This feature helps user diagnose if 'job title' is having sync issues. 5 | 6 | ## Example 7 | 8 | Enter the affected site url user principle name. Click 'Check Job Title'. 9 | ![image](https://user-images.githubusercontent.com/89838160/184313033-ef733615-1e7b-4bb5-ac94-8ae00fee8899.png) 10 | 11 | In this example, the user's job title in user profile is incorrect. Just click 'Fix it' and it will be fixed automatically. 12 | ![image](https://user-images.githubusercontent.com/89838160/184313749-5453cf65-7c9c-4f00-9d95-f4e44fbf2983.png) 13 | 14 | -------------------------------------------------------------------------------- /Documents/MissingForms.md: -------------------------------------------------------------------------------- 1 | # Missing New/Edit/Display Forms for A Library/List 2 | 3 | ## Summary 4 | This feature helps user restore new/edit/display forms if they are missing in the library/list 5 | 6 | ## Symptom 7 | User cannot open 'Version history' for a file, and it shows an error as below. This generally happens if the document library is migrated from on-prem to online. 8 | ![image](https://user-images.githubusercontent.com/79626459/185387125-1282f982-b7c8-4fd2-948f-6e896b403f75.png) 9 | 10 | ## Example 11 | 12 | * Enter the affected site url. Select the library/list to check. Click 'Check Issues' button. 13 | ![image](https://user-images.githubusercontent.com/79626459/185387601-f140bb81-cc86-4f72-9bcc-133e49b045d4.png) 14 | 15 | * It shows in red if any form is missing. Click 'Fix Issues' to recreate the form. 16 | ![image](https://user-images.githubusercontent.com/79626459/185387814-fd927508-6aaa-461e-ba5f-091697983fb3.png) 17 | 18 | * Check issues again, and the form is now restored. In the library, the version history can also be displayed. 19 | ![image](https://user-images.githubusercontent.com/79626459/185388212-eb19456e-d34b-4a94-beb3-d91f79eaf9e9.png) 20 | ![image](https://user-images.githubusercontent.com/79626459/185388402-ac9e8d21-a5b0-42df-809d-1d12bc7f6209.png) 21 | 22 | ## More Information 23 | 24 | The feature requires 'custom script' to be allowed. Reference: https://docs.microsoft.com/en-us/sharepoint/allow-or-prevent-custom-script#to-allow-custom-script-on-other-sharepoint-sites 25 | -------------------------------------------------------------------------------- /Documents/OneDriveLockIcon.md: -------------------------------------------------------------------------------- 1 | # OneDrive Lock Icon 2 | ## Summary 3 | The OneDrive lock icon issue can be caused by a lot of settings, sometimes the support engineer and tenant admin may forget to check some settings, so we developed this feature for helping support engineer and tenant admin to check related settings quickly. 4 | ![image](https://user-images.githubusercontent.com/21354416/184605424-eeec9045-3c92-47d9-a48b-59a911635289.png) 5 | ![image](https://user-images.githubusercontent.com/21354416/184605204-1e59830a-3148-4a54-9f52-64a49c1925ed.png) 6 | 7 | ## Example 8 | * Select the "OneDrive lock icon", fill the affected user and affected site, select the affected library, 9 | ![image](https://user-images.githubusercontent.com/21354416/184606521-9fcc4569-1e0b-4748-a8a6-5593e116c8df.png) 10 | * Click "Check Issues" button and wait for checking complete, 11 | ![image](https://user-images.githubusercontent.com/21354416/184607017-b725515a-4400-488a-afc9-44f1fb0c6a67.png) 12 | * Check detected issues (in red) and click "Show Remedy Steps" button for checking remedy steps, 13 | ![image](https://user-images.githubusercontent.com/21354416/184607370-46f38c99-da26-4301-b591-c793df684a3f.png) 14 | * Open the link in the remedy step in new tab and fix the settings (e.g. in this demo, need to remove the validation message and turn on the "Offline Client Availability") accordingly, 15 | ![image](https://user-images.githubusercontent.com/21354416/184607690-06191f4b-4fcc-402b-abc5-3f3ed8e25ab2.png) 16 | ![image](https://user-images.githubusercontent.com/21354416/184607787-1fbc96e8-6a5c-4e6a-a2e0-1fc02fb04259.png) 17 | 18 | ## More Information 19 | This feature will check below settings, 20 | * Offline Client Availability for the library has been set to true. 21 | * Require Check Out for the library has been set to false. 22 | * Draft Item Security of this library has been set to Any user who can read items. 23 | * Content Approval of this library has been set to false. 24 | * Validation formula/message of this library is null/null. 25 | * Validation formula/message of all columns are null/null. 26 | * The "Offline Client Availability" of the site(including parent sites) has been set to false. 27 | * Limited-access user permission lockdown mode of the site collection hasn't been enabled. 28 | * The affected user has enough permission to edit the library. 29 | -------------------------------------------------------------------------------- /Documents/Privacy/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy for the SPOQA(SharePoint Online Quick Assist tool) 2 | 3 | * [Microsoft Privacy Statement – Microsoft privacy](https://privacy.microsoft.com/en-us/privacystatement) 4 | 5 | This privacy policy’s been written to serve those who are concerned with how their ‘Personally identifiable information’ (PII) is being used. Please read our privacy policy to get a clear understanding of how we , use, collect, protect or otherwise handle your Personally Identifiable Information in accordance with our website and all other products. 6 | 7 | Please read the following “Privacy Policy” to understand how we collect, use and safeguard the personal data you (or the entity with which you are associated) may provide to us via our Add-ins. This Privacy Policy may be revised from time to time, so please revisit this page often to remain fully informed of our policies. 8 | 9 | By accepting this “Privacy Policy”, you provide consent to the collection and use of all information as set forth in this Privacy Policy.If you do not agree to the terms of this Privacy Policy, please do not use SPOQA & Websites. 10 | 11 | 12 | **1. Personal Data We Collect** 13 | 14 | We do not collect any Personal Data in the SPOQA(SharePoint Online Quick Assist tool). 15 | 16 | 17 | 18 | **2. How We Use Personal Data** 19 | 20 | We do not collect and use any Personal Data in the SPOQA(SharePoint Online Quick Assist tool). 21 | 22 | 23 | 24 | **3. Do we share Personal Data?** 25 | 26 | We do not collect and share your personal data with Advertisement providers or any third parties. 27 | 28 | 29 | 30 | **4. How do we protect visitor information?** 31 | 32 | Our apps are scanned on a regular basis for security holes and known vulnerabilities in order to make your visit to our app as safe as possible. We use regular Malware Scanning. If you suspect unauthorized access to your data, please contact us. 33 | 34 | We do not have any commercial/non-profit advertisements on our site or apps. 35 | 36 | 37 | 38 | **5. Third Party Disclosure?** 39 | 40 | We do not disclose or offer your confidential information to any third parties or services. 41 | 42 | 43 | 44 | **6. Changes to These Terms of Use** 45 | 46 | SPOQA reserves the right to change these Terms of Use at any time by posting new Terms of Use at this location. If there are any questions regarding this privacy policy, you may contact us at SPOQA@service.microsoft.com 47 | 48 | 49 | -------------------------------------------------------------------------------- /Documents/ReadMe.md: -------------------------------------------------------------------------------- 1 | 1. This folder stores documents about this tool. 2 | 3 | -------------------------------------------------------------------------------- /Documents/RestoreItems.md: -------------------------------------------------------------------------------- 1 | # Restore Items 2 | ## Summary 3 | A lot of users complain about they can't filter and restore items from recycle bin in SharePoint Online, so we developed this feature which allow user to filter/restore/export items from SharePoint Online recycle bin. 4 | 5 | ## Example 6 | * Filter the items from recycle bin by delete date, delete by, path, 7 | 8 | ![image](https://user-images.githubusercontent.com/21354416/155688589-199fc965-1333-4073-82b6-677444497a36.png) 9 | 10 | * After filtering items, user can restore all filtered items by clicking the restore button, 11 | ![image](https://user-images.githubusercontent.com/21354416/155689019-f91ba251-aace-4671-8c6a-60d489debc87.png) 12 | 13 | * After filtering items can export filtered items by clicking export button, 14 | ![image](https://user-images.githubusercontent.com/21354416/155689228-e8bc0d3b-1cf6-4b48-904a-c23cfcfa3e83.png) 15 | 16 | * The skip option for existing items when restoring has been added into "Restore Items", 17 | ![image](https://user-images.githubusercontent.com/21354416/184311082-8e61bc09-ca96-46d2-92db-f4ff4d5ea0b6.png) 18 | ![image](https://user-images.githubusercontent.com/21354416/184311738-a63cb573-f6c6-4fc7-ad98-25e1527f7631.png) 19 | 20 | * By default this option is off, it will affect the performance if there are some large libraries need to be scanned. 21 | * If this option is off, then existing column will be filled as false by default, but please remember that it is just mean the tool haven’t checked it. 22 | * When the option is selected, existing items will be skipped when restoring, 23 | ![image](https://user-images.githubusercontent.com/21354416/184311656-e4649ac6-4e4c-457b-bc0e-fb39ae5a2efd.png) 24 | 25 | 26 | * If some items are existing but the option is not enable then it may cause error message when restoring, 27 | ![image](https://user-images.githubusercontent.com/21354416/184311583-e26fa5c0-4254-4849-8af2-e203105033c4.png) 28 | 29 | ## More Information 30 | * Queried xxx items means there are totally xxx items in the first and second recycle bins of the site 31 | * Filtered xxx items means there are xxx matched these filters 32 | * Skipped xxx items (existing) means there are xxx items already existing, they are skipped when restoring 33 | -------------------------------------------------------------------------------- /Documents/SearchSpecificDocument.md: -------------------------------------------------------------------------------- 1 | # Search issue for a specific document 2 | 3 | ## Summary 4 | This feature helps user fix the issue when a specific document does not appear in the search results 5 | 6 | ## Example 7 | 8 | * Enter the affected site url and select the affected list/library. Then enter the full URL/path (for how to get full url please chck this [link](https://github.com/abrcheng/SharePointOnlineQuickAssist/tree/main/Documents/How%20to%20collect%20display%20url%20for%20files%20and%20list%20items))of the affected document. Click 'Check Issues' button. 9 | ![image](https://user-images.githubusercontent.com/21354416/184611775-f1e9e4f7-d02e-44f2-a384-5cd495da783d.png) 10 | 11 | * In this example, it detected that the library's nocrawl was enabled. Just click 'Show Remedy Steps' and it will show remedy steps, 12 | ![image](https://user-images.githubusercontent.com/21354416/184611984-bc0285ba-e794-4e53-8ef5-1b50a9ae2880.png) 13 | 14 | * Open the link in the remedy step in new tab and fix the settings (e.g. in this demo, need to trun off the no crawl in list advanced settings ) accordingly, 15 | ![image](https://user-images.githubusercontent.com/21354416/184612372-d2109f4f-1379-4b12-82fc-912e77a9b0d7.png) 16 | 17 | * And the crawl log can be checked by below , 18 | 19 | ![image](https://user-images.githubusercontent.com/21354416/171319876-02339ed1-8015-4a8f-9043-da93c89d99da.png) 20 | 21 | * If the document can be searched, will show all managed properties, 22 | ![image](https://user-images.githubusercontent.com/21354416/171320028-d9aab9f0-1f68-4841-b9e9-d4108ce75f46.png) 23 | 24 | * If the document can be searched, will show all crawled properties as well 25 | 26 | * These properties can be filtered and exported, 27 | ![image](https://user-images.githubusercontent.com/21354416/171320213-d81bd049-485a-4eb2-a6e5-583eb15c29b4.png) 28 | ![image](https://user-images.githubusercontent.com/21354416/171320278-a718070a-7d26-441d-8e8c-e6dcc6044bcf.png) 29 | ![image](https://user-images.githubusercontent.com/21354416/171320453-162bd9ef-1912-4b2e-9e45-630f8014ea49.png) 30 | 31 | ## More Information 32 | 33 | The feature diagnoses and fixes the issue as follows: 34 | 35 | * The site's Nocrawl is enabled 36 | * The affected library/list's Nocrawl is enabled 37 | * The DispForm.aspx of the affected library/list is missing 38 | * The affected document is having no major version 39 | * Crawl log of the document (need to grant permssion according to https://docs.microsoft.com/en-us/sharepoint/set-crawl-log-permissions) 40 | * All managed properties of the document if the doucment can be searched 41 | * All crawled properties of the document if the doucment can be searched 42 | -------------------------------------------------------------------------------- /Documents/SearchSpecificSite.md: -------------------------------------------------------------------------------- 1 | # Search issue for a specific document 2 | 3 | ## Summary 4 | This feature helps user fix the issue when a specific document does not appear in the search results 5 | 6 | ## Example 7 | 8 | * Enter the affected site url. Click 'Check Issues' button. 9 | ![image](https://user-images.githubusercontent.com/79626459/185375892-fe9ec6cc-a8d5-4d7b-a335-bf79d9643fdc.png) 10 | 11 | * Example 1: the site is searchable 12 | ![image](https://user-images.githubusercontent.com/79626459/185376703-5fa27117-f267-441d-aa2b-82b05e88e8dc.png) 13 | 14 | * If the site can be searched, will show the managed properties and crawled properties. 15 | ![image](https://user-images.githubusercontent.com/79626459/185382866-e932a93c-1b62-45ee-b9a8-5663269e1994.png) 16 | 17 | * These properties can be filtered and exported. 18 | * ![image](https://user-images.githubusercontent.com/79626459/185383097-d9cef95f-fa7f-40a6-9a02-627f880d0542.png) 19 | 20 | * Example 2: the site cannot be searched. It detected that 'Search and Offline Availability' is set to 'No'. And the user is not in the 'Members' group. It's suggested to follow the remedy steps in new tab and fix the issue. 21 | ![image](https://user-images.githubusercontent.com/79626459/185377239-370380a8-5254-4395-bb76-1f22a77fc11d.png) 22 | 23 | * The crawl logs can be checked by clicking 'Show Crawl Logs'. 24 | ![image](https://user-images.githubusercontent.com/79626459/185380691-5eb48fd0-d7b6-428b-a3b1-018aeb6b0f66.png) 25 | 26 | ## More Information 27 | 28 | The feature diagnoses and fixes the issue as follows: 29 | 30 | * The site's and its sub/parent sites Nocrawl are enabled 31 | * The user has permissions to the site 32 | * If the site is a group site, check if the user is in the 'Members' group 33 | * Crawl log of the site (need to grant permssion according to https://docs.microsoft.com/en-us/sharepoint/set-crawl-log-permissions) 34 | * All managed properties of the site if it can be searched 35 | * All crawled properties of the site if it can be searched 36 | -------------------------------------------------------------------------------- /Documents/SupportContacts: -------------------------------------------------------------------------------- 1 | In case you encounter any issues using our tool, you can reach support by emailing to SPOQA@service.microsoft.com. 2 | You can also raise your issue to https://github.com/abrcheng/SharePointOnlineQuickAssist/issues. 3 | -------------------------------------------------------------------------------- /Documents/UneditableClassicWiki.md: -------------------------------------------------------------------------------- 1 | # Un-editable Classic Wiki 2 | 3 | ## Summary 4 | This feature helps user to detect classic wiki page's layout issue which cause the whole page including the ribbon menu being non-interactive in edit mode. 5 | [More Details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/KBs/UneditableClassicWiki/ReadMe.md) 6 | 7 | ## Usage 8 | Input the page URL and click [Check Issues]. 9 | 10 | ## Example 11 | The feature will detect the page layout by parsing HTML elements and compare the detected layout to page's layout declaration. 12 | In the example below, the page layout was detected as "Three column with header and footer" while the layout declaration was not a valid value. 13 | ![image](https://user-images.githubusercontent.com/102142347/185521576-23b73935-b74f-4f2e-aa70-d2dc8e4041dc.png) 14 | -------------------------------------------------------------------------------- /Documents/UserInfoSyncIssue.md: -------------------------------------------------------------------------------- 1 | # User Info Sync Issue 2 | 3 | ## Summary 4 | This feature helps user diagnose if 'user info sync' is having sync issues, e.g. Display name, Email, JobTitle and WorkPhone. 5 | 6 | ## Example 7 | 8 | Enter the affected site url and user principle name. Click 'Check Issues'. 9 | ![image](https://user-images.githubusercontent.com/89838160/184843976-cc24f681-8191-43a0-a0cd-83a6b8a4e179.png) 10 | 11 | In this example, the user's job title in user info list is incorrect. Just click 'Fix it' and it will be fixed automatically. 12 | ![image](https://user-images.githubusercontent.com/89838160/185015931-53aec48b-e691-49c0-8d39-3f54a1af07c1.png) 13 | 14 | ![image](https://user-images.githubusercontent.com/89838160/185016030-6b0af27a-edd9-4a14-bad8-e5bfd295d7e0.png) 15 | -------------------------------------------------------------------------------- /Documents/UserPhotoSync.md: -------------------------------------------------------------------------------- 1 | # User Photo sync issue 2 | 3 | ## Summary 4 | This feature helps user diagnose if 'User Photo' is having sync issues. 5 | 6 | ## Example 7 | 8 | Enter the user principle name. Click 'Check Issues'. 9 | 10 | ![image](https://user-images.githubusercontent.com/89838160/184840157-3cee8a3b-8c88-4ec6-b496-c6beb66ac50a.png) 11 | 12 | 13 | In this example, the user's photo in AAD and SPO is mismatch. But it cannot be recognized by tool and it shows the remedy steps. 14 | 15 | ![image](https://user-images.githubusercontent.com/89838160/184839731-32ab9d66-5f5b-4ad4-8cda-8e86b5aadd70.png) 16 | 17 | "Photos are loaded, but if they are mismatched, please follow this article" https://github.com/abrcheng/SharePointOnlineQuickAssist/tree/main/KBs/UAP/SyncPhotoFromADToSPO 18 | -------------------------------------------------------------------------------- /KBs/List/UpdateListReadWriteSecurity.ps1: -------------------------------------------------------------------------------- 1 | #Set Parameters 2 | $SiteURL = "https://xxxxx.sharepoint.com/sites/xxxxx" 3 | $ListName = "xxxxxxx" 4 | 5 | #Connect to SharePoint Online site 6 | Connect-PnPOnline -Url $SiteURL -Interactive 7 | 8 | #Get the List 9 | $List = Get-PnPList $ListName -Includes ReadSecurity 10 | 11 | #Set List Item-Security 12 | $List.ReadSecurity = 1 13 | $List.WriteSecurity = 1 14 | $List.Update() 15 | Invoke-PnPQuery 16 | -------------------------------------------------------------------------------- /KBs/Migration/DocumentID/ReadMe.md: -------------------------------------------------------------------------------- 1 | **Symptoms,** 2 | 3 | The document ID may can't be generated in time after migrating a lot of documents to SharePoint Online (SPO) 4 | ![image](https://user-images.githubusercontent.com/21354416/136787754-26aec0cc-d938-4791-8691-902b2bc4e8cb.png) 5 | 6 | 7 | **Cause,** 8 | 9 | The SPO DocID assignment job is a async timer job process and runs for a set duration in the day. It is shared across all customers in that farm. So there is no guarantee on how many day/months it will take if there are millions of documents and there is no quick backend way to assign the Ids. 10 | 11 | **Solution,** 12 | 13 | Run the script TouchDocumentIds.ps1 for trigger the document ID assignment, please note this script will trigger the workflow or PowerAutomate flow which associated with the library, 14 | ![image](https://user-images.githubusercontent.com/21354416/136777288-e358cfb0-ce05-4ed6-ac76-c4b2a11e8bc3.png) 15 | ![image](https://user-images.githubusercontent.com/21354416/136777331-99c63615-43cf-4dd3-9a49-537dd239eaff.png) 16 | 17 | And you can run it in parallel for different libraries if necessary. 18 | Then run the script GetDocIDReport.ps1 for getting document ID assignment report, 19 | 20 | ![image](https://user-images.githubusercontent.com/21354416/136783341-44fd2dcb-72b8-4be0-9b74-04e28cb462d5.png) 21 | ![image](https://user-images.githubusercontent.com/21354416/136777527-9272041f-e728-4a9c-95a2-7455195eeb72.png) 22 | ![image](https://user-images.githubusercontent.com/21354416/136787999-dcf1e0e3-9280-4e78-bded-0cec93e82136.png) 23 | 24 | **Notes,** 25 | 1. These two scripts are depended on SharePoint Online PnP PowerShell https://docs.microsoft.com/en-us/powershell/sharepoint/sharepoint-pnp/sharepoint-pnp-cmdlets 26 | 2. These two scripts are provided "AS IS" 27 | -------------------------------------------------------------------------------- /KBs/Migration/DocumentID/TouchDocumentIds.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 3 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 4 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 5 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 6 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 7 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 8 | # THE SOFTWARE. 9 | # 10 | # Filename: TouchDocumentIds.ps1 11 | # Description: Performs an update on the documents triggering the event receiver to assign document ids. 12 | # Output: 13 | # 1. TouchDocumentIdsErrorMessage.txt, if there is any error message when executing the script will be logged 14 | # 2. TouchDocumentIdsFailedFiles.txt, if there is any files failed to be processed will be logged 15 | # Paramters: 16 | # 1. siteUrl, the site URL(e.g. https://chengc.sharepoint.com/sites/abc) whicn need to be processed 17 | # 2. listTitle, the title of the list which need to be processed 18 | # 3. batchSize, number of the changes need to be submited in a batch 19 | # Please Note: This script will trigger the workflow or PowerAutomate flow which associated with the library 20 | ################################################################################## 21 | [Cmdletbinding()] 22 | Param ( 23 | [Parameter(mandatory=$true)] # SiteUrl e.g. https://chengc.sharepoint.com/sites/abc 24 | [String] $siteUrl, 25 | [Parameter(mandatory=$true)] 26 | [String]$listTitle, # Library title, e.g. Documents 27 | [Parameter(mandatory=$true)] 28 | [int]$batchSize =10 29 | ) 30 | 31 | Connect-PnPOnline $siteUrl 32 | [Microsoft.SharePoint.Client.ClientContext] $clientContext = Get-PNPContext 33 | 34 | # Set time out to 10 minutes 35 | $clientContext.RequestTimeout = 1000*60*10; 36 | $startTime = $([System.DateTime]::Now) 37 | Write-Host "start time:$($startTime)" 38 | $listItePosition = New-Object Microsoft.SharePoint.Client.ListItemCollectionPosition 39 | $listItePosition.PagingInfo = "" 40 | $caml = " 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 1000 50 | " 51 | 52 | $oQuery = New-Object Microsoft.SharePoint.Client.CamlQuery 53 | $oQuery.ViewXml = $caml 54 | $totalProcessedCount = 0 55 | $list = $clientContext.Web.Lists.GetByTitle($listTitle) 56 | 57 | $assigned =0 58 | $errorCount=0 59 | do 60 | { 61 | $currentBatchUnSumbitCount =0 62 | $oQuery.ListItemCollectionPosition = $listItePosition 63 | $items = $list.GetItems($oQuery) 64 | $clientContext.Load($items) 65 | $clientContext.ExecuteQuery() 66 | $itemCount = $items.Count 67 | $totalProcessedCount = $totalProcessedCount + $itemCount 68 | Write-Host "Get $itemCount items from the list/library $libName" 69 | for($index=$itemCount -1; $index -ge 0; $index--) 70 | { 71 | $currentItem = $items[$index] 72 | $url = $currentItem["FileRef"] 73 | if($currentItem.FileSystemObjectType -eq [Microsoft.SharePoint.Client.FileSystemObjectType]::File -and $currentItem["_dlc_DocId"] -eq $null) 74 | { 75 | Write-Host "Processing $url" 76 | $currentItem.SystemUpdate() 77 | $assigned++ 78 | $currentBatchUnSumbitCount++ 79 | 80 | } 81 | else 82 | { 83 | Write-Host "Skip $url as it is not a file or document ID has been assigned" 84 | } 85 | 86 | if($currentBatchUnSumbitCount -eq $batchSize -or ($index -eq 0 -and $currentBatchUnSumbitCount -gt 0)) 87 | { 88 | try 89 | { 90 | $clientContext.ExecuteQuery() 91 | } 92 | catch [System.Exception] 93 | { 94 | $exceptionMessage = $_.Exception.ToString() 95 | $errorMessage = "Get error message $exceptionMessage when processing $url" 96 | Write-Host $errorMessage -ForegroundColor Red 97 | $errorMessage >>"TouchDocumentIdsErrorMessage.txt" 98 | $url >> "TouchDocumentIdsFailedFiles.txt" 99 | $errorCount++ 100 | 101 | # Wait for 10 seconds and retry again 102 | [System.Threading.Thread]::Sleep(10*000) 103 | $clientContext.ExecuteQuery() 104 | $ignoreMessage = "Retry successful, this error can be ignored" 105 | $ignoreMessage >>"TouchDocumentIdsErrorMessage.txt" 106 | Write-Host $ignoreMessage -ForegroundColor Green 107 | } 108 | 109 | $currentBatchUnSumbitCount =0 110 | } 111 | } 112 | 113 | $listItePosition = $items.ListItemCollectionPosition 114 | } While($listItePosition -ne $null) 115 | 116 | Write-Host "end time:$([System.DateTime]::Now)" 117 | Write-Host "Updated $assigned documents with $errorCount errors" 118 | $totalMinutes = [int]([System.DateTime]::Now -$startTime).TotalMinutes 119 | Write-Host "End time:$([System.DateTime]::Now), duration is $totalMinutes minutes" 120 | Write-Host "Done." -ForegroundColor Green 121 | -------------------------------------------------------------------------------- /KBs/ReadMe.md: -------------------------------------------------------------------------------- 1 | 1. This folder stores KBs for fixing the detected SPO known issues. 2 | 2. Each KB need to create a new folder. 3 | 3. Please add the ReadMe.txt and scripts in the KB folder. 4 | -------------------------------------------------------------------------------- /KBs/Restore/RestoreWithPNPRESTAPI.ps1: -------------------------------------------------------------------------------- 1 | $StartDate = "2019/01/24 9:00:00" 2 | $EndDate = "2019/01/25 9:00:00" 3 | $SiteURL = "https://chengc.sharepoint.com" 4 | 5 | Connect-PnPOnline $SiteURL 6 | 7 | $DeletedCollection = Get-PnPRecyclebinItem -RowLimit 500 | ? { ($_.DeletedByEmail -eq 'UserEmailID') -and ($_.DeletedDate -ge $StartDate) -and ($_.DeletedDate -le $EndDate)} 8 | 9 | $ctx = Get-PnPContext 10 | 11 | 12 | foreach($DeletedItem in $DeletedCollection) 13 | { 14 | Try 15 | { 16 | Write-host "Initiating Restore for: " $DeletedItem.Title 17 | $RestoreURL = $SiteURL+"/_api/web/Recyclebin('$($DeletedItem.ID)')/restore()" 18 | Invoke-PnPSPRestMethod -Method post -Url $RestoreURL 19 | 20 | Write-host "Restore Completed for: " $DeletedItem.Title 21 | Write-Host -ForegroundColor Green "Success :: File is successfully restored" 22 | Write-host "Writing to log file.................____________________________________________ " $Successcount 23 | $Successcount++ 24 | } 25 | Catch 26 | { 27 | Write-host "Exception for: " $DeletedItem.Title 28 | $errormessage = "Catch Error:" + $_.Exception.Message 29 | Write-host "Writing to log file.................____________________________________________ " $FailureCount 30 | $FailureCount++ 31 | Write-Host -ForegroundColor Red "Catch :: There is an error while restoring the Document" $_.Exception.Message 32 | Continue 33 | } 34 | } 35 | 36 | Write-Host -ForegroundColor DarkGreen "Success Count: " + $Successcount 37 | Write-Host -ForegroundColor DarkRed "Failure Count: " + $FailureCount 38 | -------------------------------------------------------------------------------- /KBs/TermStore/UpdateTermOwner/ReadMe.md: -------------------------------------------------------------------------------- 1 | ReadMe -------------------------------------------------------------------------------- /KBs/TermStore/UpdateTermOwner/UpdateTermOwner.ps1: -------------------------------------------------------------------------------- 1 | Connect-PnPOnline https://contoso.sharepoint.com -UseWebLogin 2 | $TermGroupName = "Site Collection - contoso.sharepoint.com" 3 | $TermSetName= "SiteMM" 4 | $TermSetOwner= "i:0#.f|membership|johna@contoso.com" 5 | $processedCount = 0 6 | 7 | $Ctx = Get-PnPContext 8 | $TaxonomySession = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($Ctx) 9 | $TaxonomySession.UpdateCache() 10 | $Ctx.Load($TaxonomySession) 11 | 12 | $TermStore = $TaxonomySession.GetDefaultSiteCollectionTermStore() 13 | $Ctx.Load($TermStore) 14 | $Ctx.ExecuteQuery() 15 | 16 | $TermGroup = $TermStore.Groups.GetByName($TermGroupName) 17 | $Ctx.Load($TermGroup) 18 | 19 | #Get the termset 20 | $TermSet = $TermGroup.TermSets.GetByName($TermSetName) 21 | $Ctx.Load($TermSet) 22 | $Ctx.ExecuteQuery() 23 | 24 | $terms = $TermSet.GetAllTerms() 25 | $Ctx.Load($terms) 26 | $Ctx.ExecuteQuery() 27 | 28 | foreach($term in $terms) 29 | { 30 | Write-Host "Processing $($term.Name) ....." 31 | $term.Owner = $TermSetOwner 32 | $processedCount++ 33 | } 34 | 35 | $TermStore.CommitAll() 36 | $Ctx.ExecuteQuery() 37 | Write-host "Processed $processedCount terms, Done" -ForegroundColor Green -------------------------------------------------------------------------------- /KBs/UAP/SyncPhotoFromADToSPO(21-Viaent)/ReadMe.md: -------------------------------------------------------------------------------- 1 | This script is used for syncing user properties from ADD to SharePoint Online user profile. 2 | 3 | It will sync below propeties by default, 4 | "Department","GivenName","Surname","DisplayName","telephoneNumber","JobTitle". 5 | 6 | And if you need to sync WorkMail and Manager, then need to add the addtional parameters (-SyncWorkMail $true -SyncManager $true) 7 | **It neeed to be run by SharePoint Online tenant admin.** 8 | 9 | 10 | 1. Start PowerShell as administrator and install the SharePoint PNP and Azure AD PowerShell Module 11 | 12 | a. Install-Module -Name AzureAD 13 | 14 | b. Uninstall-Module -Name "SharePointPnPPowerShellOnline" 15 | 16 | c. Install-Module -Name "PnP.PowerShell" 17 | 18 | d. If the computer doesn't allow to run PowerShell script, allow it by running Set-ExecutionPolicy according to https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7.2 19 | 20 | 2. Download the script **SyncUserPropertiesFromAADToSPOProfile.ps1** to local drive 21 | 22 | 3. Run the script as below for China 21v enviroment (please repalce the place holder contonso), 23 | 24 | .\SyncUserPropertiesFromAADToSPOProfile.ps1 -AdminSiteURL https://contonso-admin.sharepoint.cn -IsChinaCloud $true 25 | ![image](https://user-images.githubusercontent.com/21354416/167838200-e946942d-2306-48d8-8c98-80a9d665384f.png) 26 | 27 | 28 | 4. Run the script as below for Global enviroment (please repalce the place holder contonso), 29 | 30 | .\SyncUserPropertiesFromAADToSPOProfile.ps1 -AdminSiteURL https://contonso-admin.sharepoint.com 31 | 32 | 33 | ** If don't want to sync, just want to bulk update some user profile proerty (e.g. set OfficeGraphEnabled to true for all users), try below command ** 34 | 35 | 36 | .\SyncUserPropertiesFromAADToSPOProfile.ps1 -AdminSiteURL https://chengc-admin.sharepoint.com -PropertyName "OfficeGraphEnabled" -PropertyValue $true 37 | ![image](https://user-images.githubusercontent.com/21354416/170006748-8db3a84c-3e8b-4859-bdf8-f9edc3850f7b.png) 38 | ![image](https://user-images.githubusercontent.com/21354416/170006873-407ceabf-fd58-489a-acd7-83063ef1a3b1.png) 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /KBs/UAP/SyncPhotoFromADToSPO(21-Viaent)/SyncPhotoFromADToSPO(21-Viaent).ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(mandatory=$true)] 3 | [string]$mySiteHostSiteUrl = "https://chengc-my.sharepoint.com", 4 | [Parameter(mandatory=$true)] 5 | [string]$usersListFile = "D:\files\photos\UsersListFile.txt", 6 | [Parameter(mandatory=$true)] 7 | [string]$photoPath = "D:\files\photos\Photos", 8 | [Parameter(mandatory=$false)] 9 | [bool]$updateExo = $false , 10 | [Parameter(mandatory=$true)] 11 | [string]$ClientID = "140fc0dd-5f99-4e62-9925-e96c967b52f7", 12 | [Parameter(mandatory=$true)] 13 | [string]$TenantID = "aef7fc64-a1e0-4704-affa-d4fca539e508", 14 | [Parameter(mandatory=$true)] 15 | [string]$CertificateThumbprint = "1DEE9AD4BFC8757A55660110F04CD3EB6087B1E2" 16 | 17 | ) 18 | 19 | # connect AAD for get the users's ThumbnailPhoto by commmand Get-AzureADUserThumbnailPhoto -ObjectId "CVDu@chengc.onmicrosoft.com" 20 | 21 | 22 | # https://pnp.github.io/powershell/articles/authentication.html#authentication-to-gcc-or-national-cloud-environments 23 | 24 | Connect-MgGraph -Environment China -AppId $ClientID -TenantId $TenantID -CertificateThumbprint $CertificateThumbprint 25 | 26 | # Connect to exchange online 27 | if($updateExo) 28 | { 29 | Connect-ExchangeOnline 30 | } 31 | 32 | # Connect to the for uploading photos and update user profile 33 | $adminSiteUrl = $mySiteHostSiteUrl.Replace("-my", "-admin") 34 | $photoFolderUrl = "/User Photos/Profile Pictures/" 35 | $users = Get-Content $usersListFile 36 | # Update: Clear cached credential to connect to site 37 | Connect-PnPOnline $adminSiteUrl -UseWebLogin 38 | $adminCtx = Get-PnPContext 39 | $null = Get-PnPUserProfileProperty -Account $users[0] # load Microsoft.SharePoint.Client.UserProfiles 40 | 41 | Connect-PnPOnline $mySiteHostSiteUrl -UseWebLogin 42 | $ctx = Get-PnPContext 43 | 44 | $peopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($adminCtx) 45 | 46 | function GeneratetThumbnail($filePath, $baseFilename) 47 | { 48 | $full = [System.Drawing.Image]::FromFile($filePath) 49 | 50 | $midThumb = $full.GetThumbnailImage(72, 72, $null, [intptr]::Zero) 51 | $midPath = "$photoPath\$baseFilename"+"_MThumb.jpg" 52 | $midThumb.Save($midPath); 53 | 54 | $smallThumb = $full.GetThumbnailImage(48, 48, $null, [intptr]::Zero) 55 | $smallPath = "$photoPath\$baseFilename"+"_SThumb.jpg" 56 | $smallThumb.Save($smallPath) 57 | 58 | $largeThumb = $full.GetThumbnailImage(300, 300, $null, [intptr]::Zero) 59 | $largePath = "$photoPath\$baseFilename"+"_LThumb.jpg" 60 | $largeThumb.Save($largePath) 61 | 62 | $full.Dispose() 63 | $midThumb.Dispose() 64 | $midThumb.Dispose() 65 | $largeThumb.Dispose() 66 | } 67 | 68 | foreach($user in $users) 69 | { 70 | try 71 | { 72 | Write-Host "Processing $user" 73 | #$null = Get-AzureADUserThumbnailPhoto -ObjectId $user -FilePath $photoPath -ErrorAction Stop 74 | #$apiUrl = "https://microsoftgraph.chinacloudapi.cn/v1.0/users/$user/photo/`$value" 75 | #Invoke-RestMethod -Headers @{Authorization = "Bearer $accessToken"} -Uri $apiUrl -Method Get -ContentType image/jpeg -OutFile $photoPath\$user.jpg 76 | $UserID = Get-MgUser -Filter "startsWith(UserPrincipalName, '$user')" -Top 1|select ID 77 | Get-MgUserPhotoContent -UserId $userID.Id -OutFile $photoPath\$user.jpg 78 | 79 | $file = Get-ChildItem -Path $photoPath -Filter "$user*" 80 | if($file.FullName -ne $empty) 81 | { 82 | $baseFilename = $user.Replace(".", "_").Replace("@","_") 83 | GeneratetThumbnail -filePath $file.FullName -baseFilename $baseFilename 84 | 85 | if($updateExo) 86 | { 87 | Set-UserPhoto -Identity $user -PictureData ([System.IO.File]::ReadAllBytes("$($photoPath)\$($baseFilename)_SThumb.jpg")) -Confirm:$false 88 | } 89 | 90 | $thumbnails = Get-ChildItem -Path $photoPath -Filter "$baseFilename*" 91 | foreach($thumbnail in $thumbnails) 92 | { 93 | Write-Host "Uploading $($thumbnail.FullName)......" 94 | $null = Add-PnPFile -Path $thumbnail.FullName -Folder $photoFolderUrl -ErrorAction Stop 95 | } 96 | 97 | $fullPictureUrl = $mySiteHostSiteUrl + $photoFolderUrl + $baseFilename + "_MThumb.jpg" 98 | $uploadedPicture = Get-PnPFile $fullPictureUrl 99 | if($uploadedPicture.Length -gt 0) 100 | { 101 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "PictureUrl", $fullPictureUrl) 102 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PicturePlaceholderState", 0) 103 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PictureExchangeSyncState", 1) 104 | $adminCtx.ExecuteQuery() 105 | } 106 | } 107 | else 108 | { 109 | $errorMessage = "Failed to get the user's photo when processing $($user) " 110 | Write-Host $errorMessage 111 | $errorMessage >>"ErrorMessage.txt" 112 | $user >> "FailedUsers.txt" 113 | } 114 | 115 | } 116 | catch [System.Exception] 117 | { 118 | $exceptionMessage = $_.Exception.ToString() 119 | $errorMessage = "Get error message $exceptionMessage when processing $($user)" 120 | Write-Host $errorMessage 121 | $errorMessage >>"ErrorMessage.txt" 122 | $user >> "FailedUsers.txt" 123 | } 124 | } 125 | 126 | Write-Host "Done!" -ForegroundColor Green -------------------------------------------------------------------------------- /KBs/UAP/SyncPhotoFromADToSPO/GetUsersWithOutPictureInSPO.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [string]$adminSiteUrl = "https://chengc-admin.sharepoint.com" 3 | ) 4 | 5 | Connect-PnPOnline -Url $adminSiteUrl -UseWebLogin 6 | $clientContext = Get-PnPContext 7 | Connect-AzureAD 8 | $allUsers = Get-AzureADUser -all $true 9 | $userCount =0 10 | foreach($user in $allUsers) 11 | { 12 | if($user.UserPrincipalName.Contains("#EXT#") -ne $true) 13 | { 14 | Write-Host "Processing $($user.UserPrincipalName)" 15 | try 16 | { 17 | $Properties = Get-PnPUserProfileProperty -Account $user.UserPrincipalName 18 | if([System.String]::IsNullOrWhiteSpace($Properties.PictureUrl)) 19 | { 20 | Write-Host $user.UserPrincipalName 21 | $user.UserPrincipalName >>"UsersWithOutPictureInSPO.txt" 22 | $userCount++ 23 | } 24 | } 25 | catch [System.Exception] 26 | { 27 | $errormessage = $_.Exception.ToString() 28 | "Get error message $errormessage when processing $($user.UserPrincipalName) \r\n" >>"ErrorMessage.txt" 29 | } 30 | } 31 | } 32 | 33 | Write-Host "Detected $userCount users without picture in the SPO user profile, please check UsersWithOutPictureInSPO.txt for detail" 34 | Write-Host "Done" -ForegroundColor Green 35 | -------------------------------------------------------------------------------- /KBs/UAP/SyncPhotoFromADToSPO/ReadMe.md: -------------------------------------------------------------------------------- 1 | This script used for syncing user pictures from AAD to SharePoint online user profile. 2 | 3 | **It neeed to be run by SharePoint online tenant admin.** 4 | 5 | 6 | 1. Start PowerShell as administrator and install the SharePoint PNP and Azure AD PowerShell Module 7 | 8 | a. Install-Module -Name AzureAD 9 | 10 | b. Uninstall-Module -Name "PNP.PowerShell" 11 | 12 | c. Uninstall-Module -Name "SharePointPnPPowerShellOnline" 13 | 14 | d. Install-Module -Name "SharePointPnPPowerShellOnline" -RequiredVersion 3.20.2004.0 15 | 16 | 2. If you need to update the Photo in Exchange online(EXO) as well, then install the EXO PowerShell according to https://docs.microsoft.com/en-us/powershell/exchange/connect-to-exchange-online-powershell?view=exchange-ps 17 | 3. Export/Save the affected user list to UsersListFile.txt 18 | 19 | ![image](https://user-images.githubusercontent.com/21354416/151517552-413b9ce5-7dc6-4fe5-be48-d7a98d241638.png) 20 | 21 | 22 | 4. Save the SyncPhotoFromAADToSPOByGraphAPI.ps1 to local drive 23 | 5. Run it as below 24 | 25 | .\SyncPhotoFromAADToSPOByGraphAPI.ps1 -**usersListFile** ".\UsersListFile.txt" -**mySiteHostSiteUrl** https://chengc-my.sharepoint.com -**photoPath** C:\Photos\Photos -**updateExo** $false 26 | 27 | ![image](https://user-images.githubusercontent.com/21354416/151515934-0579cdb1-f2e9-4842-9042-20c5bf5c99fa.png) 28 | 29 | a. **usersListFile** is the user list file name 30 | 31 | b. **mySiteHostSiteUrl** is your tenant’s my site host URL 32 | 33 | c. **phtotoPath** is the temp folder for storing the photo which download from AAD 34 | 35 | d. **updateExo** switch specifies whether to update the photo via EXO command Set-UserPhoto in Exchange Online or not 36 | 37 | 6. Check the FailedUsers.txtand ErrorMessage.txtfor accounts which failed to be synced 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /KBs/UAP/SyncPhotoFromADToSPO/SPOManagementShellSyncPhotoFromAADToSPOByGraphAPI.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(mandatory=$true)] 3 | [string]$mySiteHostSiteUrl = "https://chengc-my.sharepoint.com", 4 | [Parameter(mandatory=$true)] 5 | [string]$usersListFile = "D:\files\photos\UsersListFile.txt", 6 | [Parameter(mandatory=$true)] 7 | [string]$photoPath = "D:\files\photos\Photos", 8 | [Parameter(mandatory=$false)] 9 | [bool]$updateExo = $false 10 | ) 11 | 12 | # connect AAD for get the users's ThumbnailPhoto by commmand Get-AzureADUserThumbnailPhoto -ObjectId "CVDu@chengc.onmicrosoft.com" 13 | Connect-PnPOnline -Scopes "User.Read","User.ReadBasic.All" 14 | $accessToken =Get-PnPAccessToken 15 | 16 | # Connect to exchange online 17 | if($updateExo) 18 | { 19 | Connect-ExchangeOnline 20 | } 21 | 22 | # Connect to the for uploading photos and update user profile 23 | $adminSiteUrl = $mySiteHostSiteUrl.Replace("-my", "-admin") 24 | $photoFolderUrl = "/User Photos/Profile Pictures/" 25 | $users = Get-Content $usersListFile 26 | # Update: Clear cached credential to connect to site 27 | Connect-PnPOnline $adminSiteUrl -UseWebLogin 28 | $adminCtx = Get-PnPContext 29 | $null = Get-PnPUserProfileProperty -Account $users[0] # load Microsoft.SharePoint.Client.UserProfiles 30 | 31 | Connect-PnPOnline $mySiteHostSiteUrl -SPOManagementShell 32 | $ctx = Get-PnPContext 33 | 34 | $peopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($adminCtx) 35 | 36 | function GeneratetThumbnail($filePath, $baseFilename) 37 | { 38 | $full = [System.Drawing.Image]::FromFile($filePath) 39 | 40 | $midThumb = $full.GetThumbnailImage(72, 72, $null, [intptr]::Zero) 41 | $midPath = "$photoPath\$baseFilename"+"_MThumb.jpg" 42 | $midThumb.Save($midPath); 43 | 44 | $smallThumb = $full.GetThumbnailImage(48, 48, $null, [intptr]::Zero) 45 | $smallPath = "$photoPath\$baseFilename"+"_SThumb.jpg" 46 | $smallThumb.Save($smallPath) 47 | 48 | $largeThumb = $full.GetThumbnailImage(300, 300, $null, [intptr]::Zero) 49 | $largePath = "$photoPath\$baseFilename"+"_LThumb.jpg" 50 | $largeThumb.Save($largePath) 51 | 52 | $full.Dispose() 53 | $midThumb.Dispose() 54 | $midThumb.Dispose() 55 | $largeThumb.Dispose() 56 | } 57 | 58 | foreach($user in $users) 59 | { 60 | try 61 | { 62 | Write-Host "Processing $user" 63 | #$null = Get-AzureADUserThumbnailPhoto -ObjectId $user -FilePath $photoPath -ErrorAction Stop 64 | $apiUrl = "https://graph.microsoft.com/v1.0/users/$user/photo/`$value" 65 | Invoke-RestMethod -Headers @{Authorization = "Bearer $accessToken"} -Uri $apiUrl -Method Get -ContentType image/jpeg -OutFile $photoPath\$user.jpg 66 | 67 | $file = Get-ChildItem -Path $photoPath -Filter "$user*" 68 | if($file.FullName -ne $empty) 69 | { 70 | $baseFilename = $user.Replace(".", "_").Replace("@","_") 71 | GeneratetThumbnail -filePath $file.FullName -baseFilename $baseFilename 72 | 73 | if($updateExo) 74 | { 75 | Set-UserPhoto -Identity $user -PictureData ([System.IO.File]::ReadAllBytes("$($photoPath)\$($baseFilename)_SThumb.jpg")) -Confirm:$false 76 | } 77 | 78 | $thumbnails = Get-ChildItem -Path $photoPath -Filter "$baseFilename*" 79 | foreach($thumbnail in $thumbnails) 80 | { 81 | Write-Host "Uploading $($thumbnail.FullName)......" 82 | $null = Add-PnPFile -Path $thumbnail.FullName -Folder $photoFolderUrl -ErrorAction Stop 83 | } 84 | 85 | $fullPictureUrl = $mySiteHostSiteUrl + $photoFolderUrl + $baseFilename + "_MThumb.jpg" 86 | $uploadedPicture = Get-PnPFile $fullPictureUrl 87 | if($uploadedPicture.Length -gt 0) 88 | { 89 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "PictureUrl", $fullPictureUrl) 90 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PicturePlaceholderState", 0) 91 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PictureExchangeSyncState", 1) 92 | $adminCtx.ExecuteQuery() 93 | } 94 | } 95 | else 96 | { 97 | $errorMessage = "Failed to get the user's photo when processing $($user) " 98 | Write-Host $errorMessage 99 | $errorMessage >>"ErrorMessage.txt" 100 | $user >> "FailedUsers.txt" 101 | } 102 | 103 | } 104 | catch [System.Exception] 105 | { 106 | $exceptionMessage = $_.Exception.ToString() 107 | $errorMessage = "Get error message $exceptionMessage when processing $($user)" 108 | Write-Host $errorMessage 109 | $errorMessage >>"ErrorMessage.txt" 110 | $user >> "FailedUsers.txt" 111 | } 112 | } 113 | 114 | Write-Host "Done!" -ForegroundColor Green -------------------------------------------------------------------------------- /KBs/UAP/SyncPhotoFromADToSPO/SyncPhotoFromAADToSPO.ps1 (Archived): -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(mandatory=$true)] 3 | [string]$mySiteHostSiteUrl = "https://chengc-my.sharepoint.com", 4 | [Parameter(mandatory=$true)] 5 | [string]$usersListFile = "D:\files\photos\UsersListFile.txt", 6 | [Parameter(mandatory=$true)] 7 | [string]$photoPath = "D:\files\photos\Photos", 8 | [Parameter(mandatory=$false)] 9 | [bool]$updateExo = $false 10 | ) 11 | 12 | # connect AAD for get the users's ThumbnailPhoto by commmand Get-AzureADUserThumbnailPhoto -ObjectId "CVDu@chengc.onmicrosoft.com" 13 | Connect-AzureAD 14 | 15 | # Connect to the for uploading photos and update user profile 16 | $adminSiteUrl = $mySiteHostSiteUrl.Replace("-my", "-admin") 17 | $photoFolderUrl = "/User Photos/Profile Pictures/" 18 | $users = Get-Content $usersListFile 19 | # Update: Clear cached credential to connect to site 20 | Connect-PnPOnline $adminSiteUrl -SPOManagementShell -ClearTokenCache 21 | $adminCtx = Get-PnPContext 22 | $null = Get-PnPUserProfileProperty -Account $users[0] 23 | 24 | Connect-PnPOnline $mySiteHostSiteUrl -UseWebLogin 25 | $ctx = Get-PnPContext 26 | 27 | $peopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($adminCtx) 28 | 29 | if($updateExo) 30 | { 31 | Connect-ExchangeOnline 32 | } 33 | 34 | function GeneratetThumbnail($filePath, $baseFilename) 35 | { 36 | $full = [System.Drawing.Image]::FromFile($filePath) 37 | 38 | $midThumb = $full.GetThumbnailImage(72, 72, $null, [intptr]::Zero) 39 | $midPath = "$photoPath\$baseFilename"+"_MThumb.jpg" 40 | $midThumb.Save($midPath); 41 | 42 | $smallThumb = $full.GetThumbnailImage(48, 48, $null, [intptr]::Zero) 43 | $smallPath = "$photoPath\$baseFilename"+"_SThumb.jpg" 44 | $smallThumb.Save($smallPath) 45 | 46 | $largeThumb = $full.GetThumbnailImage(300, 300, $null, [intptr]::Zero) 47 | $largePath = "$photoPath\$baseFilename"+"_LThumb.jpg" 48 | $largeThumb.Save($largePath) 49 | 50 | $full.Dispose() 51 | $midThumb.Dispose() 52 | $midThumb.Dispose() 53 | $largeThumb.Dispose() 54 | } 55 | 56 | foreach($user in $users) 57 | { 58 | try 59 | { 60 | Write-Host "Processing $user" 61 | $null = Get-AzureADUserThumbnailPhoto -ObjectId $user -FilePath $photoPath -ErrorAction Stop 62 | $file = Get-ChildItem -Path $photoPath -Filter "$user*" 63 | if($file.FullName -ne $empty) 64 | { 65 | $baseFilename = $user.Replace(".", "_").Replace("@","_") 66 | GeneratetThumbnail -filePath $file.FullName -baseFilename $baseFilename 67 | 68 | if($updateExo) 69 | { 70 | Set-UserPhoto -Identity $user -PictureData ([System.IO.File]::ReadAllBytes("$($photoPath)\$($baseFilename)_SThumb.jpg")) -Confirm:$false 71 | } 72 | 73 | $thumbnails = Get-ChildItem -Path $photoPath -Filter "$baseFilename*" 74 | foreach($thumbnail in $thumbnails) 75 | { 76 | Write-Host "Uploading $($thumbnail.FullName)......" 77 | $null = Add-PnPFile -Path $thumbnail.FullName -Folder $photoFolderUrl -ErrorAction Stop 78 | } 79 | $fullPictureUrl = $mySiteHostSiteUrl + $photoFolderUrl + $baseFilename + "_MThumb.jpg" 80 | $uploadedPicture = Get-PnPFile $fullPictureUrl 81 | if($uploadedPicture.Length -gt 0) 82 | { 83 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "PictureUrl", $fullPictureUrl) 84 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PicturePlaceholderState", 0) 85 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PictureExchangeSyncState", 1) 86 | $adminCtx.ExecuteQuery() 87 | } 88 | } 89 | else 90 | { 91 | $errorMessage = "Failed to get the user's phtot when processing $($user) " 92 | Write-Host $errorMessage 93 | $errorMessage >>"ErrorMessage.txt" 94 | $user >> "FailedUsers.txt" 95 | } 96 | 97 | } 98 | catch [System.Exception] 99 | { 100 | $exceptionMessage = $_.Exception.ToString() 101 | $errorMessage = "Get error message $exceptionMessage when processing $($user)" 102 | Write-Host $errorMessage 103 | $errorMessage >>"ErrorMessage.txt" 104 | $user >> "FailedUsers.txt" 105 | } 106 | } 107 | 108 | Write-Host "Done!" -ForegroundColor Green 109 | -------------------------------------------------------------------------------- /KBs/UAP/SyncPhotoFromADToSPO/SyncPhotoFromAADToSPOByGraphAPI.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(mandatory=$true)] 3 | [string]$mySiteHostSiteUrl = "https://chengc-my.sharepoint.com", 4 | [Parameter(mandatory=$true)] 5 | [string]$usersListFile = "D:\files\photos\UsersListFile.txt", 6 | [Parameter(mandatory=$true)] 7 | [string]$photoPath = "D:\files\photos\Photos", 8 | [Parameter(mandatory=$false)] 9 | [bool]$updateExo = $false 10 | ) 11 | 12 | # connect AAD for get the users's ThumbnailPhoto by commmand Get-AzureADUserThumbnailPhoto -ObjectId "CVDu@chengc.onmicrosoft.com" 13 | Connect-PnPOnline -Scopes "User.Read","User.ReadBasic.All" 14 | $accessToken =Get-PnPAccessToken 15 | 16 | # Connect to exchange online 17 | if($updateExo) 18 | { 19 | Connect-ExchangeOnline 20 | } 21 | 22 | # Connect to the for uploading photos and update user profile 23 | $adminSiteUrl = $mySiteHostSiteUrl.Replace("-my", "-admin") 24 | $photoFolderUrl = "/User Photos/Profile Pictures/" 25 | $users = Get-Content $usersListFile 26 | # Update: Clear cached credential to connect to site 27 | Connect-PnPOnline $adminSiteUrl -UseWebLogin 28 | $adminCtx = Get-PnPContext 29 | $null = Get-PnPUserProfileProperty -Account $users[0] # load Microsoft.SharePoint.Client.UserProfiles 30 | 31 | Connect-PnPOnline $mySiteHostSiteUrl -UseWebLogin 32 | $ctx = Get-PnPContext 33 | 34 | $peopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($adminCtx) 35 | 36 | function GeneratetThumbnail($filePath, $baseFilename) 37 | { 38 | $full = [System.Drawing.Image]::FromFile($filePath) 39 | 40 | $midThumb = $full.GetThumbnailImage(72, 72, $null, [intptr]::Zero) 41 | $midPath = "$photoPath\$baseFilename"+"_MThumb.jpg" 42 | $midThumb.Save($midPath); 43 | 44 | $smallThumb = $full.GetThumbnailImage(48, 48, $null, [intptr]::Zero) 45 | $smallPath = "$photoPath\$baseFilename"+"_SThumb.jpg" 46 | $smallThumb.Save($smallPath) 47 | 48 | $largeThumb = $full.GetThumbnailImage(300, 300, $null, [intptr]::Zero) 49 | $largePath = "$photoPath\$baseFilename"+"_LThumb.jpg" 50 | $largeThumb.Save($largePath) 51 | 52 | $full.Dispose() 53 | $midThumb.Dispose() 54 | $midThumb.Dispose() 55 | $largeThumb.Dispose() 56 | } 57 | 58 | foreach($user in $users) 59 | { 60 | try 61 | { 62 | Write-Host "Processing $user" 63 | #$null = Get-AzureADUserThumbnailPhoto -ObjectId $user -FilePath $photoPath -ErrorAction Stop 64 | $apiUrl = "https://graph.microsoft.com/v1.0/users/$user/photo/`$value" 65 | Invoke-RestMethod -Headers @{Authorization = "Bearer $accessToken"} -Uri $apiUrl -Method Get -ContentType image/jpeg -OutFile $photoPath\$user.jpg 66 | 67 | $file = Get-ChildItem -Path $photoPath -Filter "$user*" 68 | if($file.FullName -ne $empty) 69 | { 70 | $baseFilename = $user.Replace(".", "_").Replace("@","_") 71 | GeneratetThumbnail -filePath $file.FullName -baseFilename $baseFilename 72 | 73 | if($updateExo) 74 | { 75 | Set-UserPhoto -Identity $user -PictureData ([System.IO.File]::ReadAllBytes("$($photoPath)\$($baseFilename)_SThumb.jpg")) -Confirm:$false 76 | } 77 | 78 | $thumbnails = Get-ChildItem -Path $photoPath -Filter "$baseFilename*" 79 | foreach($thumbnail in $thumbnails) 80 | { 81 | Write-Host "Uploading $($thumbnail.FullName)......" 82 | $null = Add-PnPFile -Path $thumbnail.FullName -Folder $photoFolderUrl -ErrorAction Stop 83 | } 84 | 85 | $fullPictureUrl = $mySiteHostSiteUrl + $photoFolderUrl + $baseFilename + "_MThumb.jpg" 86 | $uploadedPicture = Get-PnPFile $fullPictureUrl 87 | if($uploadedPicture.Length -gt 0) 88 | { 89 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "PictureUrl", $fullPictureUrl) 90 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PicturePlaceholderState", 0) 91 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PictureExchangeSyncState", 1) 92 | $adminCtx.ExecuteQuery() 93 | } 94 | } 95 | else 96 | { 97 | $errorMessage = "Failed to get the user's photo when processing $($user) " 98 | Write-Host $errorMessage 99 | $errorMessage >>"ErrorMessage.txt" 100 | $user >> "FailedUsers.txt" 101 | } 102 | 103 | } 104 | catch [System.Exception] 105 | { 106 | $exceptionMessage = $_.Exception.ToString() 107 | $errorMessage = "Get error message $exceptionMessage when processing $($user)" 108 | Write-Host $errorMessage 109 | $errorMessage >>"ErrorMessage.txt" 110 | $user >> "FailedUsers.txt" 111 | } 112 | } 113 | 114 | Write-Host "Done!" -ForegroundColor Green 115 | -------------------------------------------------------------------------------- /KBs/UAP/SyncUserPropertiesFromAADToSPOProfile/ReadMe.md: -------------------------------------------------------------------------------- 1 | This script is used for syncing user properties from ADD to SharePoint Online user profile. 2 | 3 | It will sync below propeties by default, 4 | "Department","GivenName","Surname","DisplayName","telephoneNumber","JobTitle". 5 | 6 | And if you need to sync WorkMail and Manager, then need to add the addtional parameters (-SyncWorkMail $true -SyncManager $true) 7 | **It neeed to be run by SharePoint Online tenant admin.** 8 | 9 | 10 | 1. Start PowerShell as administrator and install the SharePoint PNP and Azure AD PowerShell Module 11 | 12 | a. Install-Module -Name AzureAD 13 | 14 | b. Uninstall-Module -Name "SharePointPnPPowerShellOnline" 15 | 16 | c. Install-Module -Name "PnP.PowerShell" 17 | 18 | d. If the computer doesn't allow to run PowerShell script, allow it by running Set-ExecutionPolicy according to https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7.2 19 | 20 | 2. Download the script **SyncUserPropertiesFromAADToSPOProfile.ps1** to local drive 21 | 22 | 3. Run the script as below for China 21v enviroment (please repalce the place holder contonso), 23 | 24 | .\SyncUserPropertiesFromAADToSPOProfile.ps1 -AdminSiteURL https://contonso-admin.sharepoint.cn -IsChinaCloud $true 25 | ![image](https://user-images.githubusercontent.com/21354416/167838200-e946942d-2306-48d8-8c98-80a9d665384f.png) 26 | 27 | 28 | 4. Run the script as below for Global enviroment (please repalce the place holder contonso), 29 | 30 | .\SyncUserPropertiesFromAADToSPOProfile.ps1 -AdminSiteURL https://contonso-admin.sharepoint.com 31 | 32 | 33 | ** If don't want to sync, just want to bulk update some user profile proerty (e.g. set OfficeGraphEnabled to true for all users), try below command ** 34 | 35 | 36 | .\SyncUserPropertiesFromAADToSPOProfile.ps1 -AdminSiteURL https://chengc-admin.sharepoint.com -PropertyName "OfficeGraphEnabled" -PropertyValue $true 37 | ![image](https://user-images.githubusercontent.com/21354416/170006748-8db3a84c-3e8b-4859-bdf8-f9edc3850f7b.png) 38 | ![image](https://user-images.githubusercontent.com/21354416/170006873-407ceabf-fd58-489a-acd7-83063ef1a3b1.png) 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /KBs/UAP/SyncUserPropertiesFromAADToSPOProfile/SyncUserPropertiesFromAADToSPOProfile.ps1: -------------------------------------------------------------------------------- 1 | # This script is used for syncing user properties from ADD to SharePoint Online user profile 2 | param( 3 | [Parameter(mandatory=$true)] 4 | [string]$AdminSiteURL = "https://chengc-admin.sharepoint.com", # SPO admin site URL 5 | [bool]$IsChinaCloud = $false, # IsChinaCloud indicates the AzureEnvironment 6 | [bool]$SyncManager= $false, # will not sync manage by default 7 | [bool]$SyncWorkMail=$false, 8 | [string]$PropertyName="", 9 | [object]$PropertyValue=$null 10 | ) 11 | 12 | $ADProperties = @("Department","Department","GivenName","Surname","DisplayName","telephoneNumber","JobTitle","Mobile") 13 | $SPOProperies = @("Department","SPS-Department","FirstName","LastName","PreferredName","WorkPhone","SPS-JobTitle","CellPhone") 14 | 15 | $ADProperties = [System.Collections.ArrayList]$ADProperties 16 | $SPOProperies = [System.Collections.ArrayList]$SPOProperies 17 | # AzureEnvironmentName for Connect-AzureAD: AzureCloud,AzureChinaCloud,AzureUSGovernment,AzureGermanyCloud 18 | $EnvironmentForAAD = "AzureCloud" 19 | 20 | if($IsChinaCloud) 21 | { 22 | $EnvironmentForAAD = "AzureChinaCloud" 23 | } 24 | 25 | Connect-AzureAD -AzureEnvironmentName $EnvironmentForAAD | Out-Null 26 | Connect-PnPOnline -Url $AdminSiteURL -UseWebLogin | Out-Null 27 | $AllUsers = $null 28 | 29 | if($SyncWorkMail) # proxyAddresses => WorkEmail 30 | { 31 | $ADProperties.Add("Mail") | Out-Null 32 | $SPOProperies.Add("WorkEmail") | Out-Null 33 | } 34 | 35 | if($SyncManager) 36 | { 37 | $ADProperties.Add("Manager") | Out-Null 38 | $SPOProperies.Add("Manager") | Out-Null 39 | $AllUsers = Get-AzureADUser -All:$True -Filter "UserType eq 'Member'" | select *,@{n="Manager";e={(Get-AzureADUser -ObjectId (Get-AzureADUserManager -ObjectId $_.ObjectId).ObjectId).UserPrincipalName}} 40 | } 41 | else 42 | { 43 | $AllUsers = Get-AzureADUser -All:$True -Filter "UserType eq 'Member'" 44 | } 45 | 46 | Write-host "Queried $($AllUsers.Count) users." 47 | $UpdateCount =0 48 | forEach($User in $AllUsers) 49 | { 50 | $updated =$false 51 | try 52 | { 53 | Write-host "Processing $($User.UserPrincipalName) ......" 54 | $UserAccount = "i:0#.f|membership|$($User.UserPrincipalName)" 55 | $UserProfile = Get-PnPUserProfileProperty -Account $UserAccount 56 | if([System.String]::IsNullOrEmpty($UserProfile.AccountName)) 57 | { 58 | write-host "Can't find the SPO profile for account $UserAccount, skip it" -ForegroundColor Yellow 59 | continue 60 | } 61 | 62 | if([System.String]::IsNullOrEmpty($PropertyName)) # If PropertyName is null, then perform sync, otherwise only set the property with PropertyName 63 | { 64 | for($index=0; $index -lt $SPOProperies.Count; $index++) 65 | { 66 | $SPOPropertyName = $SPOProperies[$index] 67 | $AADPropertyName = $ADProperties[$index] 68 | 69 | $SPOPropertyValue = $UserProfile.UserProfileProperties[$SPOPropertyName] 70 | $AADPropertyValue = $User.$AADPropertyName 71 | 72 | if([System.String]::IsNullOrEmpty($AADPropertyValue)) 73 | { 74 | $AADPropertyValue = "" 75 | } 76 | 77 | if([System.String]::IsNullOrEmpty($SPOPropertyValue)) 78 | { 79 | $SPOPropertyValue = "" 80 | } 81 | 82 | if($SPOPropertyName -eq "Manager" -and $AADPropertyValue -ne "") 83 | { 84 | $AADPropertyValue = "i:0#.f|membership|$AADPropertyValue" 85 | } 86 | 87 | if($SPOPropertyValue -ne $AADPropertyValue) 88 | { 89 | Write-Host "Detected mismatch: $SPOPropertyName in SPO is $SPOPropertyValue, $AADPropertyName in AAD is $AADPropertyValue, will update" 90 | Set-PnPUserProfileProperty -Account $UserAccount -PropertyName $SPOPropertyName -Value $AADPropertyValue 91 | $updated = $true 92 | } 93 | } 94 | } 95 | else # set property mode 96 | { 97 | Set-PnPUserProfileProperty -Account $UserAccount -PropertyName $PropertyName -Value $PropertyValue 98 | $updated = $true 99 | } 100 | 101 | 102 | if($updated) 103 | { 104 | $UpdateCount++ 105 | } 106 | } 107 | catch [System.Exception] 108 | { 109 | $errormessage = $_.Exception.ToString() 110 | write-host $errormessage -ForegroundColor Red 111 | } 112 | } 113 | 114 | Write-Host "Updated $UpdateCount users." -ForegroundColor Green 115 | -------------------------------------------------------------------------------- /KBs/UAP/UploadUserPictureToSPO/ReadMe.md: -------------------------------------------------------------------------------- 1 | 2 | This script used for uploading user pictures from local drive to SharePoint online user profile directly. 3 | **It neeed to be run by SharePoint online tenant admin.** 4 | 5 | 6 | 1. Start PowerShell as administrator and install the SharePoint PNP Module 7 | 8 | a. Install-Module -Name "PNP.PowerShell" 9 | 10 | 2. Prepare all users' pictures with the file name same as the users' UPN in local folder (e.g. C:\Photos\Photos), 11 | ![image](https://user-images.githubusercontent.com/21354416/160579725-d265f2fa-f01c-48fd-9e27-21620914ddd5.png) 12 | 13 | 14 | 3. Export/Save the affected user list to UsersListFile.txt 15 | 16 | ![image](https://user-images.githubusercontent.com/21354416/160580116-632a35d6-c0ea-4da3-a67b-2e363704d2dc.png) 17 | 18 | 19 | 4. Save the UploadUserPictureToSPO.ps1 to local drive 20 | 5. Run it as below 21 | 22 | .\UploadUserPictureToSPO.ps1 -**usersListFile** ".\UsersListFile.txt" -**mySiteHostSiteUrl** https://chengc-my.sharepoint.com -**photoPath** C:\Photos\Photos 23 | 24 | ![image](https://user-images.githubusercontent.com/21354416/160579874-0c30b044-878e-4957-99a9-86beea5b4ebf.png) 25 | 26 | a. **usersListFile** is the user list file name 27 | 28 | b. **mySiteHostSiteUrl** is your tenant’s my site host URL 29 | 30 | c. **phtotoPath** is the folder which stored the prepared users' pictures 31 | 32 | 33 | 6. Check the FailedUsers.txtand ErrorMessage.txtfor accounts which failed to be synced 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /KBs/UAP/UploadUserPictureToSPO/UploadUserPictureToSPO.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(mandatory=$true)] 3 | [string]$mySiteHostSiteUrl = "https://arrkengineering-my.sharepoint.com", 4 | [Parameter(mandatory=$true)] 5 | [string]$usersListFile = "C:\xxx\xxx\UsersListFile.txt", 6 | [Parameter(mandatory=$true)] 7 | [string]$photoPath = "C:\xxx\xxx\Photos" 8 | ) 9 | 10 | 11 | # Connect to the for uploading photos and update user profile 12 | $adminSiteUrl = $mySiteHostSiteUrl.Replace("-my", "-admin") 13 | $photoFolderUrl = "/User Photos/Profile Pictures/" 14 | $users = Get-Content $usersListFile 15 | # Update: Clear cached credential to connect to site 16 | Connect-PnPOnline $adminSiteUrl -UseWebLogin 17 | $adminCtx = Get-PnPContext 18 | $null = Get-PnPUserProfileProperty -Account $users[0] # Load Microsoft.SharePoint.Client.UserProfiles.dll 19 | 20 | Connect-PnPOnline $mySiteHostSiteUrl -UseWebLogin 21 | $ctx = Get-PnPContext 22 | 23 | $peopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($adminCtx) 24 | 25 | function GeneratetThumbnail($filePath, $baseFilename) 26 | { 27 | $full = [System.Drawing.Image]::FromFile($filePath) 28 | 29 | $midThumb = $full.GetThumbnailImage(72, 72, $null, [intptr]::Zero) 30 | $midPath = "$photoPath\$baseFilename"+"_MThumb.jpg" 31 | $midThumb.Save($midPath); 32 | 33 | $smallThumb = $full.GetThumbnailImage(48, 48, $null, [intptr]::Zero) 34 | $smallPath = "$photoPath\$baseFilename"+"_SThumb.jpg" 35 | $smallThumb.Save($smallPath) 36 | 37 | $largeThumb = $full.GetThumbnailImage(300, 300, $null, [intptr]::Zero) 38 | $largePath = "$photoPath\$baseFilename"+"_LThumb.jpg" 39 | $largeThumb.Save($largePath) 40 | 41 | $full.Dispose() 42 | $midThumb.Dispose() 43 | $midThumb.Dispose() 44 | $largeThumb.Dispose() 45 | } 46 | 47 | foreach($user in $users) 48 | { 49 | try 50 | { 51 | Write-Host "Processing $user" 52 | 53 | $file = Get-ChildItem -Path $photoPath -Filter "$user*" 54 | if($file.FullName -ne $empty) 55 | { 56 | $baseFilename = $user.Replace(".", "_").Replace("@","_") 57 | GeneratetThumbnail -filePath $file.FullName -baseFilename $baseFilename 58 | 59 | 60 | $thumbnails = Get-ChildItem -Path $photoPath -Filter "$baseFilename*" 61 | foreach($thumbnail in $thumbnails) 62 | { 63 | Write-Host "Uploading $($thumbnail.FullName)......" 64 | $null = Add-PnPFile -Path $thumbnail.FullName -Folder $photoFolderUrl -ErrorAction Stop 65 | } 66 | 67 | $fullPictureUrl = $mySiteHostSiteUrl + $photoFolderUrl + $baseFilename + "_MThumb.jpg" 68 | $uploadedPicture = Get-PnPFile $fullPictureUrl 69 | if($uploadedPicture.Length -gt 0) 70 | { 71 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "PictureUrl", $fullPictureUrl) 72 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PicturePlaceholderState", 0) 73 | $peopleManager.SetSingleValueProfileProperty("i:0#.f|membership|" + $user, "SPS-PictureExchangeSyncState", 1) 74 | $adminCtx.ExecuteQuery() 75 | } 76 | } 77 | else 78 | { 79 | $errorMessage = "Failed to get the user's phtot when processing $($user) " 80 | Write-Host $errorMessage 81 | $errorMessage >>"ErrorMessage.txt" 82 | $user >> "FailedUsers.txt" 83 | } 84 | 85 | } 86 | catch [System.Exception] 87 | { 88 | $exceptionMessage = $_.Exception.ToString() 89 | $errorMessage = "Get error message $exceptionMessage when processing $($user)" 90 | Write-Host $errorMessage 91 | $errorMessage >>"ErrorMessage.txt" 92 | $user >> "FailedUsers.txt" 93 | } 94 | } 95 | 96 | Write-Host "Done!" -ForegroundColor Green 97 | -------------------------------------------------------------------------------- /KBs/UneditableClassicWiki/ReadMe.md: -------------------------------------------------------------------------------- 1 | **[Symptoms]** 2 | 3 | When the user enter edit mode on a classic wiki page, the ribbon menu may gray out and the page became uneditable. 4 | 5 | ![image](https://user-images.githubusercontent.com/102142347/162902816-138a9530-606a-4030-a3e9-ef9bf6f666fb.png) 6 | 7 | **[Cause]** 8 | 9 | Classic wiki page holds its layout data in an OOTB field "WikiField" as HTML. If the field contains invalid value or the layout table in the HTML does not match the declaration, it could lead to unexpected behaviors. 10 | 11 | **[Solution]** 12 | 13 | The layout data is being saved in OOTB field named "WikiField". Below is a sample checking the value using PnP powershell cmdlet. The sample page here has "Three column with header and footer" layout. 14 | ```powershell 15 | Connect-PnPOnline https://xxxxxx.sharepoint.com/sites/xxxxxxx 16 | $pages = Get-PnPListItem -List sitepages 17 | # List up all pages and shows each page's Id and Filename 18 | $pages | Select-Object id,@{label="Filename";expression={$_.FieldValues.FileLeafRef}} 19 | # Use target page's Id to retreive WikiField value 20 | ($page | ? Id -eq 11111).FieldValues.WikiField 21 |
 


 
 
 
22 | ``` 23 | The value in "WikiField" is a \
tag containing a \ tag (#layoutsTable) and a \ tag (#layoutsData). 24 | 25 | The #layoutsTable descridbes the page layout in details and the #layoutsData declares whether the page has header and footer and how many columns it contains. If you are guided to this page by the tool, please make sure 26 | 27 | * #layoutsTable is valid HTML and the number of tr and td tags match a supported layout in following list. 28 | ![image](https://user-images.githubusercontent.com/102142347/162902915-a7334235-04e8-4543-a84a-8bb300c0213c.png) 29 | * The inner HTML of #layoutsData should be in format as \, \, \ . 30 | * The layout described in #layoutsTable should match #layoutsData. 31 | 32 | Once you identified the problem in above steps, you can fix it by modifying the value in "WikiField". 33 | 34 | **!!Make sure you understand what you are doing and back up the page before you begin the fix steps. You may lose part of page content when you change the layout data. !!** 35 | 36 | Sample using PnP powershell cmdlet 37 | ```powershell 38 | Set-PnPListItem -List sitepages -Identity 11111 -Values @{"WikiField"='
 


 
 
 
'} 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 shspobc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa 1.22.12.01.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa 1.22.12.01.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa.1.22.05.25.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa.1.22.05.25.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.21.11.06.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.21.11.06.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.21.11.29.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.21.11.29.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.21.12.06.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.21.12.06.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.21.12.17.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.21.12.17.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.21.12.28.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.21.12.28.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.02.25.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.02.25.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.02.26.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.02.26.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.03.07.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.03.07.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.03.12.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.03.12.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.03.26.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.03.26.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.03.28.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.03.28.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.04.02.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.04.02.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.04.05.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.04.05.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.04.12.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.04.12.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.04.16.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.04.16.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.04.20.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.04.20.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.04.22.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.04.22.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.04.25.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.04.25.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.05.10.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.05.10.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.05.20.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.05.20.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.06.01.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.06.01.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.06.27.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.06.27.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.07.13.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.07.13.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.0713.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.0713.sppkg -------------------------------------------------------------------------------- /Packages/HistoryVersions/spoqa1.22.10.04.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/HistoryVersions/spoqa1.22.10.04.sppkg -------------------------------------------------------------------------------- /Packages/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Deployment Approaches 2 | ## Deploy the tool from SharePoint Store 3 | 1. Open the tenant app manage page https://**contoso**-admin.sharepoint.com/_layouts/15/tenantAppCatalog.aspx and click "SharePoint Store" 4 | 5 | ![image](https://user-images.githubusercontent.com/21354416/181446459-80487868-73a1-44dc-8732-aab11b36a1c9.png) 6 | 7 | 2. Search the "SharePoint Online Quick Assist" 8 | 9 | ![image](https://user-images.githubusercontent.com/21354416/181446926-71f61529-3b33-4c0b-8a58-a3d8328520c5.png) 10 | 11 | 3. Click the searched "SharePoint Online Quick Assist" and click "Add to app catalog" button 12 | 13 | ![image](https://user-images.githubusercontent.com/21354416/181447089-484ed56a-b2f1-4e95-8c76-7ad97c613492.png) 14 | 15 | 4. Click "Add" button for the "Confirm data access" 16 | 17 | ![image](https://user-images.githubusercontent.com/21354416/181447204-359d1818-1853-4b6a-897b-d4a695e20cb6.png) 18 | 19 | 5. Click "Go to API access page" button 20 | 21 | ![image](https://user-images.githubusercontent.com/21354416/181447325-f52cd82c-ca38-4968-ba70-5045751478db.png) 22 | 23 | 6. Select pending API requests for "SharePoint Online Quick Assist" and click approve button 24 | 25 | ![image](https://user-images.githubusercontent.com/21354416/181447412-1c2ba036-e8fb-4030-ac15-06511b81239d.png) 26 | 27 | 7. Go to the site and add "SharePoint Online Quick Assist" 28 | 29 | ![image](https://user-images.githubusercontent.com/21354416/181447526-bf2d3ce3-e5f0-46cc-b548-d8833a01b6c3.png) 30 | 31 | 8. Add the "SharePoint Online Quick Assist" web part into page 32 | 33 | ![image](https://user-images.githubusercontent.com/21354416/181447638-5ab748de-865b-4b7f-a260-f775f7daa0b3.png) 34 | 35 | ## Deploy the tool tenant level app catalog 36 | * Upload SPOQA.sppkg from https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Packages/spoqa.sppkg to your tenant App Catalog 37 | * E.g.: https://<tenant>.sharepoint.com/sites/AppCatalog/AppCatalog 38 | 39 | 40 | * Deploy the app when you see the prompt as follow 41 | 42 | 43 | 44 | * Approve API access requests in SharePoint admin center 45 | * https://<tenant>-admin.sharepoint.com/_layouts/15/online/AdminHome.aspx#/webApiPermissionManagement 46 | 47 | 48 | * Add the web part to a site collection, and test it on a page 49 | 50 | 51 | ## Deploy the tool site collection level app catalog 52 | Download and install SharePoint Online Management Shell. 53 | * Open it and run the following: (You need Global admin or SharePoint admin rights. ) 54 | * Connect-SPOService https://contoso-admin.sharepoint.com 55 | * Set-SPOSite -Identity https://contoso.sharepoint.com/sites/ASite -DenyAddAndCustomizePages 0 56 | * Add-SPOSiteCollectionAppCatalog -Site https://contoso.sharepoint.com/sites/ASite 57 | * Download the tool https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Packages/spoqa.sppkg. 58 | * Access https://contoso.sharepoint.com/sites/ASite/AppCatalog. 59 | * Click “Upload” and upload “spoqa.sppkg”. 60 | * Click “Deploy” and click “Trust” button. 61 | * Approve API access requests in SharePoint admin center, 62 | https://-admin.sharepoint.com/_layouts/15/online/AdminHome.aspx#/webApiPermissionManagement 63 | * Back to the site https://contoso.sharepoint.com/sites/ASite, click “Add an app”. 64 | * Add “spoqa-client-side-solution”. 65 | * Add a new page in the site and add the web part “SharePoint Online Quick Assist”. “Publish” the page. 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Packages/spoqa.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/Packages/spoqa.sppkg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | https://user-images.githubusercontent.com/89838160/169972855-a7605e68-c6b1-4235-af61-a4226bee5b45.mp4 4 | 5 | # M365 First Aid x Hackathon 2022 6 | [![M365 First Aid x Hackathon](https://user-images.githubusercontent.com/89838160/186566847-f6585954-413c-4b46-b39a-29087022f1ae.png)](https://www.youtube.com/watch?v=IBx8SICGFJE) 7 | 8 | # M365 First Aid Introduction 9 | [![IMAGE ALT TEXT HERE](https://user-images.githubusercontent.com/89838160/186567066-16e1338c-4236-40b8-b45d-d3be503ff9f9.PNG)](https://www.youtube.com/watch?v=lA31ikfL8JY) 10 | 11 | # SharePointOnlineQuickAssist-Tutorial Materials 12 | 13 | SharePoint Online Quick Assist is a SPFX webpart that appears inside a SharePoint page in the browser. Site administrators could use the tool to diagnose some common issues and fix them. 14 | 15 | This tool is provided by the copyright holders and contributors “as is” and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. 16 | 17 | ## Please note, if you want to use the auto fix function on the affected site then the custom script for the site should be enabled https://docs.microsoft.com/en-us/sharepoint/allow-or-prevent-custom-script#to-allow-custom-script-on-other-sharepoint-sites 18 | 19 | 20 | ## Available features 21 | 22 | * **Restore Items** 23 | This feature helps user to filter/restore/export items from SharePoint Online recycle bin, 24 | ![image](https://user-images.githubusercontent.com/21354416/155688589-199fc965-1333-4073-82b6-677444497a36.png) 25 | 26 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/RestoreItems.md) 27 | 28 | * **Check Permssion issue** 29 | This feature helps user to diagnose permssion issues (get access denied or 404 when accessing shared links even the linked document does existing), 30 | ![image](https://user-images.githubusercontent.com/21354416/160541128-832029ee-cfda-4f4a-913f-9512c43aaf67.png) 31 | 32 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/CheckPermissionIssue.md) 33 | 34 | * **Search Issue For A Specific Document** 35 | 36 | 37 | This feature helps user to diagnose the issue when a specific document does not appear in the search results 38 | 39 | 40 | 41 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/SearchSpecificDocument.md) 42 | 43 | 44 | * **Search Issue For A Specific Site** 45 | 46 | This feature helps user diagnose the issue when a specific site does not appear in the search results 47 | 48 | 49 | 50 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/SearchSpecificSite.md) 51 | 52 | 53 | * **Job Title Sync Issue** 54 | 55 | 56 | This feature helps validate user's 'job title' in AAD, SPO user profile and site. 57 | 58 | 59 | 60 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/JobTitleSyncIssue.md) 61 | 62 | * **Photo Sync Issue** 63 | This feature helps user compare their profile photo from AAD to SPO user profile. 64 | 65 | 66 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/UserPhotoSync.md) 67 | 68 | * **User Info list sync issue**, 69 | User/Group mail haven’t been synced to user info list caused the mail can’t be send to User/Group in user alert, workflow 70 | User/Group display name updated but haven’t synced to user info list cause mismatch issue 71 | User’ phone number haven’t been synced to user info list cause mismatch issue 72 | User’ job title haven’t been synced to user info list cause mismatch issue 73 | ![image](https://user-images.githubusercontent.com/21354416/144986960-e4befdd6-b9d6-40a0-bb54-fc90ca8d0d70.png) 74 | ![image](https://user-images.githubusercontent.com/21354416/144987002-085d0652-f243-4c29-84b6-94452d3afdee.png) 75 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/UserInfoSyncIssue.md) 76 | * **OneDrive library sync issue**, 77 | OneDrive sync button can't be found. 78 | Library synced as read only 79 | ![image](https://user-images.githubusercontent.com/21354416/144987185-d18e2e24-5b35-4436-ba3f-002dd95819c7.png) 80 | ![image](https://user-images.githubusercontent.com/21354416/144987204-83e0eb28-9f10-4ec4-858a-cc31c78d0d32.png) 81 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/OneDriveLockIcon.md) 82 | 83 | * **Missing New/Display/Edit forms issue** 84 | ![image](https://user-images.githubusercontent.com/21354416/147523270-bef520ae-e487-4414-a449-6348b31efe82.png) 85 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/MissingForms.md) 86 | 87 | * **Uneditable wiki page** This feature helps to detect layout issue which could cause a classic wiki page being uneditable. 88 | 89 | ![image](https://user-images.githubusercontent.com/102142347/162903702-ed3ed028-6701-49b9-ab32-a88c14cb3480.png) 90 | 91 | [More details](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/UneditableClassicWiki.md) 92 | 93 | **Please click the link [Deployment Approaches](https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Documents/Installation/ReadMe.md) for checking deployment steps** 94 | 95 | ## If you want to contribute/customzied this tool, you may try below steps, 96 | 97 | To build and start using these projects, you'll need to clone and build the projects. 98 | 99 | Clone this repository by executing the following command in your console: 100 | 101 | ```shell 102 | git clone https://github.com/abrcheng/SharePointOnlineQuickAssist.git 103 | ``` 104 | 105 | Navigate to the cloned repository folder which should be the same as the repository name: 106 | 107 | ```shell 108 | cd SharePointOnlineQuickAssist 109 | ``` 110 | 111 | To access the webpart use the following command. 112 | 113 | ```shell 114 | cd SPFX 115 | cd SPOQA 116 | ``` 117 | 118 | 119 | Now run the following command to install the npm packages: 120 | 121 | ```shell 122 | npm install 123 | ``` 124 | 125 | This will install the required npm packages and dependencies to build and run the client-side project. 126 | 127 | Once the npm packages are installed, run the following command to preview your web parts in SharePoint Workbench: 128 | 129 | ```shell 130 | gulp serve 131 | ``` 132 | 133 | ### Deploy 134 | ```shell 135 | gulp clean 136 | gulp bundle --ship 137 | gulp package-solution --ship 138 | ``` 139 | ### Additional resources 140 | 141 | * [Overview of the SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview) 142 | * [SharePoint Framework development tools and libraries](https://docs.microsoft.com/sharepoint/dev/spfx/tools-and-libraries) 143 | * [Getting Started](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant) 144 | * [Microsoft Privacy Statement – Microsoft privacy](https://privacy.microsoft.com/en-us/privacystatement) 145 | -------------------------------------------------------------------------------- /SPFX/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "@microsoft/generator-sharepoint": { 3 | "isCreatingSolution": true, 4 | "environment": "spo", 5 | "whichFolder": "subdir" 6 | } 7 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Dependency directories 7 | node_modules 8 | 9 | # Build generated files 10 | dist 11 | lib 12 | release 13 | solution 14 | temp 15 | *.sppkg 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # OSX 21 | .DS_Store 22 | 23 | # Visual Studio files 24 | .ntvs_analysis.dat 25 | .vs 26 | bin 27 | obj 28 | 29 | # Resx Generated Code 30 | *.resx.ts 31 | 32 | # Styles Generated Code 33 | *.scss.ts 34 | -------------------------------------------------------------------------------- /SPFX/SPOQA/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "msjsdiag.debugger-for-chrome" 4 | ] 5 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Install Chrome Debugger Extension for Visual Studio Code to debug your components with the 4 | * Chrome browser: https://aka.ms/spfx-debugger-extensions 5 | */ 6 | "version": "0.2.0", 7 | "configurations": [{ 8 | "name": "Local workbench", 9 | "type": "chrome", 10 | "request": "launch", 11 | "url": "https://localhost:4321/temp/workbench.html", 12 | "webRoot": "${workspaceRoot}", 13 | "sourceMaps": true, 14 | "sourceMapPathOverrides": { 15 | "webpack:///.././src/*": "${webRoot}/src/*", 16 | "webpack:///../../../src/*": "${webRoot}/src/*", 17 | "webpack:///../../../../src/*": "${webRoot}/src/*", 18 | "webpack:///../../../../../src/*": "${webRoot}/src/*" 19 | }, 20 | "runtimeArgs": [ 21 | "--remote-debugging-port=9222" 22 | ] 23 | }, 24 | { 25 | "name": "Hosted workbench", 26 | "type": "chrome", 27 | "request": "launch", 28 | "url": "https://enter-your-SharePoint-site/_layouts/workbench.aspx", 29 | "webRoot": "${workspaceRoot}", 30 | "sourceMaps": true, 31 | "sourceMapPathOverrides": { 32 | "webpack:///.././src/*": "${webRoot}/src/*", 33 | "webpack:///../../../src/*": "${webRoot}/src/*", 34 | "webpack:///../../../../src/*": "${webRoot}/src/*", 35 | "webpack:///../../../../../src/*": "${webRoot}/src/*" 36 | }, 37 | "runtimeArgs": [ 38 | "--remote-debugging-port=9222", 39 | "-incognito" 40 | ] 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | // Configure glob patterns for excluding files and folders in the file explorer. 4 | "files.exclude": { 5 | "**/.git": true, 6 | "**/.DS_Store": true, 7 | "**/bower_components": true, 8 | "**/coverage": true, 9 | "**/lib-amd": true, 10 | "src/**/*.scss.ts": true 11 | }, 12 | "typescript.tsdk": ".\\node_modules\\typescript\\lib" 13 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "@microsoft/generator-sharepoint": { 3 | "version": "1.12.1", 4 | "libraryName": "spoqa", 5 | "libraryId": "029e4fc2-a440-4f5f-a358-b34a0eca54b5", 6 | "environment": "spo", 7 | "packageManager": "npm", 8 | "isCreatingSolution": false, 9 | "isDomainIsolated": true, 10 | "componentType": "webpart" 11 | } 12 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/PrdBuild.ps1: -------------------------------------------------------------------------------- 1 | gulp clean 2 | gulp build 3 | gulp bundle --ship 4 | gulp package-solution --ship -------------------------------------------------------------------------------- /SPFX/SPOQA/README.md: -------------------------------------------------------------------------------- 1 | # spoqa 2 | 3 | ## Summary 4 | 5 | Short summary on functionality and used technologies. 6 | 7 | [picture of the solution in action, if possible] 8 | 9 | ## Used SharePoint Framework Version 10 | 11 | ![version](https://img.shields.io/npm/v/@microsoft/sp-component-base/latest?color=green) 12 | 13 | ## Applies to 14 | 15 | - [SharePoint Framework](https://aka.ms/spfx) 16 | - [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant) 17 | 18 | > Get your own free development tenant by subscribing to [Microsoft 365 developer program](http://aka.ms/o365devprogram) 19 | 20 | ## Prerequisites 21 | 22 | > Any special pre-requisites? 23 | 24 | ## Solution 25 | 26 | Solution|Author(s) 27 | --------|--------- 28 | folder name | Author details (name, company, twitter alias with link) 29 | 30 | ## Version history 31 | 32 | Version|Date|Comments 33 | -------|----|-------- 34 | 1.1|March 10, 2021|Update comment 35 | 1.0|January 29, 2021|Initial release 36 | 37 | ## Disclaimer 38 | 39 | **THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** 40 | 41 | --- 42 | 43 | ## Minimal Path to Awesome 44 | 45 | - Clone this repository 46 | - Ensure that you are at the solution folder 47 | - in the command-line run: 48 | - **npm install** 49 | - **gulp serve** 50 | 51 | > Include any additional steps as needed. 52 | 53 | ## Features 54 | 55 | Description of the extension that expands upon high-level summary above. 56 | 57 | This extension illustrates the following concepts: 58 | 59 | - topic 1 60 | - topic 2 61 | - topic 3 62 | 63 | > Notice that better pictures and documentation will increase the sample usage and the value you are providing for others. Thanks for your submissions advance. 64 | 65 | > Share your web part with others through Microsoft 365 Patterns and Practices program to get visibility and exposure. More details on the community, open-source projects and other activities from http://aka.ms/m365pnp. 66 | 67 | ## References 68 | 69 | - [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant) 70 | - [Building for Microsoft teams](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/build-for-teams-overview) 71 | - [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis) 72 | - [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview) 73 | - [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development -------------------------------------------------------------------------------- /SPFX/SPOQA/SearchSite.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /SPFX/SPOQA/asset/CheckUserProfilePhoto.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/asset/CheckUserProfilePhoto.JPG -------------------------------------------------------------------------------- /SPFX/SPOQA/asset/FixedNoCrawl.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/asset/FixedNoCrawl.JPG -------------------------------------------------------------------------------- /SPFX/SPOQA/asset/JobTitle.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/asset/JobTitle.JPG -------------------------------------------------------------------------------- /SPFX/SPOQA/asset/NoCrawl.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/asset/NoCrawl.JPG -------------------------------------------------------------------------------- /SPFX/SPOQA/asset/readme: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /SPFX/SPOQA/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json", 3 | "version": "2.0", 4 | "bundles": { 5 | "share-point-online-quick-assist-web-part": { 6 | "components": [ 7 | { 8 | "entrypoint": "./lib/webparts/sharePointOnlineQuickAssist/SharePointOnlineQuickAssistWebPart.js", 9 | "manifest": "./src/webparts/sharePointOnlineQuickAssist/SharePointOnlineQuickAssistWebPart.manifest.json" 10 | } 11 | ] 12 | }, 13 | "teams-quick-assist-web-part": { 14 | "components": [ 15 | { 16 | "entrypoint": "./lib/webparts/teamsQuickAssist/TeamsQuickAssistWebPart.js", 17 | "manifest": "./src/webparts/teamsQuickAssist/TeamsQuickAssistWebPart.manifest.json" 18 | } 19 | ] 20 | }, 21 | "exo-quick-assist-web-part": { 22 | "components": [ 23 | { 24 | "entrypoint": "./lib/webparts/exoQuickAssist/ExoQuickAssistWebPart.js", 25 | "manifest": "./src/webparts/exoQuickAssist/ExoQuickAssistWebPart.manifest.json" 26 | } 27 | ] 28 | } 29 | }, 30 | "externals": {}, 31 | "localizedResources": { 32 | "SharePointOnlineQuickAssistWebPartStrings": "lib/webparts/sharePointOnlineQuickAssist/loc/{locale}.js", 33 | "ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js", 34 | "TeamsQuickAssistWebPartStrings": "lib/webparts/teamsQuickAssist/loc/{locale}.js", 35 | "ExoQuickAssistWebPartStrings": "lib/webparts/exoQuickAssist/loc/{locale}.js" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SPFX/SPOQA/config/copy-assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json", 3 | "deployCdnPath": "./release/assets/" 4 | } 5 | -------------------------------------------------------------------------------- /SPFX/SPOQA/config/deploy-azure-storage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json", 3 | "workingDir": "./release/assets/", 4 | "account": "", 5 | "container": "spoqa", 6 | "accessKey": "" 7 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/config/package-solution.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", 3 | "solution": { 4 | "name": "SharePoint Online Quick Assist", 5 | "id": "029e4fc2-a440-4f5f-a358-b34a0eca54b5", 6 | "version": "1.22.07.13", 7 | "includeClientSideAssets": true, 8 | "webApiPermissionRequests": [ 9 | { 10 | "resource": "Microsoft Graph", 11 | "scope": "User.ReadBasic.All" 12 | }, 13 | { 14 | "resource": "Microsoft Graph", 15 | "scope": "User.Read.All" 16 | }, 17 | { 18 | "resource": "Microsoft Graph", 19 | "scope": "Group.Read.All" 20 | }, 21 | { 22 | "resource": "Microsoft Graph", 23 | "scope": "GroupMember.Read.All" 24 | }, 25 | { 26 | "resource": "Microsoft Graph", 27 | "scope": "Sites.Read.All" 28 | }, 29 | { 30 | "resource": "Microsoft Graph", 31 | "scope": "Files.Read.All" 32 | }, 33 | { 34 | "resource": "Microsoft Graph", 35 | "scope": "Directory.Read.All" 36 | } 37 | ], 38 | "isDomainIsolated": false, 39 | "developer": { 40 | "name": "Microsoft Corporation", 41 | "websiteUrl": "https://github.com/abrcheng/SharePointOnlineQuickAssist", 42 | "privacyUrl": "https://github.com/abrcheng/SharePointOnlineQuickAssist/tree/main/Documents/Privacy", 43 | "termsOfUseUrl": "https://github.com/abrcheng/SharePointOnlineQuickAssist/blob/main/Terms%20of%20Use", 44 | "mpnId": "5206095" 45 | } 46 | }, 47 | "paths": { 48 | "zippedPackage": "solution/spoqa.sppkg" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /SPFX/SPOQA/config/serve.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json", 3 | "port": 4321, 4 | "https": true, 5 | "initialPage": "https://localhost:5432/workbench", 6 | "api": { 7 | "port": 5432, 8 | "entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SPFX/SPOQA/config/write-manifests.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json", 3 | "cdnBasePath": "" 4 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const build = require('@microsoft/sp-build-web'); 4 | 5 | build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`); 6 | 7 | var getTasks = build.rig.getTasks; 8 | build.rig.getTasks = function () { 9 | var result = getTasks.call(build.rig); 10 | 11 | result.set('serve', result.get('serve-deprecated')); 12 | 13 | return result; 14 | }; 15 | 16 | build.initialize(require('gulp')); 17 | -------------------------------------------------------------------------------- /SPFX/SPOQA/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spoqa", 3 | "version": "1.22.1201", 4 | "private": true, 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "build": "gulp bundle", 8 | "clean": "gulp clean", 9 | "test": "gulp test" 10 | }, 11 | "dependencies": { 12 | "@microsoft/sp-core-library": "1.12.1", 13 | "@microsoft/sp-lodash-subset": "1.12.1", 14 | "@microsoft/sp-office-ui-fabric-core": "1.12.1", 15 | "@microsoft/sp-property-pane": "1.12.1", 16 | "@microsoft/sp-webpart-base": "1.12.1", 17 | "@pnp/spfx-controls-react": "3.3.0", 18 | "office-ui-fabric-react": "7.156.0", 19 | "react": "16.9.0", 20 | "react-dom": "16.9.0" 21 | }, 22 | "devDependencies": { 23 | "@microsoft/rush-stack-compiler-3.7": "0.2.3", 24 | "@microsoft/sp-build-web": "1.12.1", 25 | "@microsoft/sp-module-interfaces": "1.12.1", 26 | "@microsoft/sp-tslint-rules": "1.12.1", 27 | "@microsoft/sp-webpart-workbench": "1.12.1", 28 | "@types/microsoft-ajax": "0.0.37", 29 | "@types/react": "16.9.36", 30 | "@types/react-dom": "16.9.8", 31 | "@types/sharepoint": "^2016.1.10", 32 | "@types/webpack-env": "1.13.1", 33 | "ajv": "~5.2.2", 34 | "gulp": "~4.0.2" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SPFX/SPOQA/sharepoint/solution/spoqa.sppkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/sharepoint/solution/spoqa.sppkg -------------------------------------------------------------------------------- /SPFX/SPOQA/src/index.ts: -------------------------------------------------------------------------------- 1 | // A file is required to be in the root of the /src directory by the TypeScript compiler 2 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/Helpers/ContextHelper.ts: -------------------------------------------------------------------------------- 1 | import { WebPartContext } from "@microsoft/sp-webpart-base"; 2 | export default class ContextHelper 3 | { 4 | public static context:any; 5 | public static GetInstance():WebPartContext 6 | { 7 | return ContextHelper.context; 8 | } 9 | public static SetInstace(webpartContext:WebPartContext) 10 | { // window.wpContext = webpartContext; 11 | ContextHelper.context = webpartContext; 12 | } 13 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/Helpers/GraphAPIHelper.ts: -------------------------------------------------------------------------------- 1 | import {MSGraphClient,SPHttpClient} from '@microsoft/sp-http'; 2 | 3 | export default class GraphAPIHelper 4 | { 5 | 6 | public static async GetUserRoles(user: string, msGraphClient:MSGraphClient) 7 | { 8 | var res = await msGraphClient.api(`/rolemanagement/directory/transitiveRoleAssignments?$count=true&$filter=principalId+eq+%27${user}%27`).version('beta').header('ConsistencyLevel','Eventual').get(); 9 | if(res) 10 | { 11 | console.log(`GraphAPIHelper.GetUserRoles for user ${user} done.`); 12 | return await res; 13 | } 14 | else 15 | { 16 | var message = `Failed to get uesr ${user} roles from graph API`; 17 | console.log(message); 18 | Promise.reject(message); 19 | } 20 | } 21 | 22 | public static async GetUserInfo(user: string, msGraphClient:MSGraphClient) 23 | { 24 | var res = await msGraphClient.api(`/users/${user}`).get(); 25 | if(res) 26 | { 27 | console.log(`GraphAPIHelper.GetUserInfo for user ${user} done.`); 28 | return await res; 29 | } 30 | else 31 | { 32 | var message = `Failed to get uesr ${user} from graph API`; 33 | console.log(message); 34 | Promise.reject(message); 35 | } 36 | } 37 | 38 | public static async GetUserPhoto(user:string, msGraphClient:MSGraphClient) 39 | { 40 | var res = await msGraphClient.api(`/users/${user}/photo/$value`).responseType('blob').get(); 41 | if(res) 42 | { 43 | console.log(`GraphAPIHelper.GetUserPhoto for user ${user} done.`); 44 | return await res; 45 | } 46 | else 47 | { 48 | console.log("GraphAPIHelper.GetUserPhoto failed"); 49 | } 50 | } 51 | 52 | public static async GetGroupMembers(groupid:string, msGraphClient:MSGraphClient) 53 | { 54 | var res = await msGraphClient.api(`/groups/${groupid}/members?$select=id,mail`).get(); 55 | if(res) 56 | { 57 | console.log(`GraphAPIHelper.GetGroupMembers for user ${groupid} done.`); 58 | const graphResponse: any = res.value; 59 | return await graphResponse; 60 | } 61 | else 62 | { 63 | var message = `Failed to get uesr ${groupid} from graph API`; 64 | console.log(message); 65 | Promise.reject(message); 66 | } 67 | } 68 | 69 | public static async AddUserinMembers(groupid:string, msGraphClient:MSGraphClient, useremail:string) 70 | { 71 | 72 | var resUserInfo = await msGraphClient.api(`/me`).get(); 73 | console.log(`User info2: ${await resUserInfo["id"]}`); 74 | var userId = await resUserInfo["id"]; 75 | 76 | //var keyOdataId = `@odata.id`; 77 | //var valueODataId = `https://graph.microsoft.com/v1.0/directoryObjects/${useremail}`; 78 | 79 | //const directoryObject = `@"{{ ""${keyOdataId}"": ""${valueODataId}"" }}`; 80 | 81 | var body: string = JSON.stringify({ 82 | "@odata.id": `https://graph.microsoft.com/v1.0/directoryObjects/${userId}` 83 | }); 84 | 85 | var res = await msGraphClient.api(`/groups/${groupid}/members/$ref`).post(body); 86 | if(res) 87 | { 88 | console.log(`GraphAPIHelper.AddUserinMembers for user ${useremail} to ${groupid} done.`); 89 | const graphResponse: any = res.value; 90 | return await graphResponse; 91 | } 92 | else 93 | { 94 | var message = `Failed to add uesr ${useremail} to ${groupid} via graph API`; 95 | console.log(message); 96 | Promise.reject(message); 97 | } 98 | } 99 | 100 | public static async GetGroupByEmail(msGraphClient:MSGraphClient, groupMail:string) 101 | { 102 | var res = await msGraphClient.api(`/groups?$filter=mail eq '${groupMail}'`).get(); 103 | if(res) 104 | { 105 | console.log(`GraphAPIHelper.GetGroupByEmail for group ${groupMail} done, get ${res.value.length} groups.`); 106 | return await res; 107 | } 108 | else 109 | { 110 | var message = `Failed to get group ${groupMail} from graph API`; 111 | console.log(message); 112 | Promise.reject(message); 113 | } 114 | } 115 | 116 | public static async GetUserByEmail(msGraphClient:MSGraphClient, userMail:string) 117 | { 118 | var res = await msGraphClient.api(`/users?$filter=mail eq '${userMail}'`).get(); 119 | if(res) 120 | { 121 | console.log(`GraphAPIHelper.GetUserByEmail for user ${userMail} done, get ${res.value.length} users`); 122 | return await res; 123 | } 124 | else 125 | { 126 | var message = `Failed to get uesr ${userMail} from graph API`; 127 | console.log(message); 128 | Promise.reject(message); 129 | } 130 | } 131 | 132 | // Run Delta Query to get file changes in the library with a given driveId 133 | public static async CheckForUpdates(msGraphClient:MSGraphClient,nextxLink:string,siteID:string,startDate:Date,driveId:string) 134 | { 135 | var apiUri = ""; 136 | if(nextxLink) 137 | { 138 | apiUri = nextxLink.substring("https://graph.microsoft.com/v1.0".length); 139 | } 140 | else 141 | { 142 | if(startDate) 143 | { 144 | let DS: string = startDate.getFullYear() 145 | + '-' + ('0' + (startDate.getMonth()+1)).slice(-2) 146 | + '-' + ('0' + startDate.getDate()).slice(-2) 147 | + 'T00%3A00%3A00Z'; 148 | ///me/drive/root/delta?token=2021-09-29T00%3A00%3A00Z 149 | ///sites/01ed74ae-3f05-41fd-a81a-47359ecb3178/drives/b!rnTtAQU__UGoGkc1nssxeLAQmDVbtgtIsz-pxN0gD0sNoo9PFdTpTZXTWzJFHti4/root 150 | apiUri = `/sites/${siteID}/drives/${driveId}/root/delta?token=${DS}`; 151 | } 152 | else 153 | { 154 | apiUri = `/sites/${siteID}/drives/${driveId}/root/delta`; 155 | } 156 | } 157 | var res = await msGraphClient.api(apiUri).get(); 158 | if(res) 159 | { 160 | console.log(`GraphAPIHelper.CheckForUpdates done.`); 161 | return await res; 162 | } 163 | else 164 | { 165 | var message = `Failed to CheckForUpdates from graph API`; 166 | console.log(message); 167 | Promise.reject(message); 168 | } 169 | } 170 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/Helpers/ItemHelper.ts: -------------------------------------------------------------------------------- 1 | // This is a place holder 2 | /*import {SPHttpClient,ISPHttpClientOptions} from '@microsoft/sp-http'; 3 | import SPOQAHelper from './SPOQAHelper'; 4 | import RestAPIHelper from './RestAPIHelper'; 5 | 6 | export enum ItemType 7 | { 8 | ListItem=0, 9 | Document=1, 10 | Folder=2, 11 | UnKnown=-1 12 | } 13 | 14 | export default class ItemHelper 15 | { 16 | public static async TryGetItemByFullUrl(spHttpClient:SPHttpClient, siteAbsoluteUrl:string, listRootFolder:string, fullDocmentPath:string) 17 | { 18 | siteAbsoluteUrl = decodeURI(siteAbsoluteUrl); 19 | listRootFolder = decodeURI(listRootFolder); 20 | fullDocmentPath = decodeURI(fullDocmentPath); 21 | } 22 | }*/ 23 | 24 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/Helpers/RemedyHelper.ts: -------------------------------------------------------------------------------- 1 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 2 | // Helper class for Remedy Steps 3 | export class RemedyHelper 4 | { 5 | private static remedyStyle = "color:black"; 6 | 7 | // Build the html string according to the remedySteps 8 | public static GetRemedyHtml(remedySteps:any[]) 9 | { 10 | var remedyHtml=`

`; 11 | // Dispaly remedy steps 12 | remedySteps.forEach(step=>{ 13 | var message =step.message; 14 | if(step.message[step.message.length-1] ==".") 15 | { 16 | message = message.substr(0, step.message.length-1); 17 | } 18 | var fixpage = ""; 19 | if(step.url) 20 | { 21 | fixpage = ` ${strings.CanBeFixedIn} ${strings.ThisPage}`; 22 | } 23 | remedyHtml+=`
${message}${fixpage}.
`; 24 | }); 25 | 26 | return remedyHtml; 27 | } 28 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/Helpers/SPOQAHelper.ts: -------------------------------------------------------------------------------- 1 | export default class SPOQAHelper 2 | { 3 | public static Show(id:string):void 4 | { 5 | let sPOQASpinner:any = document.querySelector(`#${id}`); 6 | sPOQASpinner.style.display = ""; 7 | } 8 | 9 | public static Hide(id:string):void 10 | { 11 | let sPOQASpinner:any = document.querySelector(`#${id}`); 12 | sPOQASpinner.style.display = "none"; 13 | } 14 | 15 | /* 16 | SPOQAErrorMessageBarContainer 17 | SPOQASuccessMessageBarContainer 18 | SPOQAWarningMessageBarContainer 19 | SPOQAInfoMessageBarContainer 20 | */ 21 | public static ShowMessageBar(barType:string, message:string):void 22 | { 23 | // SPOQASuccessMessageBar 24 | const barTypes:String[] = ["Error", "Success", "Warning", "Info"]; 25 | if(barTypes.indexOf(barType) >=0) 26 | { 27 | document.querySelector(`#SPOQA${barType}MessageBar`).innerHTML = `${message}`; 28 | SPOQAHelper.Show(`SPOQA${barType}MessageBarContainer`); 29 | } 30 | else 31 | { 32 | console.log(`Only accept bar type "Error", "Success", "Warning", "Info"`); 33 | } 34 | } 35 | 36 | public static ResetFormStaus():void 37 | { 38 | SPOQAHelper.Hide("SPOQAErrorMessageBarContainer"); 39 | SPOQAHelper.Hide("SPOQASuccessMessageBarContainer"); 40 | SPOQAHelper.Hide("SPOQAWarningMessageBarContainer"); 41 | SPOQAHelper.Hide("SPOQAInfoMessageBarContainer"); 42 | } 43 | 44 | public static ValidateEmail(email:string):boolean 45 | { 46 | const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 47 | return re.test(email); 48 | } 49 | 50 | public static ValidateUrl(url:string):boolean 51 | { 52 | var pattern = new RegExp('^(https:\\/\\/)?'+ // protocol 53 | '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name 54 | '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address 55 | '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path 56 | '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string 57 | '(\\#[-a-z\\d_]*)?$','i'); // fragment locator 58 | 59 | return pattern.test(url); 60 | } 61 | 62 | public static ParseQueryString(queryString?: string): any { 63 | // if the query string is NULL or undefined 64 | if (!queryString) { 65 | queryString = window.location.search.substring(1); 66 | } 67 | const params = {}; 68 | const queries = queryString.split("&"); 69 | queries.forEach((indexQuery: string) => { 70 | const indexPair = indexQuery.split("="); 71 | const queryKey = decodeURIComponent(indexPair[0]); 72 | const queryValue = decodeURIComponent(indexPair.length > 1 ? indexPair[1] : ""); 73 | params[queryKey] = queryValue; 74 | }); 75 | return params; 76 | } 77 | 78 | public static GenerateUUID():string { 79 | var d = new Date().getTime();//Timestamp 80 | var d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported 81 | // tslint:disable-next-line:no-function-expression 82 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 83 | var r = Math.random() * 16;//random number between 0 and 16 84 | if(d > 0){//Use timestamp until depleted 85 | r = (d + r)%16 | 0; 86 | d = Math.floor(d/16); 87 | } else {//Use microseconds since page-load if supported 88 | r = (d2 + r)%16 | 0; 89 | d2 = Math.floor(d2/16); 90 | } 91 | return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); 92 | }); 93 | } 94 | 95 | public static JSONToCSVConvertor(JSONData:any, showLabel:boolean, fileName:string):void { 96 | //If JSONData is not an object then JSON.parse will parse the JSON string in an Object 97 | var arrData = typeof JSONData != 'object' ? JSON.parse(JSONData) : JSONData; 98 | 99 | var CSV = ""; 100 | 101 | //This condition will generate the Label/Header 102 | if (showLabel) { 103 | var row = ""; 104 | 105 | //This loop will extract the label from 1st index of on array 106 | for (var index in arrData[0]) { 107 | 108 | //Now convert each value to string and comma-seprated 109 | row += index + ','; 110 | } 111 | 112 | row = row.slice(0, -1); 113 | 114 | //append Label row with line break 115 | CSV += row + '\r\n'; 116 | } 117 | 118 | //1st loop is to extract each row 119 | for (var i = 0; i < arrData.length; i++) { 120 | row = ""; 121 | 122 | //2nd loop will extract each column and convert it in string comma-seprated 123 | for (index in arrData[i]) { 124 | row += '"' + arrData[i][index] + '",'; 125 | } 126 | 127 | row.slice(0, row.length - 1); 128 | 129 | //add a line break after each row 130 | CSV += row + '\r\n'; 131 | } 132 | 133 | if (CSV == '') { 134 | alert("Invalid data"); 135 | return; 136 | } 137 | 138 | 139 | //Initialize file format you want csv or xls 140 | var uri = 'data:text/csv;charset=utf-8,%EF%BB%BF' + encodeURIComponent(CSV); 141 | 142 | // Now the little tricky part. 143 | // you can use either>> window.open(uri); 144 | // but this will not work in some browsers 145 | // or you will not get the correct file extension 146 | 147 | //this trick will generate a temp tag 148 | var link = document.createElement("a"); 149 | link.href = uri; 150 | 151 | //set the visibility hidden so it will not effect on your web-layout 152 | link.style.display = "none"; 153 | link.download = fileName + ".csv"; 154 | 155 | //this part will append the anchor tag and remove it after automatic click 156 | document.body.appendChild(link); 157 | link.click(); 158 | document.body.removeChild(link); 159 | } 160 | 161 | // 2022-02-12T17:28:49.3538784+08:00 162 | 163 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/Helpers/SPOQASpinner.ts: -------------------------------------------------------------------------------- 1 | export default class SPOQASpinner 2 | { 3 | public static Show(label:string) 4 | { 5 | document.querySelector("#SPOQASpinner >.ms-Spinner-label").innerHTML = label; 6 | let sPOQASpinner:any = document.querySelector("#SPOQASpinner"); 7 | sPOQASpinner.style.display = ""; 8 | } 9 | 10 | public static Hide() 11 | { 12 | let sPOQASpinner:any = document.querySelector("#SPOQASpinner"); 13 | sPOQASpinner.style.display = "none"; 14 | } 15 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/ExoQuickAssistWebPart.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json", 3 | "id": "6e9d3cc3-8c9d-4d11-893a-50179561b893", 4 | "alias": "ExoQuickAssistWebPart", 5 | "componentType": "WebPart", 6 | 7 | // The "*" signifies that the version should be taken from the package.json 8 | "version": "*", 9 | "manifestVersion": 2, 10 | 11 | // If true, the component can only be installed on sites where Custom Script is allowed. 12 | // Components that allow authors to embed arbitrary script code should set this to true. 13 | // https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f 14 | "requiresCustomScript": false, 15 | "supportedHosts": ["SharePointWebPart"], 16 | 17 | "preconfiguredEntries": [{ 18 | "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other 19 | "group": { "default": "Other" }, 20 | "title": { "default": "EXOQuickAssist" }, 21 | "description": { "default": "This tool can provide quick assist on Exchange Online issues, empower customer to resolve SharePoint Online issues quickly by themselves." }, 22 | "officeFabricIconFontName": "Page", 23 | "properties": { 24 | "description": "EXOQuickAssist" 25 | } 26 | }] 27 | } 28 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/ExoQuickAssistWebPart.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDom from 'react-dom'; 3 | import { Version } from '@microsoft/sp-core-library'; 4 | import { 5 | IPropertyPaneConfiguration, 6 | PropertyPaneTextField 7 | } from '@microsoft/sp-property-pane'; 8 | import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; 9 | 10 | import * as strings from 'ExoQuickAssistWebPartStrings'; 11 | import ExoQuickAssist from './components/ExoQuickAssist'; 12 | import { IExoQuickAssistProps } from './components/IExoQuickAssistProps'; 13 | import { SPComponentLoader } from '@microsoft/sp-loader'; 14 | import * as contextHelper from '../Helpers/ContextHelper'; 15 | import {MSGraphClient, SPHttpClient} from '@microsoft/sp-http'; 16 | 17 | export interface IExoQuickAssistWebPartProps { 18 | description: string; 19 | } 20 | 21 | export default class ExoQuickAssistWebPart extends BaseClientSideWebPart { 22 | 23 | private graphClient: MSGraphClient; 24 | 25 | constructor() { 26 | super(); 27 | contextHelper.default.SetInstace(this.context); 28 | SPComponentLoader.loadCss('https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/6.0.0/css/fabric-6.0.0.scoped.css'); 29 | } 30 | 31 | public render(): void { 32 | const element: React.ReactElement = React.createElement( 33 | ExoQuickAssist, 34 | { 35 | msGraphClient: this.graphClient, 36 | currentUser:this.context.pageContext.user, 37 | ctx:this.context 38 | } 39 | ); 40 | 41 | ReactDom.render(element, this.domElement); 42 | } 43 | 44 | protected onDispose(): void { 45 | ReactDom.unmountComponentAtNode(this.domElement); 46 | } 47 | 48 | protected get dataVersion(): Version { 49 | return Version.parse('1.0'); 50 | } 51 | 52 | protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { 53 | return { 54 | pages: [] 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/components/ExoQuickAssist.module.scss: -------------------------------------------------------------------------------- 1 | @import '~office-ui-fabric-react/dist/sass/References.scss'; 2 | 3 | .exoQuickAssist { 4 | .container { 5 | max-width: 100%; 6 | margin: 0px auto; 7 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1); 8 | } 9 | 10 | .row { 11 | @include ms-Grid-row; 12 | @include ms-fontColor-white; 13 | //background-color: $ms-color-themeDark; 14 | padding: 10px; 15 | } 16 | 17 | .column { 18 | @include ms-Grid-col; 19 | @include ms-lg10; 20 | @include ms-xl8; 21 | @include ms-xlPush2; 22 | @include ms-lgPush1; 23 | } 24 | 25 | .msgrid 26 | { 27 | @include ms-Grid; 28 | padding-top: 0px; 29 | } 30 | 31 | .msrow 32 | { 33 | @include ms-Grid-row; 34 | } 35 | 36 | .mscol6 37 | { 38 | @include ms-Grid-col; 39 | @include ms-sm6; 40 | @include ms-md6; 41 | padding-left: 0px; 42 | } 43 | 44 | .mscol8 45 | { 46 | @include ms-Grid-col; 47 | @include ms-sm8; 48 | @include ms-md8; 49 | padding-left: 0px; 50 | } 51 | 52 | .mscol4 53 | { 54 | @include ms-Grid-col; 55 | @include ms-sm4; 56 | @include ms-md4; 57 | padding-left: 0px; 58 | } 59 | 60 | .title { 61 | @include ms-font-xl; 62 | @include ms-fontColor-black; 63 | } 64 | 65 | .subTitle { 66 | @include ms-font-l; 67 | @include ms-fontColor-black; 68 | } 69 | 70 | .description { 71 | @include ms-font-l; 72 | @include ms-fontColor-black; 73 | } 74 | 75 | .button { 76 | // Our button 77 | text-decoration: none; 78 | height: 32px; 79 | 80 | // Primary Button 81 | min-width: 80px; 82 | background-color: $ms-color-themePrimary; 83 | border-color: $ms-color-themePrimary; 84 | color: $ms-color-white; 85 | 86 | // Basic Button 87 | outline: transparent; 88 | position: relative; 89 | font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif; 90 | -webkit-font-smoothing: antialiased; 91 | font-size: $ms-font-size-m; 92 | font-weight: $ms-font-weight-regular; 93 | border-width: 0; 94 | text-align: center; 95 | cursor: pointer; 96 | display: inline-block; 97 | padding: 0 16px; 98 | 99 | .label { 100 | font-weight: $ms-font-weight-semibold; 101 | font-size: $ms-font-size-m; 102 | height: 32px; 103 | line-height: 32px; 104 | margin: 0 4px; 105 | vertical-align: top; 106 | display: inline-block; 107 | } 108 | } 109 | } 110 | 111 | 112 | // Overwrite margin for .ms-ComboBox-option 113 | :global(.ms-ComboBox-option) { 114 | margin-left: 15px; 115 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/components/ExoQuickAssist.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styles from './ExoQuickAssist.module.scss'; 3 | import { IExoQuickAssistProps } from './IExoQuickAssistProps'; 4 | import { escape } from '@microsoft/sp-lodash-subset'; 5 | import { 6 | ComboBox, 7 | Fabric, 8 | IComboBox, 9 | IComboBoxOption, 10 | mergeStyles, 11 | SelectableOptionMenuItemType, 12 | Spinner, 13 | MessageBar, 14 | MessageBarType 15 | } from 'office-ui-fabric-react/lib/index'; 16 | 17 | import * as strings from 'ExoQuickAssistWebPartStrings'; 18 | import PeopleInsightsQA from './OrganizationSettings/PeopleInsightsQA'; 19 | import SPOQAHelper from '../../Helpers/SPOQAHelper'; 20 | 21 | const wrapperClassName = mergeStyles({ 22 | selectors: { 23 | '& > *': { marginBottom: '20px' }, 24 | '& .ms-ComboBox': { maxWidth: '300px' }, 25 | '& .ms-ComboBox-option':{marginLeft:"15px"} 26 | } 27 | }); 28 | 29 | const INITIAL_OPTIONS: IComboBoxOption[] = [ 30 | { key: 'OrganizationSettings', text: strings.OrganizationSettings, itemType: SelectableOptionMenuItemType.Header }, 31 | { key: 'PeopleInsights', text: strings.PeopleInsights}] 32 | 33 | export default class ExoQuickAssist extends React.Component { 34 | public state = { 35 | selectedKey: "" 36 | }; 37 | 38 | public render(): React.ReactElement { 39 | 40 | const teamsQADetail = () => { 41 | switch(this.state.selectedKey) { 42 | case "PeopleInsights": return ; 43 | default: return
; 44 | } 45 | }; 46 | 47 | return ( 48 |
49 | 50 |
51 |
52 |
53 | {strings.WelcomeToEXOQA} 54 |
55 |
56 | 57 |
58 |
59 |
60 | , option?: IComboBoxOption): void => { 68 | this.setState({ selectedKey: option.key});}} 69 | /> 70 |
71 |
72 |
73 | 74 |
75 |
76 | {teamsQADetail()} 77 |
78 |
79 |
80 |
81 |
82 | 83 |
84 | {SPOQAHelper.Hide("SPOQAErrorMessageBarContainer");}} dismissButtonAriaLabel="Close" > 85 | SPOQAErrorMessageBar 86 | 87 |
88 |
89 | {SPOQAHelper.Hide("SPOQASuccessMessageBarContainer");}} dismissButtonAriaLabel="Close" > 90 | SPOQASuccessMessageBar 91 | 92 |
93 |
94 | {SPOQAHelper.Hide("SPOQAWarningMessageBarContainer");}} dismissButtonAriaLabel="Close"> 95 | SPOQAWarningMessageBar 96 | 97 |
98 |
99 | {SPOQAHelper.Hide("SPOQAInfoMessageBarContainer");}} dismissButtonAriaLabel="Close"> 100 | SPOQAInfoMessageBar 101 | 102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | ); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/components/IExoQuickAssistProps.ts: -------------------------------------------------------------------------------- 1 | import { WebPartContext } from "@microsoft/sp-webpart-base"; 2 | import {MSGraphClient, SPHttpClient} from '@microsoft/sp-http'; 3 | import {SPUser} from '@microsoft/sp-page-context'; 4 | 5 | export interface IExoQuickAssistProps { 6 | msGraphClient:MSGraphClient; 7 | // spHttpClient:SPHttpClient; 8 | // webAbsoluteUrl:string; 9 | // webUrl:string; 10 | // rootUrl:string; 11 | currentUser:SPUser; 12 | ctx:WebPartContext; 13 | } 14 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/components/OrganizationSettings/PeopleInsightsQA.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { IExoQuickAssistProps } from '../IExoQuickAssistProps'; 3 | import styles from '../ExoQuickAssist.module.scss'; 4 | import { 5 | PrimaryButton, 6 | TextField, 7 | Label 8 | } from 'office-ui-fabric-react/lib/index'; 9 | 10 | import * as strings from 'ExoQuickAssistWebPartStrings'; 11 | 12 | export default class TestTeamsQA extends React.Component 13 | { 14 | public state = { 15 | affectedUser:this.props.currentUser.loginName, 16 | isNeedFix:false 17 | }; 18 | 19 | public render(): React.ReactElement { 20 | return ( 21 |
22 |
23 |
24 | {let text:any = e.target; this.setState({affectedUser:text.value});}} 28 | value={this.state.affectedUser} 29 | required={true} 30 | /> 31 | 32 | 33 | {this.Check();}} 37 | /> 38 | 39 | { this.state.isNeedFix ? 40 | {this.ShowRemedy();}} 44 | />: null} 45 |
46 |
47 |
48 | ); 49 | } 50 | 51 | private Check() 52 | { 53 | 54 | } 55 | 56 | private ShowRemedy() 57 | { 58 | 59 | } 60 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/loc/en-us.js: -------------------------------------------------------------------------------- 1 | define([], function() { 2 | return { 3 | WelcomeToEXOQA:"Welcome to use EXO Quick Assist", 4 | OrganizationSettings:"Organization Settings", 5 | PeopleInsights:"People Insights", 6 | SelectIssueTip:"Please select issue which you want to check", 7 | CheckIssue:"Check Issue", 8 | ShowRemedySteps:"Show Remedy Steps", 9 | AffectedUser:"Affected User:" 10 | } 11 | }); -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/loc/ja-jp.js: -------------------------------------------------------------------------------- 1 | define([], function() { 2 | return { 3 | WelcomeToEXOQA:"Welcome to use EXO Quick Assist", 4 | OrganizationSettings:"Organization Settings", 5 | PeopleInsights:"People Insights", 6 | SelectIssueTip:"Please select issue which you want to check", 7 | CheckIssue:"Check Issue", 8 | ShowRemedySteps:"Show Remedy Steps", 9 | AffectedUser:"Affected User:" 10 | } 11 | }); -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/loc/mystrings.d.ts: -------------------------------------------------------------------------------- 1 | declare interface IExoQuickAssistWebPartStrings { 2 | WelcomeToEXOQA:string, 3 | OrganizationSettings:string, 4 | PeopleInsights:string, 5 | SelectIssueTip:string, 6 | CheckIssue:string, 7 | ShowRemedySteps:string, 8 | AffectedUser:string 9 | } 10 | 11 | declare module 'ExoQuickAssistWebPartStrings' { 12 | const strings: IExoQuickAssistWebPartStrings; 13 | export = strings; 14 | } 15 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/exoQuickAssist/loc/zh-cn.js: -------------------------------------------------------------------------------- 1 | define([], function() { 2 | return { 3 | WelcomeToEXOQA:"Welcome to use EXO Quick Assist", 4 | OrganizationSettings:"Organization Settings", 5 | PeopleInsights:"People Insights", 6 | SelectIssueTip:"Please select issue which you want to check", 7 | CheckIssue:"Check Issue", 8 | ShowRemedySteps:"Show Remedy Steps", 9 | AffectedUser:"Affected User:" 10 | } 11 | }); -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/SharePointOnlineQuickAssistWebPart.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDom from 'react-dom'; 3 | import { Version } from '@microsoft/sp-core-library'; 4 | import { 5 | IPropertyPaneConfiguration, 6 | PropertyPaneTextField 7 | } from '@microsoft/sp-property-pane'; 8 | import { BaseClientSideWebPart, WebPartContext } from '@microsoft/sp-webpart-base'; 9 | 10 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 11 | import SharePointOnlineQuickAssist from './components/SharePointOnlineQuickAssist'; 12 | import { ISharePointOnlineQuickAssistProps } from './components/ISharePointOnlineQuickAssistProps'; 13 | import { SPComponentLoader } from '@microsoft/sp-loader'; 14 | import * as contextHelper from '../Helpers/ContextHelper'; 15 | import {MSGraphClient, SPHttpClient} from '@microsoft/sp-http'; 16 | 17 | export interface ISharePointOnlineQuickAssistWebPartProps { 18 | description: string; 19 | } 20 | 21 | export default class SharePointOnlineQuickAssistWebPart extends BaseClientSideWebPart { 22 | private graphClient: MSGraphClient; 23 | 24 | constructor() { 25 | super(); 26 | contextHelper.default.SetInstace(this.context); 27 | SPComponentLoader.loadCss('https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/6.0.0/css/fabric-6.0.0.scoped.css'); 28 | } 29 | 30 | public onInit(): Promise { 31 | return new Promise((resolve: () => void, reject: (error: any) => void): void => { 32 | this.context.msGraphClientFactory 33 | .getClient() 34 | .then((client: MSGraphClient): void => { 35 | this.graphClient = client; 36 | resolve(); 37 | }, err => reject(err)); 38 | }); 39 | } 40 | 41 | public render(): void { 42 | const element: React.ReactElement = React.createElement( 43 | SharePointOnlineQuickAssist, 44 | { 45 | msGraphClient: this.graphClient, 46 | spHttpClient:this.context.spHttpClient, 47 | webAbsoluteUrl:this.context.pageContext.web.absoluteUrl, 48 | webUrl:this.context.pageContext.legacyPageContext["webServerRelativeUrl"], 49 | rootUrl:this.context.pageContext.site.absoluteUrl.indexOf(".sharepoint.com") >1 ? this.context.pageContext.site.absoluteUrl.substring(0,this.context.pageContext.site.absoluteUrl.indexOf(".sharepoint.com")+(".sharepoint.com").length): this.context.pageContext.site.absoluteUrl.substring(0,this.context.pageContext.site.absoluteUrl.indexOf(".sharepoint.cn")+(".sharepoint.cn").length), 50 | currentUser:this.context.pageContext.user, 51 | ctx:this.context 52 | } 53 | ); 54 | 55 | ReactDom.render(element, this.domElement); 56 | } 57 | 58 | protected onDispose(): void { 59 | ReactDom.unmountComponentAtNode(this.domElement); 60 | } 61 | 62 | protected get dataVersion(): Version { 63 | return Version.parse('1.0'); 64 | } 65 | 66 | protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { 67 | return { 68 | pages: [] 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/ISharePointOnlineQuickAssistProps.ts: -------------------------------------------------------------------------------- 1 | import { WebPartContext } from "@microsoft/sp-webpart-base"; 2 | import {MSGraphClient, SPHttpClient} from '@microsoft/sp-http'; 3 | import {SPUser} from '@microsoft/sp-page-context'; 4 | export interface ISharePointOnlineQuickAssistProps { 5 | msGraphClient:MSGraphClient; 6 | spHttpClient:SPHttpClient; 7 | webAbsoluteUrl:string; 8 | webUrl:string; 9 | rootUrl:string; 10 | currentUser:SPUser; 11 | ctx:WebPartContext; 12 | } 13 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Search/CrawlLogGrid.tsx: -------------------------------------------------------------------------------- 1 | import { ICrawlLog,ICrawlLogs } from "./ICrawlLog"; 2 | import { DetailsList, DetailsListLayoutMode, SelectionMode, IColumn } from 'office-ui-fabric-react/lib/DetailsList'; 3 | import * as React from 'react'; 4 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 5 | export default class CrawlLogGrid extends React.Component 6 | { 7 | private columns: IColumn[] = [ 8 | { 9 | key: 'TimeStamp', 10 | name: strings.SD_CrawlTimeStamp, 11 | fieldName: 'TimeStamp', 12 | minWidth: 100, 13 | maxWidth: 100, 14 | isResizable: true, 15 | isCollapsible: true, 16 | data: 'string', 17 | onRender: (item: ICrawlLog) => { 18 | return
{item.TimeStamp}
; 19 | }, 20 | isPadded: true, 21 | }, 22 | { 23 | key: 'Path', 24 | name: strings.SD_CrawlPath, 25 | fieldName: 'Path', 26 | minWidth: 120, 27 | maxWidth: 120, 28 | isResizable: true, 29 | isCollapsible: true, 30 | data: 'string', 31 | onRender: (item: ICrawlLog) => { 32 | return
{item.FullUrl}
; 33 | }, 34 | isPadded: true 35 | }, 36 | { 37 | key: 'ErrorCode', 38 | name: strings.SD_CrawlErrorCode, 39 | fieldName: 'ErrorCode', 40 | minWidth: 30, 41 | maxWidth: 60, 42 | isResizable: true, 43 | isCollapsible: true, 44 | data: 'string', 45 | onRender: (item: ICrawlLog) => { 46 | return {item.ErrorCode}; 47 | }, 48 | isPadded: true 49 | }, 50 | { 51 | key: 'IsDeleted', 52 | name: strings.SD_CrawlIsDeleted, 53 | fieldName: 'IsDeleted', 54 | minWidth: 30, 55 | maxWidth: 60, 56 | isResizable: true, 57 | isCollapsible: true, 58 | data: 'string', 59 | onRender: (item: ICrawlLog) => { 60 | return {item.IsDeleted}; 61 | }, 62 | isPadded: true 63 | }, 64 | { 65 | key: 'DeletePending', 66 | name: strings.SD_CrawlDeletePending, 67 | fieldName: 'DeletePending', 68 | minWidth: 30, 69 | maxWidth: 60, 70 | isResizable: true, 71 | isCollapsible: true, 72 | data: 'string', 73 | onRender: (item: ICrawlLog) => { 74 | return {item.DeletePending}; 75 | }, 76 | isPadded: true 77 | }, 78 | { 79 | key: 'DeleteReason', 80 | name: strings.SD_CrawlDeleteReason, 81 | fieldName: 'DeleteReason', 82 | minWidth: 30, 83 | maxWidth: 60, 84 | isResizable: true, 85 | isCollapsible: true, 86 | data: 'string', 87 | onRender: (item: ICrawlLog) => { 88 | return {item.DeleteReason}; 89 | }, 90 | isPadded: true 91 | }, 92 | { 93 | key: 'ExReason', 94 | name: strings.SD_CrawlExclusionReason, 95 | fieldName: 'ExReason', 96 | minWidth: 30, 97 | maxWidth: 60, 98 | isResizable: true, 99 | isCollapsible: true, 100 | data: 'string', 101 | onRender: (item: ICrawlLog) => { 102 | return {item.ExclusionReason}; 103 | }, 104 | isPadded: true 105 | }, 106 | { 107 | key: 'ErrorDesc', 108 | name: strings.SD_CrawlErrorDesc, 109 | fieldName: 'ErrorDesc', 110 | minWidth: 120, 111 | maxWidth: 120, 112 | isResizable: true, 113 | isCollapsible: true, 114 | data: 'string', 115 | onRender: (item: ICrawlLog) => { 116 | return
{item.ErrorDesc}
; 117 | }, 118 | isPadded: true 119 | } 120 | ]; 121 | 122 | public state = { 123 | items:this.props.items, 124 | columns:this.columns}; 125 | 126 | public render():React.ReactElement 127 | { 128 | const { items, columns} = this.state; 129 | return
130 |
Crawl Logs:
131 | {this.state.items && this.state.items.length >0 ? 132 | : strings.RI_NoData} 140 |
; 141 | } 142 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Search/CrawledPropertyGrid.tsx: -------------------------------------------------------------------------------- 1 | import { DetailsList, DetailsListLayoutMode, SelectionMode, IColumn } from 'office-ui-fabric-react/lib/DetailsList'; 2 | import { 3 | DefaultButton, 4 | TextField, 5 | } from 'office-ui-fabric-react/lib/index'; 6 | import * as React from 'react'; 7 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 8 | import { ICrawledProperty,ICrawledProperties } from "./ICrawledProperty"; 9 | import SPOQAHelper from '../../../Helpers/SPOQAHelper'; 10 | export default class CrawledPropertyGrid extends React.Component 11 | { 12 | private columns: IColumn[] = [ 13 | { 14 | key: 'Name', 15 | name: strings.SD_PropertyName, 16 | fieldName: 'Name', 17 | minWidth: 200, 18 | maxWidth: 400, 19 | isResizable: true, 20 | isCollapsible: true, 21 | data: 'string', 22 | onRender: (item: ICrawledProperty) => { 23 | return
{item.Name}
; 24 | }, 25 | isPadded: true, 26 | }]; 27 | 28 | public state = { 29 | items:this.props.items, 30 | columns:this.columns 31 | }; 32 | 33 | public render():React.ReactElement 34 | { 35 | const { items, columns} = this.state; 36 | return
37 |
38 | 39 | {let text:any = e.target; this.FilterCrawledProperty(text.value);}} 43 | // value={this.state.keywordFilter} 44 | // onKeyDown={(e)=>{if(e.keyCode ===13){}}} 45 | style={{ display: 'inline'}} 46 | /> 47 | {this.DoExport();}} 51 | /> 52 | 53 |
54 | {this.state.items && this.state.items.length >0 ? 55 | : strings.RI_NoData} 62 |
; 63 | } 64 | 65 | private DoExport():void 66 | { 67 | // Export CrawledProperty 68 | SPOQAHelper.JSONToCSVConvertor(this.props.items, true, "CrawledProperty"); 69 | } 70 | 71 | private FilterCrawledProperty(cpFilter:string) { 72 | cpFilter = cpFilter.trim(); 73 | if(cpFilter.length >=1) 74 | { 75 | var filteredItems = []; 76 | this.props.items.forEach(e=>{ 77 | if((e.Name && e.Name.toLowerCase().indexOf(cpFilter.toLowerCase()) >=0)) 78 | { 79 | filteredItems.push( 80 | { 81 | Name:e.Name 82 | } 83 | ); 84 | } 85 | }); 86 | this.setState({items:filteredItems}); 87 | } 88 | else if(!cpFilter || cpFilter=="") 89 | { 90 | this.setState({items:this.props.items}); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Search/ICrawlLog.ts: -------------------------------------------------------------------------------- 1 | export interface ICrawlLog { 2 | FullUrl:string; 3 | IsDeleted:string; 4 | ExclusionReason:string; 5 | DeleteReason:string; 6 | ErrorCode:string; 7 | TimeStamp:string; 8 | ErrorDesc:string; 9 | DeletePending:string; 10 | } 11 | 12 | export interface ICrawlLogs 13 | { 14 | items:ICrawlLog[]; 15 | } 16 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Search/ICrawledProperty.ts: -------------------------------------------------------------------------------- 1 | export interface ICrawledProperty { 2 | Name:string; 3 | } 4 | 5 | export interface ICrawledProperties 6 | { 7 | items:ICrawledProperty[]; 8 | } 9 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Search/IManagedProperty.ts: -------------------------------------------------------------------------------- 1 | export interface IManagedProperty { 2 | Name:string; 3 | Value:string; 4 | } 5 | 6 | export interface IManagedProperties 7 | { 8 | items:IManagedProperty[]; 9 | } 10 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Search/ManagedPropertyGrid.tsx: -------------------------------------------------------------------------------- 1 | import { DetailsList, DetailsListLayoutMode, SelectionMode, IColumn } from 'office-ui-fabric-react/lib/DetailsList'; 2 | import { 3 | DefaultButton, 4 | TextField, 5 | } from 'office-ui-fabric-react/lib/index'; 6 | import * as React from 'react'; 7 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 8 | import { IManagedProperty,IManagedProperties } from "./IManagedProperty"; 9 | import SPOQAHelper from '../../../Helpers/SPOQAHelper'; 10 | export default class ManagedPropertyGrid extends React.Component 11 | { 12 | private columns: IColumn[] = [ 13 | { 14 | key: 'Name', 15 | name: strings.SD_PropertyName, 16 | fieldName: 'Name', 17 | minWidth: 100, 18 | maxWidth: 150, 19 | isResizable: true, 20 | isCollapsible: true, 21 | data: 'string', 22 | onRender: (item: IManagedProperty) => { 23 | return
{item.Name}
; 24 | }, 25 | isPadded: true, 26 | }, 27 | { 28 | key: 'Value', 29 | name: strings.SD_PropertyValue, 30 | fieldName: 'Value', 31 | minWidth: 200, 32 | maxWidth: 300, 33 | isResizable: true, 34 | isCollapsible: true, 35 | data: 'string', 36 | onRender: (item: IManagedProperty) => { 37 | return
{item.Value}
; 38 | }, 39 | isPadded: true 40 | }]; 41 | 42 | public state = { 43 | items:this.props.items, 44 | columns:this.columns 45 | }; 46 | 47 | public render():React.ReactElement 48 | { 49 | const { items, columns} = this.state; 50 | return
51 |
52 | 53 | {let text:any = e.target; this.FilterManagedProperty(text.value);}} 57 | // value={this.state.keywordFilter} 58 | // onKeyDown={(e)=>{if(e.keyCode ===13){}}} 59 | style={{ display: 'inline'}} 60 | /> 61 | {this.DoExport();}} 65 | /> 66 | 67 |
68 | {this.state.items && this.state.items.length >0 ? 69 | : strings.RI_NoData} 76 |
; 77 | } 78 | 79 | private DoExport():void 80 | { 81 | // Export ManagedProperty 82 | SPOQAHelper.JSONToCSVConvertor(this.props.items, true, "ManagedProperties"); 83 | } 84 | 85 | private FilterManagedProperty(mpFilter:string) { 86 | mpFilter = mpFilter.trim(); 87 | if(mpFilter.length >=1) 88 | { 89 | var filteredItems = []; 90 | this.props.items.forEach(e=>{ 91 | if((e.Name && e.Name.toLowerCase().indexOf(mpFilter.toLowerCase()) >=0)||(e.Value && e.Value.toLowerCase().indexOf(mpFilter.toLowerCase()) >=0)) 92 | { 93 | filteredItems.push( 94 | { 95 | Name:e.Name, 96 | Value:e.Value 97 | } 98 | ); 99 | } 100 | }); 101 | this.setState({items:filteredItems}); 102 | } 103 | else if(!mpFilter || mpFilter=="") 104 | { 105 | this.setState({items:this.props.items}); 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Search/SearchLibrary.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | DefaultButton 4 | } from 'office-ui-fabric-react/lib/index'; 5 | import { ISharePointOnlineQuickAssistProps } from '../ISharePointOnlineQuickAssistProps'; 6 | 7 | export default class SearchLibraryQA extends React.Component 8 | { 9 | public render():React.ReactElement 10 | { 11 | return ( 12 |
13 | {alert("clicked"); }} 17 | /> 18 |
19 | ); 20 | } 21 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Search/SearchPeople.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | DefaultButton 4 | } from 'office-ui-fabric-react/lib/index'; 5 | import { ISharePointOnlineQuickAssistProps } from '../ISharePointOnlineQuickAssistProps'; 6 | 7 | export default class SearchPeopleQA extends React.Component 8 | { 9 | public render():React.ReactElement 10 | { 11 | return ( 12 |
13 | {alert("clicked"); }} 17 | /> 18 |
19 | ); 20 | } 21 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/SharePointOnlineQuickAssist.module.scss: -------------------------------------------------------------------------------- 1 | @import '~office-ui-fabric-react/dist/sass/References.scss'; 2 | 3 | // https://codepen.io/andrewconnell/pen/NGNQbR 4 | 5 | .sharePointOnlineQuickAssist { 6 | .container { 7 | max-width: 100%; 8 | margin: 0px auto; 9 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1); 10 | } 11 | 12 | .row { 13 | @include ms-Grid-row; 14 | @include ms-fontColor-white; 15 | //background-color: $ms-color-themeDark; 16 | padding: 10px; 17 | } 18 | 19 | .column { 20 | @include ms-Grid-col; 21 | @include ms-lg10; 22 | @include ms-xl8; 23 | @include ms-xlPush2; 24 | @include ms-lgPush1; 25 | } 26 | 27 | .msgrid 28 | { 29 | @include ms-Grid; 30 | padding-top: 0px; 31 | } 32 | 33 | .msrow 34 | { 35 | @include ms-Grid-row; 36 | } 37 | 38 | .mscol6 39 | { 40 | @include ms-Grid-col; 41 | @include ms-sm6; 42 | @include ms-md6; 43 | padding-left: 0px; 44 | } 45 | 46 | .mscol8 47 | { 48 | @include ms-Grid-col; 49 | @include ms-sm8; 50 | @include ms-md8; 51 | padding-left: 0px; 52 | } 53 | 54 | .mscol4 55 | { 56 | @include ms-Grid-col; 57 | @include ms-sm4; 58 | @include ms-md4; 59 | padding-left: 0px; 60 | } 61 | 62 | .title { 63 | @include ms-font-xl; 64 | @include ms-fontColor-black; 65 | } 66 | 67 | .subTitle { 68 | @include ms-font-l; 69 | @include ms-fontColor-black; 70 | } 71 | 72 | .description { 73 | @include ms-font-l; 74 | @include ms-fontColor-black; 75 | } 76 | 77 | .button { 78 | // Our button 79 | text-decoration: none; 80 | height: 32px; 81 | 82 | // Primary Button 83 | min-width: 80px; 84 | background-color: $ms-color-themePrimary; 85 | border-color: $ms-color-themePrimary; 86 | color: $ms-color-white; 87 | 88 | // Basic Button 89 | outline: transparent; 90 | position: relative; 91 | font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif; 92 | -webkit-font-smoothing: antialiased; 93 | font-size: $ms-font-size-m; 94 | font-weight: $ms-font-weight-regular; 95 | border-width: 0; 96 | text-align: center; 97 | cursor: pointer; 98 | display: inline-block; 99 | padding: 0 16px; 100 | 101 | .label { 102 | font-weight: $ms-font-weight-semibold; 103 | font-size: $ms-font-size-m; 104 | height: 32px; 105 | line-height: 32px; 106 | margin: 0 4px; 107 | vertical-align: top; 108 | display: inline-block; 109 | } 110 | } 111 | } 112 | 113 | // Overwrite margin for .ms-ComboBox-option 114 | :global(.ms-ComboBox-option) { 115 | margin-left: 15px; 116 | } 117 | /*:global(#sp-appBar) { 118 | display: none; 119 | } 120 | :global(#O365_NavHeader) { 121 | display: none; 122 | } 123 | :global(.mp_be_ada2ac09) { 124 | display: none; 125 | } 126 | 127 | // #spCommandBar 128 | :global(#spCommandBar) { 129 | display: none; 130 | } 131 | // CommentsWrapper 132 | :global(#CommentsWrapper) { 133 | display: none; 134 | }*/ -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Site/IFile.ts: -------------------------------------------------------------------------------- 1 | export interface IFile { 2 | ModifiedByEmail:string; 3 | ModifiedByName:string; 4 | ModifiedDate:string; 5 | Path:string; 6 | //Id:string; 7 | FileName:string; 8 | Library:string; 9 | } 10 | 11 | export interface IFiles 12 | { 13 | items:IFile[]; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Site/IFilesDeltaProps.ts: -------------------------------------------------------------------------------- 1 | import {MSGraphClient} from '@microsoft/sp-http'; 2 | export interface IFilesDeltaProps { 3 | description: string; 4 | msGraphClient:MSGraphClient; 5 | } 6 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/Site/IRestoreItem.ts: -------------------------------------------------------------------------------- 1 | export interface IRestoreItem { 2 | DeletedByEmail:string; 3 | DeletedByName:string; 4 | DeletedDate:Date; 5 | Path:string; 6 | Id:string; 7 | Existing:boolean; 8 | } 9 | 10 | export interface IRestoreItems 11 | { 12 | items:IRestoreItem[]; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/UserProfile/UserProfileDepartment.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 3 | import { 4 | DefaultButton 5 | } from 'office-ui-fabric-react/lib/index'; 6 | import { ISharePointOnlineQuickAssistProps } from '../ISharePointOnlineQuickAssistProps'; 7 | export default class UserProfileDepartmentQA extends React.Component 8 | { 9 | public render():React.ReactElement 10 | { 11 | return ( 12 |
13 | {alert("clicked"); }} 17 | /> 18 |
19 | ); 20 | } 21 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/UserProfile/UserProfileEmail.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 3 | import { 4 | DefaultButton 5 | } from 'office-ui-fabric-react/lib/index'; 6 | import { ISharePointOnlineQuickAssistProps } from '../ISharePointOnlineQuickAssistProps'; 7 | export default class UserProfileEmailQA extends React.Component 8 | { 9 | public render():React.ReactElement 10 | { 11 | return ( 12 |
13 | {alert("clicked"); }} 17 | /> 18 |
19 | ); 20 | } 21 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/UserProfile/UserProfileManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 3 | import { 4 | DefaultButton 5 | } from 'office-ui-fabric-react/lib/index'; 6 | import { ISharePointOnlineQuickAssistProps } from '../ISharePointOnlineQuickAssistProps'; 7 | export default class UserProfileManagerQA extends React.Component 8 | { 9 | public render():React.ReactElement 10 | { 11 | return ( 12 |
13 | {alert("clicked"); }} 17 | /> 18 |
19 | ); 20 | } 21 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/UserProfile/UserProfilePhoto.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { DefaultButton, TextField,Label} from 'office-ui-fabric-react/lib/index'; 3 | import GraphAPIHelper from '../../../Helpers/GraphAPIHelper'; 4 | import RestAPIHelper from '../../../Helpers/RestAPIHelper'; 5 | import SPOQASpinner from '../../../Helpers/SPOQASpinner'; 6 | import SPOQAHelper from '../../../Helpers/SPOQAHelper'; 7 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 8 | import { ISharePointOnlineQuickAssistProps } from '../ISharePointOnlineQuickAssistProps'; 9 | import styles from '../SharePointOnlineQuickAssist.module.scss'; 10 | export default class UserProfilePhotoQA extends React.Component 11 | { 12 | public state = { 13 | affectedUser: this.props.currentUser.loginName, 14 | aadUserPhotoUrl:"", 15 | uapUserPhotoUrl:"" 16 | }; 17 | public mySiteHost:string =""; 18 | public render():React.ReactElement 19 | { 20 | this.mySiteHost = this.props.webAbsoluteUrl.replace(this.props.webUrl == "/"?"":this.props.webUrl,"").replace(".sharepoint.com", "-my.sharepoint.com"); 21 | return ( 22 |
23 |
24 |
25 | {let text:any = e.target; this.setState({affectedUser:text.value});}} 29 | value={this.state.affectedUser} 30 | required={true} 31 | /> 32 | 33 | {this.state.aadUserPhotoUrl!=""?
:null} 34 | {this.state.aadUserPhotoUrl!=""?:null} 35 | {this.state.uapUserPhotoUrl!=""? :null} 36 | {this.CheckUserPhoto();}} 40 | /> 41 |
42 |
43 |
44 | ); 45 | } 46 | 47 | private async CheckUserPhoto() 48 | { 49 | SPOQAHelper.ResetFormStaus(); 50 | try{ 51 | var userPhoto = await GraphAPIHelper.GetUserPhoto(this.state.affectedUser, this.props.msGraphClient); 52 | const blobUrl = window.URL.createObjectURL(userPhoto); 53 | this.setState({aadUserPhotoUrl:blobUrl}); 54 | console.log("GraphAPIHelper.GetUserPhoto done"); 55 | 56 | try 57 | { 58 | var userInfoUAP = await RestAPIHelper.GetUserInfoFromUserProfile(this.state.affectedUser,this.props.spHttpClient, this.props.webAbsoluteUrl); 59 | console.log(`${strings.UPP_PhotoURL} ${userInfoUAP.PictureUrl}`); 60 | if(userInfoUAP.PictureUrl && userInfoUAP.PictureUrl!="") 61 | { 62 | this.setState({uapUserPhotoUrl:userInfoUAP.PictureUrl}); 63 | } 64 | SPOQAHelper.ShowMessageBar("Success", strings.UPP_PhotoSuccess); 65 | } 66 | catch(err) 67 | { 68 | SPOQAHelper.ShowMessageBar("Error", strings.UPP_PhotoFailed); 69 | } 70 | } 71 | catch(err) 72 | { 73 | SPOQAHelper.ShowMessageBar("Error", strings.UPP_NonAADPhoto); 74 | this.setState({aadUserPhotoUrl:"", uapUserPhotoUrl:""}); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/sharePointOnlineQuickAssist/components/UserProfile/UserProfileTitle.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | DefaultButton, 4 | TextField, 5 | Label 6 | } from 'office-ui-fabric-react/lib/index'; 7 | import GraphAPIHelper from '../../../Helpers/GraphAPIHelper'; 8 | import RestAPIHelper from '../../../Helpers/RestAPIHelper'; 9 | import SPOQASpinner from '../../../Helpers/SPOQASpinner'; 10 | import SPOQAHelper from '../../../Helpers/SPOQAHelper'; 11 | import { ISharePointOnlineQuickAssistProps } from '../ISharePointOnlineQuickAssistProps'; 12 | import styles from '../SharePointOnlineQuickAssist.module.scss'; 13 | import * as strings from 'SharePointOnlineQuickAssistWebPartStrings'; 14 | export default class UserProfileTitleQA extends React.Component 15 | { 16 | public state = { 17 | affectedUser: this.props.currentUser.loginName, 18 | aadJobTitle:"", 19 | uapJobtitle:"", 20 | siteJobTitle:"", 21 | userId:-1, 22 | affectedSite:this.props.webAbsoluteUrl 23 | }; 24 | 25 | public render():React.ReactElement 26 | { 27 | return ( 28 |
29 |
30 |
31 | {let text:any = e.target; this.setState({affectedSite:text.value});}} 35 | value={this.state.affectedSite} 36 | required={true} 37 | /> 38 | {let text:any = e.target; this.setState({affectedUser:text.value});}} 42 | value={this.state.affectedUser} 43 | required={true} 44 | 45 | /> 46 | 47 | {this.state.aadJobTitle != ""? : null} 48 | {this.state.aadJobTitle != "" && this.state.userId && this.state.userId !=-1? : null} 49 | {this.state.aadJobTitle != "" && this.state.userId && this.state.userId !=-1?: null} 50 | 51 | {this.CheckUserProfileTitle();}} 55 | /> 56 | 57 | { (this.state.siteJobTitle != this.state.aadJobTitle || this.state.aadJobTitle != this.state.uapJobtitle) && this.state.userId && this.state.userId !=-1 ? 58 |
65 |
66 |
67 | ); 68 | } 69 | 70 | public async CheckUserProfileTitle() 71 | { 72 | // reset status 73 | this.ResetStatus(); 74 | 75 | if(this.state.affectedSite =="" || this.state.affectedUser =="" ) 76 | { 77 | SPOQAHelper.ShowMessageBar("Error", strings.UI_NonAffectedSiteandUser); 78 | return; 79 | } 80 | 81 | if(this.state.affectedSite =="" || !this.state.affectedSite || !SPOQAHelper.ValidateUrl(this.state.affectedSite)) 82 | { 83 | SPOQAHelper.ShowMessageBar("Error", strings.UI_NonAffectedSite); 84 | return; 85 | } 86 | 87 | if(this.state.affectedUser =="" || !this.state.affectedUser || !SPOQAHelper.ValidateEmail(this.state.affectedUser)) 88 | { 89 | SPOQAHelper.ShowMessageBar("Error", strings.UI_NonAffectedUser); 90 | return; 91 | } 92 | 93 | SPOQASpinner.Show(strings.Checking); 94 | console.log("Start to CheckUserProfileTitle"); 95 | try 96 | { 97 | var userInfoAAD = await GraphAPIHelper.GetUserInfo(this.state.affectedUser, this.props.msGraphClient); 98 | console.log(`Job title from AAD is ${userInfoAAD.jobTitle}`); 99 | this.setState({aadJobTitle:userInfoAAD.jobTitle}); 100 | var userInfoUAP = await RestAPIHelper.GetUserInfoFromUserProfile(this.state.affectedUser,this.props.spHttpClient, this.state.affectedSite); 101 | console.log(`Job title from UAP is ${userInfoUAP.Title}`); 102 | this.setState({uapJobtitle:userInfoUAP.Title}); 103 | var userInfoSite = await RestAPIHelper.GetUserFromUserInfoList(this.state.affectedUser, this.props.spHttpClient, this.state.affectedSite); 104 | console.log(`Job title from user info list is ${userInfoSite.JobTitle}`); 105 | this.setState({siteJobTitle:userInfoSite.JobTitle}); 106 | this.setState({userId:userInfoSite.Id}); 107 | console.log("ended CheckUserProfileTitle"); 108 | } 109 | catch(err) 110 | { 111 | this.forceUpdate(); 112 | if(this.state.aadJobTitle == "" || !this.state.aadJobTitle) 113 | { 114 | SPOQAHelper.ShowMessageBar("Error", strings.UPT_NonAADTitle); 115 | } 116 | else if(this.state.userId ==-1) 117 | { 118 | SPOQAHelper.ShowMessageBar("Error", strings.UPT_NonSiteTitle); 119 | } 120 | } 121 | 122 | SPOQASpinner.Hide(); 123 | } 124 | 125 | public async FixJobTitle() 126 | { 127 | if(this.state.siteJobTitle != this.state.aadJobTitle) // fix the job title in the user info list 128 | { 129 | SPOQASpinner.Show(strings.UPT_FixSiteTitle); 130 | RestAPIHelper.FixJobTitleInUserInfoList(this.state.userId, this.props.spHttpClient, this.state.affectedSite, this.state.aadJobTitle, this.SuccessCallBack, this.FailedCallback); 131 | } 132 | else if(this.state.uapJobtitle != this.state.aadJobTitle) 133 | { 134 | SPOQASpinner.Show(strings.UPT_FixUserProfileTitle); 135 | try 136 | { 137 | var fixResult = await RestAPIHelper.FixJobTitleInUserProfile(this.state.affectedUser, this.props.spHttpClient, this.state.affectedSite, this.state.aadJobTitle); 138 | console.log(fixResult); 139 | } 140 | catch(err) 141 | { 142 | SPOQAHelper.ShowMessageBar("Error", strings.UPT_FailedUserProfileTitle); 143 | } 144 | } 145 | } 146 | 147 | public SuccessCallBack() 148 | { 149 | SPOQASpinner.Hide(); 150 | SPOQAHelper.ShowMessageBar("Success", strings.UPT_SuccessUserInfoListTitle); 151 | } 152 | 153 | public FailedCallback() 154 | { 155 | SPOQASpinner.Hide(); 156 | SPOQAHelper.ShowMessageBar("Error", strings.UPT_FailedUserInfoListTitle); 157 | } 158 | 159 | private ResetStatus():void 160 | { 161 | this.state.userId = -1; 162 | this.state.aadJobTitle = ""; 163 | this.state.uapJobtitle =""; 164 | this.state.siteJobTitle =""; 165 | SPOQAHelper.ResetFormStaus(); 166 | } 167 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/TeamsQuickAssistWebPart.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json", 3 | "id": "dbbdda4a-efbb-4e44-8a46-a72a99890e85", 4 | "alias": "TeamsQuickAssistWebPart", 5 | "componentType": "WebPart", 6 | 7 | // The "*" signifies that the version should be taken from the package.json 8 | "version": "*", 9 | "manifestVersion": 2, 10 | 11 | // If true, the component can only be installed on sites where Custom Script is allowed. 12 | // Components that allow authors to embed arbitrary script code should set this to true. 13 | // https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f 14 | "requiresCustomScript": false, 15 | "supportedHosts": ["SharePointWebPart"], 16 | 17 | "preconfiguredEntries": [{ 18 | "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other 19 | "group": { "default": "Other" }, 20 | "title": { "default": "TeamsQuickAssist" }, 21 | "description": { "default": "This tool can provide quick assist on teams issues, empower customer to resolve SharePoint Online issues quickly by themselves." }, 22 | "officeFabricIconFontName": "Page", 23 | "properties": { 24 | "description": "TeamsQuickAssist" 25 | } 26 | }] 27 | } 28 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/TeamsQuickAssistWebPart.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDom from 'react-dom'; 3 | import { Version } from '@microsoft/sp-core-library'; 4 | import { IPropertyPaneConfiguration } from '@microsoft/sp-property-pane'; 5 | import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; 6 | import TeamsQuickAssist from './components/TeamsQuickAssist'; 7 | import { ITeamsQuickAssistProps } from './components/ITeamsQuickAssistProps'; 8 | 9 | import { SPComponentLoader } from '@microsoft/sp-loader'; 10 | import * as contextHelper from '../Helpers/ContextHelper'; 11 | import {MSGraphClient, SPHttpClient} from '@microsoft/sp-http'; 12 | 13 | export interface ITeamsQuickAssistWebPartProps { 14 | description: string; 15 | } 16 | 17 | export default class TeamsQuickAssistWebPart extends BaseClientSideWebPart { 18 | private graphClient: MSGraphClient; 19 | 20 | constructor() { 21 | super(); 22 | contextHelper.default.SetInstace(this.context); 23 | SPComponentLoader.loadCss('https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/6.0.0/css/fabric-6.0.0.scoped.css'); 24 | } 25 | 26 | public onInit(): Promise { 27 | return new Promise((resolve: () => void, reject: (error: any) => void): void => { 28 | this.context.msGraphClientFactory 29 | .getClient() 30 | .then((client: MSGraphClient): void => { 31 | this.graphClient = client; 32 | resolve(); 33 | }, err => reject(err)); 34 | }); 35 | } 36 | 37 | public render(): void { 38 | const element: React.ReactElement = React.createElement( 39 | TeamsQuickAssist, 40 | { 41 | msGraphClient: this.graphClient, 42 | currentUser:this.context.pageContext.user, 43 | ctx:this.context 44 | } 45 | ); 46 | 47 | this.context.msGraphClientFactory 48 | .getClient() 49 | .then((client: MSGraphClient): void => { 50 | // get information about the current user from the Microsoft Graph 51 | client 52 | .api('/me') 53 | .get((error, response: any, rawResponse?: any) => { 54 | console.log(`${response} and ${error}`); 55 | }); 56 | }); 57 | 58 | ReactDom.render(element, this.domElement); 59 | } 60 | 61 | protected onDispose(): void { 62 | ReactDom.unmountComponentAtNode(this.domElement); 63 | } 64 | 65 | protected get dataVersion(): Version { 66 | return Version.parse('1.0'); 67 | } 68 | 69 | protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { 70 | return { 71 | pages: [] 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/components/Admin/TestTeamsQA.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { ITeamsQuickAssistProps } from "../ITeamsQuickAssistProps"; 3 | import styles from "../TeamsQuickAssist.module.scss"; 4 | import { 5 | PrimaryButton, 6 | TextField, 7 | Label, 8 | } from "office-ui-fabric-react/lib/index"; 9 | 10 | import GraphAPIHelper from "../../../Helpers/GraphAPIHelper"; 11 | import SPOQAHelper from "../../../Helpers/SPOQAHelper"; 12 | import * as strings from "TeamsQuickAssistWebPartStrings"; 13 | import { Text } from "@microsoft/sp-core-library"; 14 | 15 | export default class TestTeamsQA extends React.Component { 16 | public state = { 17 | affectedUser: this.props.currentUser.loginName, 18 | isNeedFix: false, 19 | }; 20 | 21 | public render(): React.ReactElement { 22 | return ( 23 |
24 |
25 |
26 | { 30 | let text: any = e.target; 31 | this.setState({ affectedUser: text.value }); 32 | }} 33 | value={this.state.affectedUser} 34 | required={true} 35 | /> 36 | 37 | 38 | { 42 | this.Check(); 43 | }} 44 | /> 45 | 46 | {this.state.isNeedFix ? ( 47 | { 55 | this.ShowRemedy(); 56 | }} 57 | /> 58 | ) : null} 59 |
60 |
61 |
62 | ); 63 | } 64 | 65 | private async Check() { 66 | try { 67 | SPOQAHelper.ResetFormStaus(); 68 | let userInfo: any = await GraphAPIHelper.GetUserInfo( 69 | this.state.affectedUser, 70 | this.props.msGraphClient 71 | ); 72 | let roles: any = await GraphAPIHelper.GetUserRoles( 73 | userInfo.id, 74 | this.props.msGraphClient 75 | ); 76 | if (roles.value.length < 50) { 77 | SPOQAHelper.ShowMessageBar( 78 | "Success", 79 | Text.format(strings.RO_CheckPass, roles.value.length) 80 | ); 81 | } else { 82 | SPOQAHelper.ShowMessageBar("Error", strings.RO_CheckFail); 83 | this.setState({isNeedFix: true}); 84 | } 85 | } catch (err) { 86 | SPOQAHelper.ShowMessageBar("Error", strings.RO_APIError); 87 | console.log(err); 88 | } 89 | } 90 | 91 | private ShowRemedy() { 92 | try { 93 | SPOQAHelper.ResetFormStaus(); 94 | SPOQAHelper.ShowMessageBar("Info",strings.RO_Remedy); 95 | } 96 | catch (err){ 97 | console.log(err); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/components/ITeamsQuickAssistProps.ts: -------------------------------------------------------------------------------- 1 | import { WebPartContext } from "@microsoft/sp-webpart-base"; 2 | import {MSGraphClient, SPHttpClient} from '@microsoft/sp-http'; 3 | import {SPUser} from '@microsoft/sp-page-context'; 4 | 5 | export interface ITeamsQuickAssistProps { 6 | msGraphClient:MSGraphClient; 7 | // spHttpClient:SPHttpClient; 8 | // webAbsoluteUrl:string; 9 | // webUrl:string; 10 | // rootUrl:string; 11 | currentUser:SPUser; 12 | ctx:WebPartContext; 13 | } 14 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/components/TeamsQuickAssist.module.scss: -------------------------------------------------------------------------------- 1 | @import '~office-ui-fabric-react/dist/sass/References.scss'; 2 | 3 | // https://codepen.io/andrewconnell/pen/NGNQbR 4 | 5 | .teamsQuickAssist { 6 | .container { 7 | max-width: 100%; 8 | margin: 0px auto; 9 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1); 10 | } 11 | 12 | .row { 13 | @include ms-Grid-row; 14 | @include ms-fontColor-white; 15 | //background-color: $ms-color-themeDark; 16 | padding: 10px; 17 | } 18 | 19 | .column { 20 | @include ms-Grid-col; 21 | @include ms-lg10; 22 | @include ms-xl8; 23 | @include ms-xlPush2; 24 | @include ms-lgPush1; 25 | } 26 | 27 | .msgrid 28 | { 29 | @include ms-Grid; 30 | padding-top: 0px; 31 | } 32 | 33 | .msrow 34 | { 35 | @include ms-Grid-row; 36 | } 37 | 38 | .mscol6 39 | { 40 | @include ms-Grid-col; 41 | @include ms-sm6; 42 | @include ms-md6; 43 | padding-left: 0px; 44 | } 45 | 46 | .mscol8 47 | { 48 | @include ms-Grid-col; 49 | @include ms-sm8; 50 | @include ms-md8; 51 | padding-left: 0px; 52 | } 53 | 54 | .mscol4 55 | { 56 | @include ms-Grid-col; 57 | @include ms-sm4; 58 | @include ms-md4; 59 | padding-left: 0px; 60 | } 61 | 62 | .title { 63 | @include ms-font-xl; 64 | @include ms-fontColor-black; 65 | } 66 | 67 | .subTitle { 68 | @include ms-font-l; 69 | @include ms-fontColor-black; 70 | } 71 | 72 | .description { 73 | @include ms-font-l; 74 | @include ms-fontColor-black; 75 | } 76 | 77 | .button { 78 | // Our button 79 | text-decoration: none; 80 | height: 32px; 81 | 82 | // Primary Button 83 | min-width: 80px; 84 | background-color: $ms-color-themePrimary; 85 | border-color: $ms-color-themePrimary; 86 | color: $ms-color-white; 87 | 88 | // Basic Button 89 | outline: transparent; 90 | position: relative; 91 | font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif; 92 | -webkit-font-smoothing: antialiased; 93 | font-size: $ms-font-size-m; 94 | font-weight: $ms-font-weight-regular; 95 | border-width: 0; 96 | text-align: center; 97 | cursor: pointer; 98 | display: inline-block; 99 | padding: 0 16px; 100 | 101 | .label { 102 | font-weight: $ms-font-weight-semibold; 103 | font-size: $ms-font-size-m; 104 | height: 32px; 105 | line-height: 32px; 106 | margin: 0 4px; 107 | vertical-align: top; 108 | display: inline-block; 109 | } 110 | } 111 | } 112 | 113 | // Overwrite margin for .ms-ComboBox-option 114 | :global(.ms-ComboBox-option) { 115 | margin-left: 15px; 116 | } -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/components/TeamsQuickAssist.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import styles from "./TeamsQuickAssist.module.scss"; 3 | import { ITeamsQuickAssistProps } from "./ITeamsQuickAssistProps"; 4 | import { escape } from "@microsoft/sp-lodash-subset"; 5 | import { 6 | ComboBox, 7 | Fabric, 8 | IComboBox, 9 | IComboBoxOption, 10 | mergeStyles, 11 | SelectableOptionMenuItemType, 12 | Spinner, 13 | MessageBar, 14 | MessageBarType, 15 | } from "office-ui-fabric-react/lib/index"; 16 | 17 | import * as strings from "TeamsQuickAssistWebPartStrings"; 18 | import TestTeamsQA from "./Admin/TestTeamsQA"; 19 | import SPOQAHelper from "../../Helpers/SPOQAHelper"; 20 | 21 | const wrapperClassName = mergeStyles({ 22 | selectors: { 23 | "& > *": { marginBottom: "20px" }, 24 | "& .ms-ComboBox": { maxWidth: "300px" }, 25 | "& .ms-ComboBox-option": { marginLeft: "15px" }, 26 | }, 27 | }); 28 | 29 | const INITIAL_OPTIONS: IComboBoxOption[] = [ 30 | { 31 | key: "AccountIssue", 32 | text: strings.AccountIssue, 33 | itemType: SelectableOptionMenuItemType.Header, 34 | }, 35 | { key: "LoginCookieError", text: strings.LoginCookieError }, 36 | ]; 37 | 38 | export default class TeamsQuickAssist extends React.Component< 39 | ITeamsQuickAssistProps, 40 | {} 41 | > { 42 | public state = { 43 | selectedKey: "", 44 | }; 45 | 46 | public render(): React.ReactElement { 47 | const teamsQADetail = () => { 48 | switch (this.state.selectedKey) { 49 | case "LoginCookieError": 50 | return ( 51 | 56 | ); 57 | default: 58 | return
; 59 | } 60 | }; 61 | 62 | return ( 63 |
64 | 65 |
66 |
67 |
68 | {strings.WebPartTitle} 69 |
70 |
71 | 72 |
73 |
74 |
75 | , 84 | option?: IComboBoxOption 85 | ): void => { 86 | this.setState({ selectedKey: option.key }); 87 | }} 88 | /> 89 |
90 |
91 |
92 | 93 |
94 |
{teamsQADetail()}
95 |
96 |
97 |
98 |
99 | 106 |
110 | { 115 | SPOQAHelper.Hide("SPOQAErrorMessageBarContainer"); 116 | }} 117 | dismissButtonAriaLabel="Close" 118 | > 119 | SPOQAErrorMessageBar 120 | 121 |
122 |
126 | { 131 | SPOQAHelper.Hide("SPOQASuccessMessageBarContainer"); 132 | }} 133 | dismissButtonAriaLabel="Close" 134 | > 135 | SPOQASuccessMessageBar 136 | 137 |
138 |
142 | { 147 | SPOQAHelper.Hide("SPOQAWarningMessageBarContainer"); 148 | }} 149 | dismissButtonAriaLabel="Close" 150 | > 151 | SPOQAWarningMessageBar 152 | 153 |
154 |
158 | { 163 | SPOQAHelper.Hide("SPOQAInfoMessageBarContainer"); 164 | }} 165 | dismissButtonAriaLabel="Close" 166 | > 167 | SPOQAInfoMessageBar 168 | 169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | ); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/loc/en-us.js: -------------------------------------------------------------------------------- 1 | define([], function() { 2 | return { 3 | Admin: "Admin", 4 | Test: "Test", 5 | WebPartTitle:"Welcome to use Teams Quick Assist!", 6 | SelectIssueTip:"Please select issue which you want to check", 7 | RO_CheckPass:"User has {0} roles, not affected", 8 | RO_CheckFail:"User has more than 50 admin roles, please reduce it to below 50", 9 | RO_APIError: "Failed to get role info for this user, please check UPN and try again", 10 | RO_Remedy:'Please select affected user from Microsoft365 Admin Center(
https://admin.microsoft.com/#/users), select "Manage Roles" and reduce role count to below 50', 11 | AccountIssue:"Account Issue", 12 | LoginCookieError:"Login - Cookie Error", 13 | } 14 | }); -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/loc/ja-jp.js: -------------------------------------------------------------------------------- 1 | define([], function() { 2 | return { 3 | Admin: "Admin", 4 | Test: "Test", 5 | WebPartTitle:"Welcome to use Teams Quick Assist!", 6 | SelectIssueTip:"Please select issue which you want to check", 7 | RO_CheckPass:"User has {0} roles, not affected", 8 | RO_CheckFail:"User has more than 50 admin roles, please reduce it to below 50", 9 | RO_APIError: "Failed to get role info for this user", 10 | RO_Remedy:'Please select affected user from Microsoft365 Admin Center(https://admin.microsoft.com/#/users), select "Manage Roles" and reduce role count to below 50', 11 | AccountIssue:"Account Issue", 12 | LoginCookieError:"Login - Cookie Error", 13 | } 14 | }); -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/loc/mystrings.d.ts: -------------------------------------------------------------------------------- 1 | declare interface ITeamsQuickAssistWebPartStrings { 2 | Admin: string; 3 | Test: string; 4 | WebPartTitle:string; 5 | SelectIssueTip:string; 6 | RO_CheckPass:string; 7 | RO_CheckFail:string; 8 | RO_APIError:string; 9 | RO_Remedy:string; 10 | AccountIssue:string; 11 | LoginCookieError:string; 12 | } 13 | 14 | declare module 'TeamsQuickAssistWebPartStrings' { 15 | const strings: ITeamsQuickAssistWebPartStrings; 16 | export = strings; 17 | } 18 | -------------------------------------------------------------------------------- /SPFX/SPOQA/src/webparts/teamsQuickAssist/loc/zh-cn.js: -------------------------------------------------------------------------------- 1 | define([], function() { 2 | return { 3 | Admin: "Admin", 4 | Test: "Test", 5 | WebPartTitle:"欢迎使用Teams快速助手!", 6 | SelectIssueTip:"请选择您遇到的问题类型", 7 | RO_CheckPass:"用户角色数量为 {0} ,不受此问题影响", 8 | RO_CheckFail:"用户角色数量多于50, 请在管理员中心将其减少到50以下", 9 | RO_APIError: "无法获取该用户的角色情况,请检查用户名并重试", 10 | RO_Remedy:'请在Microsoft365管理员中心(https://admin.microsoft.com/#/users)选中该用户并点击"管理角色",然后将总角色数量减少至50个以下', 11 | AccountIssue:"账户问题", 12 | LoginCookieError:"登陆问题 - 第三方cookie问题", 13 | } 14 | }); -------------------------------------------------------------------------------- /SPFX/SPOQA/teams/6e9d3cc3-8c9d-4d11-893a-50179561b893_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/teams/6e9d3cc3-8c9d-4d11-893a-50179561b893_color.png -------------------------------------------------------------------------------- /SPFX/SPOQA/teams/6e9d3cc3-8c9d-4d11-893a-50179561b893_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/teams/6e9d3cc3-8c9d-4d11-893a-50179561b893_outline.png -------------------------------------------------------------------------------- /SPFX/SPOQA/teams/82d9e654-8ffa-45ad-866a-df31c3d5a9b2_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/teams/82d9e654-8ffa-45ad-866a-df31c3d5a9b2_color.png -------------------------------------------------------------------------------- /SPFX/SPOQA/teams/82d9e654-8ffa-45ad-866a-df31c3d5a9b2_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/teams/82d9e654-8ffa-45ad-866a-df31c3d5a9b2_outline.png -------------------------------------------------------------------------------- /SPFX/SPOQA/teams/dbbdda4a-efbb-4e44-8a46-a72a99890e85_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/teams/dbbdda4a-efbb-4e44-8a46-a72a99890e85_color.png -------------------------------------------------------------------------------- /SPFX/SPOQA/teams/dbbdda4a-efbb-4e44-8a46-a72a99890e85_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/SPFX/SPOQA/teams/dbbdda4a-efbb-4e44-8a46-a72a99890e85_outline.png -------------------------------------------------------------------------------- /SPFX/SPOQA/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@microsoft/rush-stack-compiler-3.7/includes/tsconfig-web.json", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "forceConsistentCasingInFileNames": true, 6 | "module": "esnext", 7 | "moduleResolution": "node", 8 | "jsx": "react", 9 | "declaration": true, 10 | "sourceMap": true, 11 | "experimentalDecorators": true, 12 | "skipLibCheck": true, 13 | "outDir": "lib", 14 | "inlineSources": false, 15 | "strictNullChecks": false, 16 | "noUnusedLocals": false, 17 | "typeRoots": [ 18 | "./node_modules/@types", 19 | "./node_modules/@microsoft" 20 | ], 21 | "types": [ 22 | "webpack-env", 23 | "microsoft-ajax", 24 | "sharepoint" 25 | ], 26 | "lib": [ 27 | "es5", 28 | "dom", 29 | "es2015.collection", 30 | "es2015.promise" 31 | ] 32 | }, 33 | "include": [ 34 | "src/**/*.ts", 35 | "src/**/*.tsx" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /SPFX/SPOQA/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json", 3 | "rules": { 4 | "class-name": false, 5 | "export-name": false, 6 | "forin": false, 7 | "label-position": false, 8 | "member-access": true, 9 | "no-arg": false, 10 | "no-console": false, 11 | "no-construct": false, 12 | "no-duplicate-variable": true, 13 | "no-eval": false, 14 | "no-function-expression": true, 15 | "no-internal-module": true, 16 | "no-shadowed-variable": true, 17 | "no-switch-case-fall-through": true, 18 | "no-unnecessary-semicolons": true, 19 | "no-unused-expression": true, 20 | "no-use-before-declare": true, 21 | "no-with-statement": true, 22 | "semicolon": true, 23 | "trailing-comma": false, 24 | "typedef": false, 25 | "typedef-whitespace": false, 26 | "use-named-parameter": true, 27 | "variable-name": false, 28 | "whitespace": false 29 | } 30 | } -------------------------------------------------------------------------------- /assets/ApproveAPI.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/ApproveAPI.JPG -------------------------------------------------------------------------------- /assets/CheckUserProfilePhoto.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/CheckUserProfilePhoto.JPG -------------------------------------------------------------------------------- /assets/Deploy.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/Deploy.JPG -------------------------------------------------------------------------------- /assets/JobTitle.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/JobTitle.JPG -------------------------------------------------------------------------------- /assets/JobTitleSync.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/JobTitleSync.JPG -------------------------------------------------------------------------------- /assets/NoCrawl.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/NoCrawl.JPG -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /assets/SearchSpecificDocument.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/SearchSpecificDocument.JPG -------------------------------------------------------------------------------- /assets/SiteNoCrawl.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/SiteNoCrawl.JPG -------------------------------------------------------------------------------- /assets/UploadSolution.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/UploadSolution.JPG -------------------------------------------------------------------------------- /assets/WebPart.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrcheng/SharePointOnlineQuickAssist/716f79dca0188a74dded79cf678de65c835383d5/assets/WebPart.JPG --------------------------------------------------------------------------------