There are many ways to iterate a collection in PowerShell. I just really like using delegate functions. This approach is not native PowerShell but utilises the .NET Action class as a function parameter. Using a delegate function approach, it is possible to create a recursive loop that can be very easily reused in the future just by providing an alternative Action.
The example code I provide below demonstrates how to create a delegate function in PowerShell, how to write a function that accepts one as a parameter, and provides some ready made samples for iterating SharePoint objects, specifically all webs or all lists. I am using some specific SharePoint objects in these samples, however the fundamental pattern can be used to effectively iterate any recursive structure.
foreachDecendentWeb : perform an action on every web below the provided web foreachListInWeb : perform an action on every list in the provided web foreachListInWebAndAllDecendentWebs : perform an action on every list in the current and all decendent webs
Some notes
The below script references ‘TopOfScript.ps1’, it is specifically related to calling SharePoint CSOM from PowerShell. Read about it here on sharepointnutsandbolts.
Making the call, providing the delegate
The utility scipts, recursive functions accepting delegate parameters
There is a minor style bug in SharePoint 2013 (including SharePoint Online). The error message on a required DateTime field is not displayed in a manner consistent with other control validation errors. No it’s not just you, and no it’s not due to some conflicting CSS – it is a SharePoint bug.
Specifically I am referring to the page layout edit experience. A user fails to provide a value for a required DateTimeField control and the validation message is shown in the default text colour – ‘You must specify a value for this required field.’
For all other validation messages the SharePoint controls add the ms-formvalidation which sets a CSS rule to set the red colour. This is the only rule which the ms-formvalidation class sets and as such this is the only rule that should be applied to fix the issue.
I use the following CSS selector to resolve this issue:
With the addition of Office 365 themes we can provide some company branding throughout the Office 365 suite. But why does it take so long to propagate down throughout the SharePoint sites in the tenant?
Set an Office 365 theme
These themes affect the suite bar across the top of the page. I see it often that after setting the Office 365 theme for a tenant, the theme gets applied to Mail, Calendar, Delve, etc but can seem to take a very long time before it appears on SharePoint sites.
Well it is actually just taking a long time to appear on SharePoint sites if you have visited SharePoint recently. The Office 365 theme colours are cached locally in the browser using local storage.
The local storage key that is used is: SPSuiteLinksJson. This appears to store everything that is required to render the entire suite bar.
Interestingly there is another local storage key which appears to store the date at which the suite bar data was cached: SPSuiteLinksDate. Presumably this is used to calculate when the cache should be refreshed from the server. I am not sure exactly how long this is yet. Please comment if you have figured out the cache timeout.
Regardless of its duration, if you want to force end users to get the latest theme more often you have the options of clearing either of these values or modifying the date field appropriately. But really, I can’t imagine why this would be so important although its nice to know that a bit of JavaScript can sort this out if need be.
Paul.
FYI – The value that is stored will be something like the following (taken from a test tenant):
{"SPSuiteVersion":2,"SPIsMobile":false,"CssUrl":"https://prod.msocdn.com/16.00.0915.008/en-US/css/shellg2coremincss_40fd4be6.css","JsUrl":"https://prod.msocdn.com/16.00.0915.008/en-US/JSC/CoreMinShellG2Bundle.js","NavBarData":{"AboutMeLink":{"BrandBarText":null,"Id":"ShellAboutMe","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"About me","Title":"Go to the My profile page","Url":"https://tenant-my.sharepoint.com/person.aspx"},"AdminLink":{"BrandBarText":null,"Id":"ShellAdmin","MenuName":"Admin centers","ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Admin","Title":"Go to the Office 365 admin center","Url":"https://portal.office.com/admin/default.aspx"},"AppsImage":null,"AppsLinks":null,"ClientData":"{\"AddBusinessUserUrl\":null,\"AdminHelpUrlFormat\":\"http:\\/\\/o15.officeredir.microsoft.com\\/r\\/rlidOfficeWebHelp?p1=O365ENTADMIN&clid=1033&ver=15&services=INTUNE_O365%2cYAMMER_ENTERPRISE%2cMCOSTANDARD%2cSHAREPOINTSTANDARD%2cEXCHANGE_S_STANDARD&p2=O365&HelpID={HelpID}\",\"AppHeaderLinkText\":null,\"AppHeaderLinkUrl\":null,\"AppLauncherErrorHelpUrl\":\"http:\\/\\/o15.officeredir.microsoft.com\\/r\\/rlidOfficeWebHelp?p1=O365ENTADMIN&clid=1033&ver=15&services=INTUNE_O365%2cYAMMER_ENTERPRISE%2cMCOSTANDARD%2cSHAREPOINTSTANDARD%2cEXCHANGE_S_STANDARD&p2=O365&HelpID=O365E_AppLTrustedSites\",\"AppSearchEnabled\":false,\"AppsCustomizationDisabled\":false,\"AppsDiscoverabilityDisabled\":false,\"AppsDragAndDropDisabled\":false,\"AppsGetAllAppTilesEnabled\":false,\"AppsPrePinnedDisabled\":false,\"AppsResizingDisabled\":true,\"AppsUpdateTimeSpan\":3600000,\"CDNUrl\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\",\"CardBundleJS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/JSC\\/CardBundle.js\",\"ChatNotificationsDisabled\":false,\"ClearUserThemeCacheUrls\":\"[{\\\"WorkloadId\\\":\\\"AdminPortal\\\",\\\"WorkloadUrl\\\":\\\"https:\\/\\/portal.office.com\\/misc\\/expirecookies.aspx\\\",\\\"RequestType\\\":\\\"img\\\",\\\"NoRequestInSameWorkload\\\":true},{\\\"WorkloadId\\\":\\\"Sharepoint\\\",\\\"WorkloadUrl\\\":\\\"https:\\/\\/tenant-my.sharepoint.com\\/_layouts\\/15\\/ClearLocalCache.aspx\\\",\\\"RequestType\\\":\\\"iframe\\\",\\\"NoRequestInSameWorkload\\\":false},{\\\"WorkloadId\\\":\\\"Sharepoint\\\",\\\"WorkloadUrl\\\":\\\"https:\\/\\/tenant.sharepoint.com\\/_layouts\\/15\\/ClearLocalCache.aspx\\\",\\\"RequestType\\\":\\\"iframe\\\",\\\"NoRequestInSameWorkload\\\":false}]\",\"ClientTelemetryEnabled\":false,\"ClientTelemetrySource\":\"O365SuiteUX\",\"ClientTelemetryToken\":\"\",\"ClientTelemetryUIVersion\":\"1000\\/1.6.5.0\",\"ClientTelemetryUrl\":\"\",\"CollectorIds\":[\"SharePoint\",\"Graph\",\"FirstParty\",\"LineOfBusiness\"],\"ConsumerWorkloadUrls\":null,\"DefaultSavedUserUrl\":null,\"DisplayNameFormat\":null,\"EditPhotoPopupUrl\":\"https:\\/\\/outlook.office365.com\\/ecp\\/PersonalSettings\\/EditAccount.aspx?chgPhoto=1&exsvurl=1&realm={0}\",\"ExchangeWLADUpdateInterval\":28800000,\"FlexPaneDisabled\":false,\"GallatinLegalAlertEnabled\":false,\"GroupsDisabled\":true,\"HasEXOLicense\":true,\"HasSkypeLicense\":true,\"IdentitySwitcherEnabled\":false,\"ImmersiveProfileUrl\":\"profile\\/\",\"ImmersiveSettingsUrl\":\"settings\\/\",\"IsConsumerShell\":false,\"IsGuestMode\":false,\"IsIWDelveLinkPresent\":true,\"IsNFDDisabled\":false,\"IsNFDOnO365SuiteServiceEnabled\":false,\"IsO365SuiteServiceEnabled\":false,\"IsPartnerResellerPage\":false,\"IsRTL\":false,\"IsTenantDirSyncEnabled\":false,\"LoadUserThemesUrl\":\"https:\\/\\/portal.office.com\\/data.theme?action=tu&l=en-US&tt=G2&cdnver=16.00.0915.008\",\"LocalNotificationsDisabled\":false,\"LogArgLength\":1024,\"LogLevelSwitches\":[false,true,true,true],\"LogLevelSwitchesForPage\":null,\"LogUrl\":\"https:\\/\\/clientlog.portal.office.com\\/l.l\\/\",\"LyncIntegrationDisabled\":true,\"LyncIntegrationUrl\":\"https:\\/\\/swx.cdn.skype.com\\/shared\\/v\\/1.2.3\\/SkypeBootstrap.min.js\",\"MePhotoCachingDisabled\":false,\"MobileShellDisabled\":true,\"MultipleAADSwitchingEnabled\":false,\"MyAccountEnabled\":false,\"MyAccountUrl\":\"account\\/\",\"MyAppsUrl\":\"https:\\/\\/portal.office.com\\/myapps\",\"NeutralGrayColors\":[\"000000\",\"212121\",\"333333\",\"666666\",\"767676\",\"A6A6A6\",\"C8C8C8\",\"EAEAEA\",\"F4F4F4\",\"F8F8F8\",\"FFFFFF\"],\"NeutralStatusColors\":[\"A80F22\",\"D83B01\",\"2A8DD4\",\"107C10\"],\"NewAppLauncherHelpUrl\":null,\"NewAppNotificationEnabled\":false,\"NewMailNotificationsDisabled\":false,\"NoResultsHelpLinkUrl\":\"https:\\/\\/support.office.com\",\"NotificationsFlexPaneEnabled\":true,\"NotificationsSettingsV2Enabled\":false,\"PUID\":\"1003BFFD91368966\",\"PortalUrl\":\"https:\\/\\/portal.office.com\\/\",\"ProfileAboutCardApiUrl\":\"api\\/profile\\/data\",\"ProfileDoughboyUrl\":\"\\/images\\/profile\\/doughboy.png\",\"ProfileHeaderBGUrl\":\"\\/images\\/profile\\/profile-header-bg.jpg\",\"ProfileOrgChartCardApiUrl\":\"api\\/profile\\/org\",\"ProfilePaneEnabled\":false,\"RemindersNotificationDisabled\":false,\"RenderAsyncDisabled\":false,\"ResponsiveShellEnabled\":false,\"SHSID\":\"0822f3b5-7e00-4401-8436-34dc280519a9\",\"SavedUserUrl\":null,\"SettingsCardApiUrl\":\"api\\/settings\\/cards\",\"SettingsFlexPaneEnabledWorkloads\":\"ShellAdmin;AdminPortal\",\"SettingsPaneEnabled\":false,\"SettingsSearchClassifierUrl\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/JS\\/SettingSearch\\/SettingsSearchClassifier_en.js\",\"SettingsSearchNlrtUrl\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/JS\\/SettingSearch\\/MicrosoftNaturalLanguageRuntime.js\",\"SettingsSessionStorageEnabled\":false,\"ShellCoreCSS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/css\\/shellg2corecss_9037d638.css\",\"ShellCoreCSSResourceKey\":\"shellg2corecss\",\"ShellCoreJS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/JSC\\/CorePrimeShellG2Bundle.js\",\"ShellCoreJSResourceKey\":\"shellcoreprimeg2m\",\"ShellPlusCSS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/css\\/shellg2pluscss_1db8cf27.css\",\"ShellPlusCSSResourceKey\":\"shellg2pluscss\",\"ShellPlusJS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/JSC\\/O365ShellG2Plus.js\",\"ShellPlusJSResourceKey\":\"shellplusg2m\",\"ShellPlusNarrowCSS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/css\\/shellg2plusncss_c867ccef.css\",\"ShellPlusNarrowCSSResourceKey\":\"shellg2plusncss\",\"ShellPlusNarrowJS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/JSC\\/O365ShellG2PlusN.js\",\"ShellPlusNarrowJSResourceKey\":\"shellplusg2n\",\"ShellPlusTouchCSS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/css\\/shellg2plustcss_846fbfc5.css\",\"ShellPlusTouchCSSResourceKey\":\"shellg2plustcss\",\"ShellPlusTouchJS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/JSC\\/O365ShellG2PlusT.js\",\"ShellPlusTouchJSResourceKey\":\"shellplusg2t\",\"ShellPlusWideCSS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/css\\/shellg2pluswcss_5c4da058.css\",\"ShellPlusWideCSSResourceKey\":\"shellg2pluswcss\",\"ShellPlusWideJS\":\"https:\\/\\/prod.msocdn.com\\/16.00.0915.008\\/en-US\\/JSC\\/O365ShellG2PlusW.js\",\"ShellPlusWideJSResourceKey\":\"shellplusg2w\",\"ShowMailNotificationCount\":false,\"ShowNewAppLauncher\":false,\"ShowNewMyAppsLink\":true,\"SkypeApiKey\":\"b32c0389-1143-4a42-b15f-7b860f9eafbb\",\"SocialNotificationsDisabled\":true,\"SuiteServiceCallsDisabled\":false,\"SuiteServiceUrl\":\"https:\\/\\/outlook.office365.com\\/owa\\/service.svc\",\"SwitchToBusinessUserUrl\":null,\"SystemNotificationsDisabled\":false,\"TID\":\"2fb81f0d-c6ef-4c83-b35c-9553261f9d9b\",\"TenantPrimaryColorShades\":[\"149B14\",\"18BD19\",\"18BD19\",\"1DE01D\",\"72D071\",\"C7E2C7\",\"FDFEFD\",\"FFFFFF\",\"FFFFFF\"],\"TenantThemeColors\":[\"1DE01D\",\"0CA597\",\"FFFFFF\",\"FFFFFF\"],\"TenantThemeCssUrl\":\"https:\\/\\/portal.office.com\\/data.theme?action=tc&tc=1DE01D|0CA597|FFFFFF|FFFFFF&tt=G2&tv=40357e1c-4ba4-4ff1-94ae-6df34f02fe07&l=en-US\",\"ThemeCssUrl\":\"https:\\/\\/portal.office.com\\/data.theme?action=tc&tc=1DE01D|0CA597|FFFFFF|FFFFFF&tt=G2&tv=40357e1c-4ba4-4ff1-94ae-6df34f02fe07&l=en-US\",\"ThemePanelEnabled\":true,\"UID\":\"f0f20750-f14a-416b-84da-03119aa4ac1e\",\"UPN\":\"ccdev5@tenant.onmicrosoft.com\",\"UserPersonalizationAllowed\":false,\"UserThemeId\":\"Base\",\"UserThemesPanelUrl\":null,\"UserThemesSettingsPageUrl\":\"https:\\/\\/portal.office.com\\/EditProfile15.aspx?serviceId=ThemeItem\",\"WorkloadId\":\"Sharepoint\"}","CommunityLink":{"BrandBarText":null,"Id":"ShellCommunity","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Community","Title":"Community","Url":"http://g.microsoftonline.com/0BX20en/142"},"CompanyDisplayName":"Content and Code","CorrelationID":"0822f3b5-7e00-4401-8436-34dc280519a9","CultureName":"en-US","CurrentMainLinkElementID":"ShellSharepoint","CurrentWorkloadHelpSubLinks":null,"CurrentWorkloadSettingsLink":null,"CurrentWorkloadSettingsSubLinks":null,"CurrentWorkloadUserSubLinks":null,"Dimensions":{"Top":50},"DownArrowImage":null,"DownWhiteArrowImage":null,"FeedbackLink":{"BrandBarText":null,"Id":"ShellFeedback","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Feedback","Title":null,"Url":"https://portal.office.com/SendSmile?wid=2"},"FlightName":"15GA,Exp180917IngestionFailedStatusTreat1,Exp130705C,Exp170859ihdc100,SE80186HRCSetupRedirect,SE130231CFRV2,SE130238GeminiSignupUI,SE160251CFRV2Detail,SE160252CFRV2Prefetch,SE160258ShellDelveLink,SE190296ShellVideoLink,SE190331GeminiPurchaseUI,SE190354IWSignupAlertsOn,SE190448AADUXChangePassword,SE190549NotificationsFlexPane,SE190532AggregatedServiceHealth,SE200626ShellSwayLink,SE200631PartnerFeedback,SE200681SwitchReadFromAPIService,SE220756PartnerClientTroubleshoot,SE220826AppStore,SE220829LOBApps,SE220825Office2016PreviewForPc,SE220822IntuneMDMStaged,SE240791PartnerUsageTracking,SE240809ShellServiceThemeCache,SE240810O365ImmersiveSettings,SE240827CortanaAccessSettings,SE240829ShellClassNoteBookLink,SE240843PartnerSettingsPageFeature,SE240844HelpFlexPane,SE240866MobileAdmin,SE240880OAuthAuthenticationForAPIService,SE240881GeminiCatalogUI,SE240883ShellNewMyAppsLink,SE250903CFRV3,SE250928ShellPowerBILink,SE260930UnifiedSetup,SE240865ShellStaffNoteBookLink,SE271003CFRV3CsvExportEnabled,SE271005CutoverProxy,SE271017SwitchReadFromAPIService,SE271018CFRV3TS,SE271014AdvSetupImap,SE281032AetherSubscriptionsUI,SE291071PartnerResellerMultiPartner,SE281034OfficeHome3,Exp9015C","FlipHelpIcon":false,"FooterCopyrightLogoTitle":null,"FooterCopyrightText":null,"FooterICPLink":null,"FooterLogoImage":null,"HasTenantBranding":true,"HelpImage":null,"HelpLink":{"BrandBarText":null,"Id":"HelpLink","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Help","Title":null,"Url":"&services=INTUNE_O365%2cYAMMER_ENTERPRISE%2cMCOSTANDARD%2cSHAREPOINTSTANDARD%2cEXCHANGE_S_STANDARD&p2=O365"},"ImageClusterUrl":null,"IsAuthenticated":true,"LegalLink":{"BrandBarText":null,"Id":"ShellLegal","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Legal","Title":"Legal","Url":"http://g.microsoftonline.com/0BX20en/721"},"LogoIconID":"o365logo","LogoImage":null,"LogoNavigationUrl":"https://portal.office.com/Home","LogoThemeableImage":null,"MenuTitleText":null,"MyProfileUrl":"https://portal.office.com/EditProfile15.aspx?ServiceID=LanguageItem","NavBarAriaLabel":null,"NotificationsBellIconImage":null,"NotificationsCountLabelText":null,"NotificationsHighIconImage":null,"NotificationsLowIconImage":null,"NotificationsMediumIconImage":null,"NotificationsPopupHeaderText":null,"NotificationsProgressIconImage":null,"O365SettingsLink":{"BrandBarText":null,"Id":"ShellO365Settings","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Office 365 settings","Title":null,"Url":"https://portal.office.com/settings/"},"PartnerLink":null,"PoweredByText":"powered by {0}","PrivacyLink":{"BrandBarText":null,"Id":"ShellPrivacy","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Privacy","Title":"Privacy","Url":"http://g.microsoftonline.com/0BX20en/138"},"SPO_MySiteHostUrl":null,"SPO_RootSiteUrl":null,"SessionID":"e88c267e-5b6e-49ab-8f2d-766510e25c46","SettingsImage":null,"SignOutLink":{"BrandBarText":null,"Id":"ShellSignout","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Sign out","Title":"Sign out of Office 365 and return to the Sign-in page","Url":"https://login.microsoftonline.com/logout.srf?ct=1443035468&rver=6.4.6456.0&lc=1033&id=271346"},"TenantBackgroundImageUrl":null,"TenantLogoNavigationUrl":null,"TenantLogoUrl":{"BrandBarText":null,"Id":null,"MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":null,"Title":"Content and Code","Url":"data:image/png;base64,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"},"ThemeColors":null,"TransparentImageUrl":null,"TruncatedUserDisplayName":null,"UpArrowImage":null,"UseSPOBehaviors":false,"UserDisplayName":"Content and Code Dev 5","WorkloadLinks":[{"BrandBarText":"Outlook","Id":"ShellMail","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Mail","Title":"Go to your email","Url":"https://outlook.office365.com/owa/?realm=tenant.onmicrosoft.com&exsvurl=1&ll-cc=1033&modurl=0"},{"BrandBarText":"Outlook","Id":"ShellCalendar","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Calendar","Title":"Go to your calendar","Url":"https://outlook.office365.com/owa/?realm=tenant.onmicrosoft.com&exsvurl=1&ll-cc=1033&modurl=1"},{"BrandBarText":"Outlook","Id":"ShellPeople","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"People","Title":"Go to People and contacts","Url":"https://outlook.office365.com/owa/?realm=tenant.onmicrosoft.com&exsvurl=1&ll-cc=1033&modurl=2"},{"BrandBarText":null,"Id":"ShellNewsfeed","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Newsfeed","Title":"Go to your Newsfeed","Url":"https://tenant-my.sharepoint.com/default.aspx"},{"BrandBarText":null,"Id":"ShellDocuments","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"OneDrive","Title":"Go to OneDrive for Business","Url":"https://tenant-my.sharepoint.com/personal/ccdev5_tenant_onmicrosoft_com/_layouts/15/start.aspx#/_layouts/15/onedrive.aspx"},{"BrandBarText":null,"Id":"ShellSites","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Sites","Title":"Go to team sites","Url":"https://tenant-my.sharepoint.com/personal/ccdev5_tenant_onmicrosoft_com/_layouts/15/start.aspx#/Social/Sites.aspx"},{"BrandBarText":"Outlook","Id":"ShellTasks","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Tasks","Title":"Go to Outlook Web App for Tasks","Url":"https://outlook.office365.com/owa/?realm=tenant.onmicrosoft.com&exsvurl=1&ll-cc=1033&modurl=3"},{"BrandBarText":null,"Id":"ShellOfficeGraph","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Delve","Title":"Go to Delve","Url":"https://tenant-my.sharepoint.com/_layouts/15/me.aspx?origin=shell"},{"BrandBarText":null,"Id":"ShellVideo","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":null,"Text":"Video","Title":"Go to Video for Office 365 to share videos","Url":"https://tenant.sharepoint.com/portals/hub/_layouts/15/videohome.aspx"},{"BrandBarText":null,"Id":"ShellWordOnline","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Word Online","Title":"Go to Word Online","Url":"https://office.live.com/start/Word.aspx?auth=2"},{"BrandBarText":null,"Id":"ShellExcelOnline","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Excel Online","Title":"Go to Excel Online","Url":"https://office.live.com/start/Excel.aspx?auth=2"},{"BrandBarText":null,"Id":"ShellPowerPointOnline","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"PowerPoint Online","Title":"Go to PowerPoint Online","Url":"https://office.live.com/start/PowerPoint.aspx?auth=2"},{"BrandBarText":null,"Id":"ShellOneNoteOnline","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"OneNote Online","Title":"Go to OneNote Online","Url":"https://www.onenote.com/notebooks?auth=2"},{"BrandBarText":null,"Id":"ShellSway","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Sway","Title":"Go to Sway","Url":"https://www.sway.com?auth_pvr=OrgId&auth_upn=ccdev5@tenant.onmicrosoft.com"},{"BrandBarText":null,"Id":"ShellOfficeStore","MenuName":null,"ServiceId":null,"SubLinks":null,"TargetWindow":"_blank","Text":"Office 365 Store","Title":null,"Url":"https://portal.office.com/store"}]},"SharedCSSTouchWideUrl":"https://prod.msocdn.com/16.00.0915.008/en-US/css/shellg2corewcss_8b4fb7b2.css","SharedJSTouchWideUrl":"https://prod.msocdn.com/16.00.0915.008/en-US/JSC/CoreShellG2BundleW.js","SharedCSSTouchNarrowUrl":"https://prod.msocdn.com/16.00.0915.008/en-US/css/shellg2corencss_18d28bae.css","SharedJSTouchNarrowUrl":"https://prod.msocdn.com/16.00.0915.008/en-US/JSC/CoreShellG2BundleN.js","SharedCSSTouchDeviceUrl":"https://prod.msocdn.com/16.00.0915.008/en-US/css/shellg2coretcss_ba6efae3.css","SharedJSTouchDeviceUrl":"https://prod.msocdn.com/16.00.0915.008/en-US/JSC/CoreShellG2BundleT.js","TenantPrimaryColorShades":["149B14","18BD19","18BD19","1DE01D","72D071","C7E2C7","FDFEFD","FFFFFF","FFFFFF"],"UserThemePrimaryColorShades":["104A7D","0D62AA","106EBE","0078D7","2B88D8","71AFE5","C7E0F4","DEECF9","EFF6FC"],"UserPersonalizationAllowed":false,"ThemeVersion":"G2","ShellRequestId":"aadc309d-b069-3000-9493-98edca352038"}
I while ago I blogged about creating a static link to a pre-refined (pre-filtered) search page. This post follows that idea to it’s natural conclusion by providing a number of JavaScript functions which can dynamically create search result page URLs. These URLs will look something like this:
It would be worth reading the intro of my earlier article to get a better understanding of what is happening in the snippets provided in this post.
Default Enterprise Search Centre
OF NOTE:
As the most common usage will surely be to produce search result page URLs that are refined on a single value, I have written an ‘overload’ function that simplifies calling the method in this scenario
The ‘search page URL’ can be provided to the functions in a number of ways including:
“/search” : to the web. The default page for that web. In the case of an Enterprise Search Centre this will be the ‘Everything’ search results page
“/search/Pages/peopleresults.aspx” : to the page
Use an absolute URL if you are out of the context of the SharePoint Online tenant in which the search page resides. This will be true for provider hosted add-ins (apps)
If you are writing your own refiner, then pass an empty string and set window.location.hash to the result of the function
This script has no dependencies on other libraries (jQuery, SP.js, etc)
The hex encoded string must be UTF-8 encoded. JavaScript is natively UTF-16. The particular scenario where this raised an issue for me was the wide-ampersand character which is often used instead of a standard ampersand as it is XML friendly. ‘unescape’ returns a UTF-8 encoded string and is used to force the required encoding. Thanks to ecmanaut for this solution
The goal of this post is to provide very basic ‘hello world’ example of how to call the Office 365 Unified API (aka Graph API) using JavaScript and the ADAL.js library. This has recently become possible (May 2015) now that CORS is supported by the Office 365 APIs (most of the individual endpoints support it as well as the unified API).
The ADAL library simplifies the process of obtaining and caching the authentication tokens required to retrieve data from Office 365. It is possible to avoid the ADAL library and handle this yourself, although I would recommend doing so as a learning exercise only.
I failed to find a simple example of how to achieve this, my search results often filled with examples of calling the APIs from server-side code or else utilising the Angular.js framework. This example is based on a more complex example.
The following snippet will log to the browser console the results of a call the to files endpoint of the Office 365 unified API, which will return a JSON object containing information about the files in the current users’ OD4B.
Register an Azure Active Directory App. Note that *every* Office 365 subscriptions comes with AAD and supports the creation of an app
Associate the required ‘permissions to other services’, in this case ‘Read users files’ via the Office 365 Unified API
Allow implicit flow
Not covered explicitly in the above article but also critical are the following steps:
Get the App’s Client ID and copy it into the snippet
The App Client ID
Get the Azure Active Directory subscription ID and copy it into the snippet
The subscription ID in Azure Active Directory
Once the above steps have been completed, you can try out the snippet by embedding in a Script Editor web part, or you can run it externally to SharePoint as part of, say, a provider hosted app.
NOTE: I found that the call to files endpoint is failing for certain users. I am still unsure whether this is due to external vs internal users (is working for internal [.onmicrosoft.com] users) or whether it could be licencing issue. The /beta/me endpoint is working in all cases.
Paul.
GLOSSARY
CORS: Cross-Origin Resource Sharing
ADAL: Active Directly Authentication Library
OD4B: OneDrive 4 Business
For solutions that are contained in a single site collection, or span a small number of site collections, or are in a tenant where the other solutions are not trusted or are unknown, then I have a strong preference to use site collection scoped search schema rather than tenant scoped.
Side note: I am yet to come across a situation where I would use site scoped search schema. In my mind, the existence of search schema at this level only serves to confuse.
Search Schema hierarchy is SharePoint Online. There is also site scoped search schema at lowest level which is not present here.
For those that aren’t fully aware, search schema (the set of managed properties that are accessible via the search framework) can be provisioned at the tenant, site collection, or site scope. These scopes are hierarchical such that managed properties are inherited from the tenant scope down to the site scope but can be overridden along the way. There are some good articles that delve into this in more detail.
By provisioning search schema at the site collection level you are mitigating the risks of errors related to other solutions changing the properties which your solution relies upon. This is especially relevant in SharePoint Online where all solutions in the tenant have to share a common set of RefinableTypeXX managed properties.
There are some important exceptions, of course.
People Search, a.k.a User Profile Search, a.k.a Local People Results
In SharePoint Online, people properties are indexed on a very slow schedule. We requested more information from Microsoft regarding this and were told that this schedule is ‘confidential’. I have found that when using site-collection scoped managed properties it can take *weeks* for them to get populated. I have found much better (although still poor) performance using tenant scoped properties (usually within a few days). Assuming you do require custom search schema for people properties I would still recommend provisioning all remaining managed properties (all those not mapped to people properties) at the site collection level.
Many site collections
Of course, having many site collections which require the same search schema is valid reason to go tenant scoped. This is purely due to management of the properties going forwards. A solid scripted deployment procedure should not care if you are provision search schema to 1 or 50 site collections – but anyone maintaining the solution will definitely care if they have update 50 schemas manually, or are suddenly required to script something which they feel should be *easy*. Even in this scenario you should still consider how much you trust other solutions in the tenant against the impact of finding out that one day your managed properties are mapped incorrectly. Depending on your solution this could lead to errors that are left undetected, or conversely obviously break your home page.
In SharePoint Online I have detected a bug that prevents the suite bar logo (configured in the o365 tenant admin center) from being rendered after applying a theme with a non-default colour scheme. The logo is not just hidden or not visible; the HTML is no longer rendered to the page at all.
NOTE: This issue has been raised with Microsoft and they have acknowledged it as a bug. They have told is that a fix is planned for June 2015 and should take a couple of weeks to reach all tenants.
Update 06/08/2015
I was advised last week that a fix this issue had officially started rolling out. Today I can confirm that one of our test tenants no longer exhibits this behavior! At the time of writing some of our tenants have not yet received the fix, but it is definitely rolling out and should be with you soon if not already.
When exactly is this occurring?
There is a colour scheme file that nominated as the default for each master page. Only when using this colour scheme in conjunction with the given master page will the logo be present. Specifically, only a colour scheme which is nominated as the default colour scheme will show the suite navigation logo.
This is unrelated to any customisation work and can be observed on any OOTB SharePoint Online publishing site.
The default colour scheme for a given master page is nominated within that master page’s preview file. The preview file is the one which sits alongside the master page in the master page gallery and has the same name name as the master page but with an extension of ‘.preview’ instead of ‘.master’ (e.g., seattle.preview). The first line of the contents of this file identifies the default colour scheme for the master page. When this colour scheme is applied, the theming engine assumes that the CSS is already themed appropriately and does *not* act.
Identifying the default colour scheme for a master page
I still want the logo on every page, what can we do?
As I have said, a fix is on the way – just wait a few months!
We can inject the logo using JavaScript (or CSS, but we were unable to achieve a CSS only solution which meets our responsive design requirements)
It is against best practice
This approach is brittle as the suite bar is a living, changing thing – Microsoft is updating it all the time and any changes they make will likely break this functionality.
The logo will no longer be configurable via tenant admin settings.
We can create and use multiple master pages – one for every theme colour
Partially defeats the purpose of master pages which is to maintain all common pages elements in a single place.
Master pages may fall out of synch
Adds complexity for support
I want to reproduce this myself, how do I do it?
Create an new site collection in a tenant that has a suite navigation logo configured, using the Publishing Site template
Note that the logo is present
Via Site Settings, “Change the look”
Choose the “Office” composed look
[Specifically, we want the seattle master page and colour pallette 001]
Change the colour scheme to anything except the default
Apply the look
Note that the logo is no longer present
Re-apply the theme with the default colour scheme and logo will reappear
If you are attempting to run the PowerShell command Add-Type with a Path parameter that references an assembly which has been emailed or downloaded from the internet (e.g. Add-Type -Path "C:\Microsoft.SharePoint.Client.dll") then it is likely that you will encounter the following error:
Could not load file or assembly ‘file:///’ or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
To confirm that the following steps are appropriate. Check the inner exception:
PS> $error[0].Exception.InnerException
“An attempt was made to load an assembly from a network location which would have caused the assembly to be
sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable
CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly,
please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more
information.”
Not using SharePoint Client Components?
First check the execution policy under which PowerShell is running. This can be done by running the Get-ExecutionPolicy cmdlet. If you are not running under an Unrestricted policy, try running the Add-type cmdlet after setting the execution policy to Unrestricted (Set-ExecutionPolicy “Unrestricted”). If this resolves the issue then you’ll need to look into getting the assembly signed by a trusted publisher if you can’t continue to run PowerShell in this lowered state of security.
Next ensure that the assembly hasn’t been blocked. The easiest way to achieve this is by right-clicking on the assembly and checking on the General tab that there isn’t the option to unblock the assembly at bottom of the dialog. There is also the Unblock-File cmldlet to achieve this action via PowerShell.
Unblocking an assembly
Finally, PowerShell supports a config file which by default is not present. It allows configuration of a few things like the .NET versions which are supported and, importantly for us, whether or not PowerShell is allowed to load from remote sources. In order to add/update this file, ensure that you are logged in as a local administrator. The config file needs to reside adjacent to the PowerShell exe file. So, by default, it ought to be created here: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe.config
Note: Do not confuse this with powershell_ise.exe.config although you may want to update this as well if you use ISE.
The content of the powershell.exe.config should be as follows. If you already have a file present, ensure that you merge the XML rather than just replacing it.
Using SharePoint Client Components?
If you are adding the SharePoint Client assemblies required for the execution of CSOM requests then you should take a different approach. Rather than bundling these assemblies with your script, instead insure that the correct SharePoint Client Components package is installed on the executing machine and reference the assemblies from their default location:
When you import an image to use as a background image as part of a composed look in SharePoint Online, the image is re-scaled to 1024 x 768 and compressed as low quality jpg. If you have an image which still looks reasonable after these modifications then please continue to use composed looks as the ensures that the page weight is kept to a minimum.
A full HD imageThe same image as above after being processed by the Composed Look framework. Admittedly the compression is pretty good in this example.
SharePoint provides no configuration around this that I am aware of and even you provide a background image URL in the composed look to a non-compressed image, the image will be compressed and the compressed image will be referenced when the composed look is applied.
The only way to support a high resolution background image is to reference it in CSS, overriding the composed look background image. I have found that the best way to do this is with the following two CSS rules. The second prevents the background being used in dialogs which occasionally don’t use the transparent overlay and can become unusable otherwise.
If the image needs to be changed later, a new image with the same name can uploaded to replace the current one. The issue with this approach is that client browsers may have cached the background image and will continue to use the cached image until the cache expires (could be years, if hosted outside of SharePoint, or will be 24 hours if hosted in the Style Library) or the user manually clears their browser cache. In order to force the browser to re-fetch the image a query string value should be appended (or amended, in the current example we are using ‘v=1.0’).
Note that if you are using theme-able CSS you may need to reapply the theme in order to apply changes to the CSS.
Yammer and SharePoint Online are becoming more and more integrated. Recently, with the Yammer Embed widget supporting SSO from Office 365 to Yammer, we are in a situation where we can perform actions against Yammer from SharePoint Online without requiring further authentication.
This opens up opportunities for utilising the Yammer SDK and Yammer REST API to build all kinds of Yammer interactions directly into your SharePoint pages. It also allows us to start implementing some of those anti-patterns that customers want but Yammer doesn’t want to support as they’re against ‘social freedom’. A prime example of this is forcing users into groups. In some scenarios it may be rather practical. I won’t discuss the pros and cons of this further but do consider that Microsoft would rather you coerce users socially to make their own decision to join the ‘correct’ groups rather than programmatically deciding for them.
Regardless of that, I’m going to provide an example which, upon page load, joins the current O365 user’s Yammer identity to a Yammer group based upon their SharePoint user profile.I’d like to point out that if Yammer Embed is present on the page and is enabled with Single Sign On, then the authentication piece can be hidden entirely from the user. I am currently unaware how to achieve SSO with Yammer from SharePoint Online without pigging-backing Yammer Embed, although I haven’t looked in earnest so I suspect it’s achievable without too much effort.
A few notes on the code:
Add the first code snippet to a page with a Script Editor web part. It calls the initiation code and any configurations can be provided here, and modified when live
The second code snippet contains all the logic. This can be included to the page in any manner you wish but you must ensure it has loaded prior to running the init function
In order to use the Yammer SDK you must register a Yammer app on the target network and provide the client ID as the data-app-id attribute on the script element which includes it
Each user must authorise the Yammer app, just once, before it can act in their behalf. I have implemented this as a status message, an example of which can be seen in the image below
Each user must authorise the Yammer App to act on their behalf
The code references ‘hut Id’ which is just a value stored in user’s profile and which is used to map a user to a Yammer group
I use local storage to prevent the code executing more often than every 24 hours. This has been commented out for clarity, however I would recommend functionality such as this is re-implemented
The experience of signing into Yammer from SharePoint is different if SharePoint is hosted on-premise or online. Only when online is the same identity used and can an SSO experience be achieved. In contrast, on-prem, the disconnect between O365 and Yammer credentials allows users to to provide credentials for any Yammer user in any Yammer network rather than being restricted to the associated identity
And finally, the code:
Finally, for completeness, here is a the settings object which I pass to Yammer Embed to achieve SSO with Yammer from SharePoint Online. I find that in practice anywhere I would want to run the above code I also have a feed of some sort that is appropriate to display. If this is not the case for you, hiding the feed with display:none will achieve the same result as long as the width of the Yammer Embed is equal to or greater than 400px. Note that this is *not* required, however without it the user may be prompted to provide their Yammer credentials.