Posted on:
Categories: Office 365
Description:
Trying to remove one of the existing domains from your Office 365 tenancy? This should be pretty easy as long as the following criteria are met 1. Domain is not used for UPN addresses2. Domain is not used for SMTP addresses associated with your recipients or Lync online users If you try to remove the domain prior to meeting conditions above (for instance by running Remove-MsolDomain –force) you will get the error saying Unable to remove this domain. Use Get-MsolUser –DomainName <domain name> to retrieve a list of objects that are blocking removal. Depending on how your O365 users were created (through Directory Synchronization or directly in O365) you will either need to update UPNs and remove those addresses from your on-premises Exchange recipients or Office 365 cloud accounts. Once the UPNs are changed and domain is released from recipient addresses, you can confirm that domain is not in use by executing the following cmdlets below. CONNECT TO O365 FROM POWERSHELL $UserCredential = Get-Credential $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https//outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection Import-PSSession $Session Connect-MSOLService CONFIRM THAT DOMAIN IS NOT IN USE To confirm that domain is not used for UPN addresses Get-msoluser –DomainName "domain.com" (where "domain.com" is the domain you are planning to remove from O365) To confirm that domain is not used for SMTP addresses Get-recipient –ResultSize unlimited | where $_.EmailAddresses –match "domain.com" To confirm that domain is not used for E-mail addresses associated with MSOL Groups Get-msolgroup –All |where $_.ProxyAddresses –match "domain.com" Once all 3 PowerShell scripts come back clean you can remove the domain from O365 by running Remove-MSOLDomain –DomainName




Posted on:
Categories: SharePoint
Description:
I recently dealt with an issue wherein a user was reporting that they were unable to filter several columns based on the choice values configured for items in several lists. Ordinarily, when you have a column configured to use the ‘Choice’ data type, you are able to filter that column by clicking the arrow next to the column title. When you click the arrow you should be presented with a list of values that you can filter on. These values correspond to the relevant choice that has been entered for each item.In this instance, the user was not seeing any filterable values in the drop down, even though there were plenty of items with values for this column type. Solution If Key Filters are enabled you lose the ability to filter a column by clicking the drop down next to the column name. It is an either or scenario, and it looks like you cannot have both options available at the same time. It turned out that the user had enabled Key Filters for all of the columns that were not filterable by clicking the arrow next to the column name. Key filters appear under the quick launch area of the page. ​




Posted on:
Categories: SharePoint
Description:
I was recently helping a user to test PowerView in SharePoint. They had an Excel file that they wanted to use as a data source. In this instance the user wanted to use the BISM file type that is available in the Data Sources library to connect to their Excel file. We created the BISM file in the Data Sources library and pointed it to a regular Excel Workbook that contained some data, but we got the following error The issue was that the Excel Workbook did not contain a data model, which is one of the requirements when using a BISM connection file. Once a data model was created for the Excel file the error no longer appeared. https//support.office.com/en-us/article/Create-a-connection-to-a-data-model-for-Power-View-c10d648d-0b7c-49c4-abcf-aa6ffc33c1c9




Posted on:
Categories: PowerShell;SharePoint
Description:
We have found that as you add more content types to a content type hub it takes longer and longer for the Content Type Subscriber timer job to run. The time that it takes the Content Type Subscriber time job to finish appears to be directly related to the number of items contained in the content type hub. At this point​ we have hundreds of content types in our content type hub, and it can take hours for the Content Type Subscriber timer job to complete. In our testing environments, I'm often asked to manually run the Content Type Subscriber job when new content types are added to the content type hub. Our developers will then have to wait until the job completes in order to proceed with their testing. They are often eager to commence their testing, which means that we end up repeatedly clicking on the Timer Job status page in Central administration to get an indication of how much progress the timer job has made. In order to get around this inconvenience, I wrote the following script which will start the Content Type Subscriber job for a specified web application. The script will send an email to anyone that you specify once the timer job has completed. In our case I typically send the email to myself and the developer who is waiting to test their application. ​ #Start and Monitor Content Type Subscriber Timer Job param ( [string]$webApp ) Function StartAndMonitorCTSubscriberJob($webAppUrl,$to) Write-Host -foregroundColor Green "Starting Content Type Subscriber Job..." Get-SPTimerJob -WebApplication $webAppUrl -Identity "MetadataSubscriberTimerJob" |Start-SPTimerJob Start-Sleep -s 20 $webAppURL = Get-SPWebApplication $webAppUrl do $runningJobs = $webAppURL.WebService.RunningJobs |?$_.JobDefinitionTitle -eq "Content Type Subscriber" | select JobDefinitionTitle,ServerName,StartTime,PercentageDone,status | Format-Table -autosize $runningJobs start-sleep -s 30 until($runningJobs.Count -eq 0) send-mailmessage -to $to -from "no-reply@sharepoint.contoso.com” -subject "Content Type Subscriber Job Completed for $webApp" -SmtpServer server name #separate email addresses with a comma StartAndMonitorCTSubscriberJob -WebAppUrl $webApp -To “user1@contoso.com”,”user2@contoso.com”​




