Sometimes you wish there was an easier way to identify all custom columns, content types and lists of your SharePoint sites. Although you have defined a few best practices before you started the project – e.g. “Don’t apply any changes to the out-of-the-box columns and content types”, “Collect all your custom columns in the same group” and “Don’t use any spaces or special characters when creating a new column” – some columns and content types fall between the cracks.

Sometimes you are looking for a quick way to get a good overview of the site architecture of your SharePoint sites to add to your project documentation and you don’t feel like listing all the columns and content types manually in an Excel-file.

Sometimes you need PowerShell to export
the site architecture of your SharePoint sites!

That’s why I created the PowerShell script below to quickly export all columns, content types, lists and list views to CSV-files. After running the PowerShell script, open the CSV-files in MS Excel, create a table and apply some filters to easily search through your SharePoint site architecture. The PowerShell script uses the SharePoint client-side object model to iterate through all SharePoint sites in your site collection recursively.

To download the PowerShell script, click here.

If you are a SharePoint developer and you are looking for an easy way to explore the properties of a column, content type, list, site property bag, user profile or whatever, then try SharePoint Manager for SharePoint on-premise environments or SharePoint Client Browser for Office 365 environments.

# LOAD CSOM LIBRARIESWrite-Host "Load CSOM libraries" -foregroundcolor black -backgroundcolor yellowAdd-Type -Path "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SharePoint.Client\v4.0_16.0.0.0__71e9bce111e9429c\Microsoft.SharePoint.Client.dll"Add-Type -Path "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SharePoint.Client.Runtime\v4.0_16.0.0.0__71e9bce111e9429c\Microsoft.SharePoint.Client.Runtime.dll"Add-Type -Path "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SharePoint.Client.Taxonomy\v4.0_16.0.0.0__71e9bce111e9429c\Microsoft.SharePoint.Client.Taxonomy.dll" # SHAREPOINT PARAMS$url = "https://<<yourtenant>>.sharepoint.com"$username = "<<youruser>>@<<yourtenant>>.onmicrosoft.com"$password = "<<yourpassword>>"$password = $password | ConvertTo-SecureString -AsPlainText -force # SHAREPOINT CONTEXT$context = New-Object Microsoft.SharePoint.Client.ClientContext($url) # AUTHENTICATE SHAREPOINT CONTEXTtry{Write-Host "Authenticate to SharePoint Online site collection '$url' and get ClientContext object" -foregroundcolor black -backgroundcolor yellow$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)$context.Credentials = $credentials$context.ExecuteQuery()Write-Host "Authentication succeeded!" -foregroundcolor black -backgroundcolor green}catch{Write-Host "Authentication failed!" -foregroundcolor black -backgroundcolor redthrow} # EXPORT SITE ARCHITECTURE VARIABLES[System.Collections.ArrayList] $exportedColumns = @()[System.Collections.ArrayList] $exportedContentTypes = @()[System.Collections.ArrayList] $exportedLists = @()[System.Collections.ArrayList] $exportedListViews = @()[System.Collections.ArrayList] $exportedTerms = @() # EXPORT SITE ARCHITECTURE FUNCTIONSfunction ExportIA([Microsoft.SharePoint.Client.Web] $web){ExportColumns $webExportContentTypes $webExportLists $web $subWebs = $web.Webs$context.Load($subWebs)$context.ExecuteQuery() foreach ($subWeb in $subWebs){ExportIA $subWeb}} function ExportColumns([Microsoft.SharePoint.Client.Web] $web){$fields = $web.Fields$context.Load($fields)$context.ExecuteQuery() foreach ($field in $fields){$exportedColumn = New-Object -TypeName PSObject -Property @{Site = $web.TitleSiteUrl = $web.UrlColumnGroup = $field.GroupColumnTitle = $field.TitleColumnInternalName = $field.InternalNameColumnDescription = $field.DescriptionColumnType = $listField.TypeDisplayNameColumnRequired = $field.RequiredColumnHidden = $field.Hidden} | Select-Object Site,SiteUrl,ColumnGroup,ColumnTitle,ColumnDescription,ColumnInternalName,ColumnType,ColumnRequired,ColumnHidden $exportedColumns.Add($exportedColumn) > $null}} function ExportContentTypes([Microsoft.SharePoint.Client.Web] $web){$contenttypes = $web.ContentTypes$context.Load($contenttypes)$context.ExecuteQuery() foreach ($contenttype in $contenttypes){$contenttypeFields = $contenttype.Fields$context.Load($contenttypeFields)$context.ExecuteQuery() foreach ($contenttypeField in $contenttypeFields){$exportedContentType = New-Object -TypeName PSObject -Property @{Site = $web.TitleSiteUrl = $web.UrlContentTypeGroup = $contenttype.GroupContentTypeID = $contenttype.IdContentTypeName = $contenttype.NameContentTypeDescription = $contenttype.DescriptionColumnTitle = $contenttypeField.TitleColumnInternalName = $contenttypeField.InternalNameColumnType = $listField.TypeDisplayNameColumnRequired = $contenttypeField.RequiredColumnHidden = $contenttypeField.Hidden} | Select-Object Site,SiteUrl,ContentTypeGroup,ContentTypeID,ContentTypeName,ContentTypeDescription,ColumnTitle,ColumnInternalName,ColumnType,ColumnRequired,ColumnHidden $exportedContentTypes.Add($exportedContentType) > $null}}} function ExportLists([Microsoft.SharePoint.Client.Web] $web){$lists = $web.Lists$context.Load($lists)$context.ExecuteQuery() foreach ($list in $lists){$listRootFolder = $list.RootFolder$context.Load($listRootFolder)$listViews = $list.Views$context.Load($listViews)$listContentTypes = $list.ContentTypesif ($list.AllowContentTypes){$context.Load($listContentTypes)}$context.ExecuteQuery() if ($list.AllowContentTypes){foreach ($listContentType in $listContentTypes){$contenttypeFields = $listContentType.Fields$context.Load($contenttypeFields)$context.ExecuteQuery() foreach ($contenttypeField in $contenttypeFields){$exportedList = New-Object -TypeName PSObject -Property @{Site = $web.TitleSiteUrl = $web.UrlListTitle = $list.TitleListUrl = $listRootFolder.ServerRelativeUrlListType = $list.BaseTypeListTemplate = $list.BaseTemplateListContentType = $listContentType.NameListContentTypeID = $listContentType.IdColumnTitle = $contenttypeField.TitleColumnInternalName = $contenttypeField.InternalNameColumnType = $listField.TypeDisplayNameColumnRequired = $contenttypeField.RequiredColumnHidden = $contenttypeField.Hidden} | Select-Object Site,SiteUrl,ListTitle,ListUrl,ListType,ListTemplate,ListContentType,ListContentTypeID,ColumnTitle,ColumnInternalName,ColumnType,ColumnRequired,ColumnHidden $exportedLists.Add($exportedList) > $null}}}else{$listFields = $list.Fields$context.Load($listFields)$context.ExecuteQuery() foreach ($listField in $listFields){$exportedList = New-Object -TypeName PSObject -Property @{Site = $web.TitleSiteUrl = $web.UrlListTitle = $list.TitleListUrl = $listRootFolder.ServerRelativeUrlListType = $list.BaseTypeListTemplate = $list.BaseTemplateColumnTitle = $listField.TitleColumnInternalName = $listField.InternalNameColumnType = $listField.TypeDisplayNameColumnRequired = $listField.RequiredColumnHidden = $listField.Hidden} | Select-Object Site,SiteUrl,ListTitle,ListUrl,ListType,ListTemplate,ColumnTitle,ColumnInternalName,ColumnType,ColumnRequired,ColumnHidden $exportedLists.Add($exportedList) > $null}} foreach ($listView in $listViews){if (-not $listView.PersonalView){$viewFields = $listView.ViewFields$context.Load($viewFields)$context.ExecuteQuery() [System.Collections.ArrayList] $viewFieldArray = @();foreach ($viewField in $viewFields){$viewFieldArray.Add($viewField) > $null} $exportedListView = New-Object -TypeName PSObject -Property @{Site = $web.TitleSiteUrl = $web.UrlListTitle = $list.TitleListUrl = $listRootFolder.ServerRelativeUrlListType = $list.BaseTypeListTemplate = $list.BaseTemplateListView = $listView.TitleListViewType = $listView.ViewTypeListViewQuery = $listView.ViewQueryColumnInternalNames = [System.String]::Join(",", $viewFieldArray.ToArray())} | Select-Object Site,SiteUrl,ListTitle,ListUrl,ListType,ListTemplate,ListView,ListViewType,ListViewQuery,ColumnInternalNames $exportedListViews.Add($exportedListView) > $null}}}}# EXPORT TAXONOMY FUNCTIONSfunction ExportTaxonomy(){$taxonomySession = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($context)$context.Load($taxonomySession)$context.ExecuteQuery()$termStores = $taxonomySession.TermStores$context.Load($termStores)$context.ExecuteQuery()foreach ($termStore in $termStores){$termGroups = $termStore.Groups$context.Load($termGroups)$context.ExecuteQuery()foreach ($termGroup in $termGroups){$termSets = $termGroup.TermSets$context.Load($termSets)$context.ExecuteQuery()foreach($termSet in $termSets){$terms = $termSet.Terms$context.Load($terms)$context.ExecuteQuery()ExportTerms $termGroup $termSet $terms}}}}function ExportTerms([Microsoft.SharePoint.Client.Taxonomy.TermGroup] $termGroup, [Microsoft.SharePoint.Client.Taxonomy.TermSet] $termSet, [Microsoft.SharePoint.Client.Taxonomy.TermCollection] $terms){foreach ($term in $terms){#$termGroupName = [Microsoft.SharePoint.Taxonomy.TaxonomyItem]::NormalizeName($termGroup.Name)#$termSetName = [Microsoft.SharePoint.Taxonomy.TaxonomyItem]::NormalizeName($termSet.Name)#$termName = [Microsoft.SharePoint.Taxonomy.TaxonomyItem]::NormalizeName($term.Name)#$termPath = [Microsoft.SharePoint.Taxonomy.TaxonomyItem]::NormalizeName($term.PathOfTerm)$exportedTerm = New-Object -TypeName PSObject -Property @{TermGroupName = $termGroup.NameTermGroupId = $termGroup.IdTermSetName = $termSet.NameTermSetId = $termSet.IdTermName = $term.NameTermPath = $term.PathOfTermTermId = $term.Id} | Select-Object TermGroupName,TermGroupId,TermSetName,TermSetId,TermName,TermPath,TermId $exportedTerms.Add($exportedTerm) > $null$subTerms = $term.Terms$context.Load($subTerms)$context.ExecuteQuery()ExportTerms $termGroup $termSet $subTerms}} # EXPORT SITE ARCHITECTURE TO CSVtry{Write-Host "Exporting site architecture" -foregroundcolor black -backgroundcolor yellow$web = $context.Web$context.Load($web)$context.ExecuteQuery() ExportIA $webWrite-Host "Writing site architecture to CSV-files" -foregroundcolor black -backgroundcolor yellow $exportedColumns | Export-Csv sp_sitecolumns.csv -Delimiter ";" -NoTypeInformation$exportedContentTypes | Export-Csv sp_sitecontenttypes.csv -Delimiter ";" -NoTypeInformation$exportedLists | Export-Csv sp_listcontenttypes.csv -Delimiter ";" -NoTypeInformation$exportedListViews | Export-Csv sp_listviews.csv -Delimiter ";" -NoTypeInformation$exportedNavNodes | Export-Csv sp_navigation.csv -Delimiter ";" -NoTypeInformation Write-Host "Export site architecture succeeded!" -foregroundcolor black -backgroundcolor greenWrite-Host "Exporting managed metadata" -foregroundcolor black -backgroundcolor yellowExportTaxonomyWrite-Host "Writing managed metadata to CSV-files" -foregroundcolor black -backgroundcolor yellow $exportedTerms | Export-Csv sp_managedmetadata.csv -Delimiter ";" -NoTypeInformationWrite-Host "Export managed metadata succeeded!" -foregroundcolor black -backgroundcolor green}catch{Write-Host "Export failed!" -foregroundcolor black -backgroundcolor redthrow}

Maarten Ghijsens

Teamlead Office 365 Apps @ Spikes