Posted on:
Categories: SharePoint;SQL
Description:
​Deploying Microsoft SQL Server Reporting Services (SSRS) within a SharePoint 2010 environment can be a challenge. It can be particularly confusing when available documentation is not representative of your SharePoint and SQL infrastructure. Having several clients with multi server SharePoint farms and stand alone SQL servers, the documentation I found never fit these farm topologies and SQL versions I needed for my clients. What I did not want, was to deploy an extraneous SQL server instance on a SharePoint server, only to sit idle consuming resources. I decided to get a definitive map of what components are required where for the SSRS solution to work within a SharePoint 2010 and 2013 environment given a multi server farm topology and 2008, 2012 and 2014 versions of Microsoft SQL. Below I map the components necessary for the various multi server topologies, and what components should be installed where. OPTIONAL * This component only needs to be installed if balancing services for redundancy, either SSRS services or Web Application (WFE) services.




Posted on:
Categories: PowerShell;SharePoint
Description:
Minimal Download Strategy (MDS) ​is a new technology in SharePoint 2013 that reduces the amount of data that the browser has to download when users navigate from one page to another in a SharePoint site. MDS is a site scoped feature that is activated by default on all sites. This may cause compatibility issues with 3rd party load balancers, reverse proxies or developed customizations. Without a customized site template, ensuring all new sites do NOT have this enabled may be a challenge. If you are in need of disabling this feature, you can use the below script at an interval of your choosing to disable MDS on all sites. The script will log it's actions on what it changed nightly to a log file in a destination of your choice. $fullFilePath = c\Scripts\DisableMDS\DisableMDSLog.txt Remove-Item -Force -LiteralPath $fullFilePath -ErrorAction SilentlyContinue Add-PsSnapin Microsoft.SharePoint.PowerShell -ea 0 $OutString = "Script Running at " + (Get-Date); $OutString | Out-File -FilePath $fullFilePath -Append $WebApps = Get-SPWebApplication | Where-Object $_.Url -notlike "*my*" ForEach($WebApp in $WebApps) ForEach($Site in $WebApp.Sites) $OutString = "Checking Site-Collection " + $Site.Url; $OutString | Out-File -FilePath $fullFilePath -Append ForEach($Web in $Site.AllWebs) $OutString = " Checking Sub-Site " + $Web; $OutString | Out-File -FilePath $fullFilePath -Append If($Web.EnableMinimalDownload -eq 1) $OutString = " MDS is Enabled for this site. Disabling"; $OutString | Out-File -FilePath $fullFilePath -Append Disable-SPFeature -Identity MDSFeature -URL $Web.URL -confirm$false Else $OutString = " Skipping " + $Web; $OutString | Out-File -FilePath $fullFilePath -Append $Web.Dispose(); $Site.Dispose();




Posted on:
Categories: SharePoint
Description: SharePoint 2013 with SSRS throws "User cannot be found."
Scenario You migrate a SharePoint 2010 Site to SharePoint 2013 with SSRS 2012 SP1, while also converting the Site to Claims Based Authentication. When you click on "Manage Data Sources" on a report the following error is displayed "Report Server has encountered a SharePoint error. ---> Microsoft.ReportingServices.Diagnostics.Utilities.SharePointException Report Server has encountered a SharePoint error. ---> Microsoft.SharePoint.SPException User cannot be found."Solution Update - Alternatively, I was also able to resolve this issue by installing SQL 2012 SP1 CU9 on the SharePoint server hosting SSRS. ULS Logs showed the following stack trace Throwing Microsoft.ReportingServices.Diagnostics.Utilities.SharePointException , Microsoft.ReportingServices.Diagnostics.Utilities.SharePointException Report Server has encountered a SharePoint error. ---> Microsoft.SharePoint.SPException User cannot be found. at Microsoft.SharePoint.SPUserCollection.get_Item(String loginName) at Microsoft.ReportingServices.SharePoint.Objects.RSSPImpFile.get_Author() at Microsoft.ReportingServices.SharePoint.Server.SharePointServiceHelper.SyncToRSCatalog(ExternalItemPath path, Boolean createOnly) - -- End of inner exception stack trace ---; Let's have a look at the SSRS code to see where SSRS gets the Author from Then the following code is ran which is what throws our expectation. The code takes the SPFile.Properties["vti_author"] and tries to resolve the user using SPWeb.SiteUsers Collection, which returns "User cannot be found." I compared the Properties["vti_author"] on a SSRS Report which was working. The difference was that the broken one did not have the claims prefix "i0#.w|" It appears that the Claims Migration does not update this property, I have validated this on a number of farms. Next, I wrote a script to resolve this issue As I was writing the script, I noticed that this issue also occurs on SPFile.Properties["vti_modifiedby"]. The script will resolve both issues. Throwing Microsoft.ReportingServices.Diagnostics.Utilities.SharePointException , Microsoft.ReportingServices.Diagnostics.Utilities.SharePointException Report Server has encountered a SharePoint error. ---> Microsoft.SharePoint.SPException User cannot be found. at Microsoft.SharePoint.SPFile.GetModifiedByFallback(String modifiedBy) at Microsoft.SharePoint.SPFile.get_ModifiedBy() at Microsoft.ReportingServices.SharePoint.Objects.RSSPImpFile.get_ModifiedBy() at Microsoft.ReportingServices.SharePoint.Server.SharePointServiceHelper.SyncToRSCatalog(ExternalItemPath path, Boolean createOnly) - -- End of inner exception stack trace ---; 6. #----------------------------------------------------------------------------- # Name Fix-ClaimsConversionProperties.ps1 # Description This script will update the vti_author and vti_modifiedby with the claims prefix # # Usage Run the function with the required parameters # By Ivan Josipovic, Softlanding.ca #----------------------------------------------------------------------------- Function Fix-ClaimsConversionProperties($webUrl, $listTitle) $web = Get-SPWeb $webUrl; $list = $web.lists[$listTitle]; foreach ($item in $list.Items) if (!$item.Properties["vti_author"].StartsWith("i0#.w") -or !$item.Properties["vti_modifiedby"].StartsWith("i0#.w")) $item.Name; $currentAuthor = $item.Properties["vti_author"]; if (!$currentAuthor.StartsWith("i0#.w")) try $userAuthor = $web.EnsureUser($currentAuthor); $item.Properties["vti_author"] = $userAuthor.UserLogin; catch Write-Host "$currentAuthor user was not found! They were replaced with System."; $item.Properties["vti_author"] = $web.EnsureUser("SHAREPOINT\system").UserLogin; $currentModifiedBy = $item.Properties["vti_modifiedby"]; if (!$currentModifiedBy.StartsWith("i0#.w")) try $item.Properties["vti_modifiedby"] = $web.EnsureUser($currentModifiedBy).UserLogin; catch Write-Host "$currentModifiedBy user was not found! They were replaced with System."; $item.Properties["vti_modifiedby"] = $web.EnsureUser("SHAREPOINT\system").UserLogin; $item["Editor"] = $web.EnsureUser("SHAREPOINT\system"); $item.SystemUpdate(); $item.Properties["vti_author"] $item.Properties["vti_modifiedby"]




Posted on:
Categories: SharePoint
Description: Make SharePoint 2010 Applications work on 2013
Scenario You have an Desktop Application that was built for SharePoint 2010 and you need to run in on SharePoint 2013. When the Application is ran the following error is displayed, System.IO.FileNotFoundException Could not load file or assembly 'Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' or one of its dependencies. The system cannot find the file specified. Background Assembly Version SharePoint 2013 doesn’t come with version 14 (2010) or 12 (2007) assemblies. For backwards compatibility, SharePoint deploys Assembly Binding Redirects for previous assembly versions, what this does is redirect any calls to version 12 or 14 to the version 15 of the assembly. Here is an example of the Assembly Binding Redirect Configuration <dependentAssembly> <assemblyIdentity name="Microsoft.SharePoint" publicKeyToken="71e9bce111e9429c" culture="neutral" /> <!-- Redirecting to version 15.0.0.0 of the assembly. --> <bindingRedirect oldVersion="14.0.0.0" newVersion="15.0.0.0" /> </dependentAssembly> Common Language Runtime Version At this point you're thinking, since we have Assembly Binding Redirects, then our Application should work! The issue is that SharePoint 2010 Applications are written in .Net 3.5, while SharePoint 2013 is written in .Net 4.5 .Net 4.0 introduced a new version of the CLR (Common Language Runtime), it is essentially what runs .Net code Due to the CLR update, it is not possible to load .Net 4.5 assemblies from .NET 3.5, however the other way works fine.Solution .Net Supports a notion of a Configuration file for executables. This configuration allows you to change the way the application is ran, among many other things. More info http//msdn.microsoft.com/en-us/library/1fk1t1t0(v=vs.110).aspx To fix our issue, we are going to tell .NET to use the 4.0 CLR, which is what .Net 4.5 uses. Assuming our application is called MyApp.exe, create a text file called MyApp.exe.config and place the following XML into it <?xml version="1.0" encoding="utf-8"?> <configuration> <startup> <supportedRuntime version="v4.0"/> </startup> </configuration> Now when you run your application, it will use the 4.0 CLR and the application should work correctly with SharePoint 2013.




Posted on:
Categories: SharePoint
Description: Fix for blurry fonts with SharePoint 2013 and Internet Explorer 8
Scenario You are using SharePoint 2013 with Internet Explorer 8 and the fonts are not legible. Solution A Microsoft Employee provided a fix on technet https//social.technet.microsoft.com/Forums/en-US/fc9f72b6-c710-47c8-aba4-fe4cb650a633/background-image-in-sharepoint-2013-is-blurry The Fix involves adding additional CSS to the corev15.css file Process On each SharePoint server do the following Edit the following files "C\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\1033\STYLES\Themable\COREv15.css" "C\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\1033\STYLES\COREv15.css" Add the following text to the bottom of the files .ms-core-needIEFilter .ms-core-overlay filter none !important .ms-core-needIEFilter #suiteBarRightfilter none !important .ms-core-needIEFilter #suiteBarLeftfilternone !important .ms-core-needIEFilter #globalNavBoxfilternone !important




Posted on:
Categories: PowerShell
Description: PowerShell issue with passing a null string parameter
Scenario You are using PowerShell to execute a Method on a C# Object. This Method has a string parameter which you must pass a null string into. All of the usual options did not work, $null, [String]Empty, [object]$null, [string]$null… Solution I found a Bug Report on https//connect.microsoft.com/PowerShell/feedback/details/307821/it-isnt-possible-to-pass-null-as-null-into-a-net-method-that-has-a-parameter-of-type-string The fix has been rolled into PowerShell 3.0 To Pass a Null string use the following Static Method [System.Management.Automation.Language.NullString]Value For us Stuck on PowerShell 2.0, I have taken the code from PowerShell 3.0 and converted it to inline c# $Assem = ("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") $cSharp = @" using System; namespace PSHelper public class NullString private readonly static NullString _value; public static NullString Value get return NullString._value; static NullString() NullString._value = new NullString(); private NullString() public override string ToString() return null; "@ Add-Type -ReferencedAssemblies $Assem -TypeDefinition $cSharp -Language CSharp; [PSHelper.NullString]Value




Posted on:
Categories: SharePoint
Description: A simple script to clear the SharePoint Workflow History List
Scenario You receive the following error when opening the Workflow History List This view cannot be displayed because it exceeds the list view threshold (5000 items) enforced by the administrator. Solution SharePoint has a notion of "List View Thresholds", where it restricts the number of items that a databases operation can involve at one time. If you have a site where workflows are used heavily, then it is very easy to overrun the default 5000 item limit. To solve this solution, either increase the List View Threshold or remove some items from the list. Be careful, there are a many blogs mentioning the Automatic Workflow Cleanup Timer Job. This job does not clean up the Workflow History list, it removes the item workflow Associations. In my case, this specific list had almost 2 million items! After looking over a number of blogs I pieced together a script. #----------------------------------------------------------------------------- # Name Clear-SPList.ps1 # Description This script will clear a SPList # Example Clear-SPList -WebUrl "http//siteurl" -ListName "Workflow History"; # Usage Run the function with the required parameters # By Ivan Josipovic, Softlanding.ca #----------------------------------------------------------------------------- Function Clear-SPList($WebUrl, $ListName) Add-PSSnapin Microsoft.SharePoint.Powershell -EA 0; $web = get-spweb $weburl; $list = $web.lists[$ListName]; $stringbuilder = new-object System.Text.StringBuilder; $stringbuilder.Append("") | Out-Null; $spQuery = New-Object Microsoft.SharePoint.SPQuery; $spQuery.ViewAttributes = 'Scope="Recursive"'; $spQuery.ViewFields = ''; $spQuery.Query = ''; $spQuery.RowLimit = 2000; do $listItems = $list.GetItems($spQuery) $spQuery.ListItemCollectionPosition = $listItems.ListItemCollectionPosition foreach ($item in $listItems) $stringbuilder.AppendFormat("") | Out-Null; $stringbuilder.AppendFormat("0", $list.ID) | Out-Null; $stringbuilder.AppendFormat("0", $item.Id) | Out-Null; $stringbuilder.Append("Delete") | Out-Null; $stringbuilder.Append("") | Out-Null; $stringbuilder.Append("") | Out-Null; $web.ProcessBatchData($stringbuilder.ToString()) | Out-Null; while ($spQuery.ListItemCollectionPosition -ne $null) write-host "Done";




Posted on:
Categories: SharePoint
Description: SharePoint Workflows won't associate with a List.
Scenario You create a SharePoint Designer Workflow and Publish it. When you try to start the workflow, if fails and then it disappears. The workflow no longer appears to be associated with the list in SharePoint Designer and in the Library Workflow Settings Page. Solution ULS Logs Showed the following error RunWorkflow System.ArgumentException Item does not exist. It may have been deleted by another user. at Microsoft.SharePoint.SPList.GetItemById(String strId, Int32 id, String strRootFolder, Boolean cacheRowsetAndId, String strViewFields, Boolean bDatesInUtc, Boolean bExpandQuery) at Microsoft.SharePoint.SPList.GetItemById(String strId, Int32 id, String strRootFolder, Boolean cacheRowsetAndId, String strViewFields, Boolean bDatesInUtc) at Microsoft.SharePoint.SPList.GetItemById(String strId, Int32 id, String strRootFolder, Boolean cacheRowsetAndId, String strViewFields) at Microsoft.SharePoint.SPList.GetItemById(Int32 id, String strRootFolder, Boolean cacheRowsetAndId, String strViewFields) at Microsoft.SharePoint.Workflow.SPWorkflowNoCodeSupport.LoadWorkflowBytesElevated(SPWeb web, Guid docLibID, Int32 fileID, Int32 fileVer, Boolean fallback, Int32& userid, DateTime& lastModified) at Microsoft.SharePoint.Workflow.SPWorkflowNoCodeSupport.<>c__DisplayClass1.<LoadWorkflowBytes>b__0(SPSite elevatedSite, SPWeb elevatedWeb) at Microsoft.SharePoint.Workflow.SPWorkflowNoCodeSupport.LoadWorkflowBytes(SPWeb web, Guid docLibID, Int32 fileID, Int32 fileVer, Boolean fallback, Int32& userid) at Microsoft.SharePoint.Workflow.SPNoCodeXomlCompiler.LoadXomlAssembly(SPWorkflowAssociation association, SPWeb web) at Microsoft.SharePoint.Workflow.SPWinOeHostServices.LoadDeclarativeAssembly(SPWorkflowAssociation association, Boolean fallback) at Microsoft.SharePoint.Workflow.SPWinOeHostServices.CreateInstance(SPWorkflow workflow) at Microsoft.SharePoint.Workflow.SPWinOeEngine.RunWorkflow(SPWorkflowHostService host, SPWorkflow workflow, Collection`1 events, TimeSpan timeOut) at Microsoft.SharePoint.Workflow.SPWorkflowManager.RunWorkflowElev(SPWorkflow workflow, Collection`1 events, SPWorkflowRunOptionsInternal runOptions) Next, I opened SharePoint designer and browsed to the Workflow library This is the location of the SharePoint Designer Workflow Definitions I noticed that the files were all checked out If I try to check in the files, I receive the following error After Googling this issue further, people suggested to check the required fields on the Workflow Library, specifically the Title Column. Changing the Title Column to Not Required resolve this issue. After digging into this further, the issue was caused by a user updating the Title Field and setting it to required on the whole site.




Posted on:
Categories: SharePoint
Description: A PowerShell Wrapper for stsadm.exe -o localupgradestatus which only displays Errors.
Scenario As a SharePoint Admin, one of the regular tasks we perform after patching is to validate that all components have been successfully patched. The recommended way is to utilizes STSADM.exe with the "-o localupgradestatus" parameter. There is no PowerShell equivalent for this command. This command will return a large XML file which needs to be reviewed for errors. This process is tedious and error prone as we have to manually look for a Status of Error. Solution We have written a script which will run the STSADM command mentioned above, but, will only return Objects which have an Error Status. #------------------------------------------------------------------------------------------- # Name Get-SPLocalUpgradeStatus # Description This script will display objects which need to be upgraded # Usage Run the function with the required parameters # By Ivan Josipovic, softlanding.ca #------------------------------------------------------------------------------------------- Function Get-SPLocalUpgradeStatus () Add-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction 0; $ErrorActionPreference = "Stop"; $RawXML = stsadm.exe -o localupgradestatus; $xml = [xml]($RawXML | Select-Object -First ($RawXML.Length - 6)); $output = $xml.Objects.Object | ? $_.Status -ne "OK" | Format-List; if ($output) $output else Write-Host -Foregroundcolor green "All is well!"; Get-SPLocalUpgradeStatus;




Posted on:
Categories: PowerShell;SharePoint
Description:
After discovering that migrating OneNote notebooks from one SharePoint location to another is difficult to do while maintaining the integrity of the notebooks (http//help.share-gate.com/article/907-onenote-migration), I needed to retrieve an inventory of all OneNote notebooks that reside on a collection of Office365 personal sites. Once I had a list of OneNote notebooks I could begin the process of migrating them in such a way that their integrity is maintained. The following script uses the Client Side Object Model to find all OneNote notebooks. It will export a list of OneNote notebooks to a csv file. ​Make sure that the script is run in the same directory as the SharePoint Client dlls. #Search for all OneNote files in a collection of Office365 sites $globalnotebooks = @() Add-Type -Path "Microsoft.SharePoint.Client.dll" Add-Type -Path "Microsoft.SharePoint.Client.Runtime.dll" $cred = Get-Credential -Message "Enter your credentials for SharePoint Online" $globalspoCred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName, $cred.Password) Function Get-OneNoteInventory($url) $clientContext = New-Object Microsoft.SharePoint.Client.ClientContext($url) $clientContext.Credentials = $spoCred $list = $clientContext.Web.Lists.GetByTitle("Documents") $query = New-Object Microsoft.SharePoint.Client.CamlQuery $query.ViewXml = " <View> <Query> <Where> <Eq> <FieldRef Name='HTML_x0020_File_x0020_Type' /> <Value Type='Computed'>OneNote.Notebook</Value> </Eq> </Where> </Query> </View>" $listItems = $list.GetItems($query) $clientContext.Load($listItems) $clientContext.ExecuteQuery() $listUrl = $list.Context.Url foreach ($listItem in $listItems) $fullUrl = $listUrl + $listItem["FileRef"] $o = new-object psobject $o | Add-Member -MemberType noteproperty -Name Name -value $listItem['Title'] $o | Add-Member -MemberType noteproperty -Name Path -value $fullUrl $globalnotebooks += $o $urls = @( "https//contoso-my.sharepoint.com/personal/user1", "https//contoso-my.sharepoint.com/personal/user2", "https//contoso-my.sharepoint.com/personal/user3", "https//contoso-my.sharepoint.com/personal/user4", "https//contoso-my.sharepoint.com/personal/user5", "https//contoso-my.sharepoint.com/personal/user6", "https//contoso-my.sharepoint.com/personal/user7" ) foreach($url in $urls) Get-OneNoteInventory -Url $url $globalnotebooks | export-csv "OneNote_Inventory.csv" -noTypeInformation ​