├── Scripts ├── SharePoint.Sandbox.ListSolutionsFromTenant │ ├── Get-SPOnlineSandboxSolutionList.ps1 │ └── README.MD ├── SharePoint.Hybrid.Search.Configuration │ ├── Documentation │ │ └── Hybrid Configuration Wizard.docx │ ├── readme.md │ └── HybridWizard.ps1 ├── README.md ├── SharePoint.Hybrid.CloudSSA.Configuration │ ├── DetectWorkFlowConnection.ps1 │ ├── WorkflowManagerfixUp.ps1 │ ├── DetectProviderHostedAddIns.ps1 │ ├── AuthenticationRealmFixUp.ps1 │ ├── readme.md │ ├── SPHybridValidation.ps1 │ └── CreateHybridCloudSSA.ps1 ├── SharePoint.SiteColProvisioning.Configuration │ ├── definetenantadminsite.ps1 │ ├── allowtenantapiv16.ps1 │ ├── allowtenantapiv15.ps1 │ └── readme.md ├── readme-template.md ├── AzureAD.Principals.Expire │ ├── Principals.ps1 │ └── readme.md └── SharePoint.LowTrustACS.Configuration │ ├── LowTrustConfigurationSession.ps1 │ ├── Connect-SPFarmToAAD.psm1 │ └── readme.md ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE.md └── CONTRIBUTING.md ├── README.md ├── LICENSE └── .gitignore /Scripts/SharePoint.Sandbox.ListSolutionsFromTenant/Get-SPOnlineSandboxSolutionList.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharepoint/sp-admin-scripts/master/Scripts/SharePoint.Sandbox.ListSolutionsFromTenant/Get-SPOnlineSandboxSolutionList.ps1 -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.Search.Configuration/Documentation/Hybrid Configuration Wizard.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharepoint/sp-admin-scripts/master/Scripts/SharePoint.Hybrid.Search.Configuration/Documentation/Hybrid Configuration Wizard.docx -------------------------------------------------------------------------------- /Scripts/README.md: -------------------------------------------------------------------------------- 1 | # Patterns and Practices - Scripts # 2 | Different kind of automation scripts for SharePoint and Office 365 in general. See readme from specific folders for exact details. 3 | 4 | ![](http://i.imgur.com/I2VYM3a.png) 5 | 6 | # "Sharing is caring" # 7 | 8 | -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.CloudSSA.Configuration/DetectWorkFlowConnection.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .synopsis 3 | Script determines whether A Workflow Manager Service Application Proxy Connection is deployed to the local farm. 4 | .example 5 | .\DetectWorkFlowConnection.ps1 6 | #> 7 | if ((Get-PSSnapin -Name "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) 8 | { 9 | Add-PSSnapin -Name "Microsoft.SharePoint.PowerShell" 10 | } 11 | cls 12 | 13 | $workflowproxy = Get-SPWorkflowServiceApplicationProxy 14 | 15 | if ($workflowproxy) 16 | { 17 | Write-Output "Workflow Manager Connection Detected. Use documented remediation steos to update it after hybrid deployment" 18 | } 19 | else 20 | { 21 | Write-Output "No Workflow Manager Connection Detected. Remediation not required" 22 | } -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | | Q | A | 2 | | --------------- | --------------------------------------- | 3 | | Bug fix? | no - yes? | 4 | | New feature? | no - yes? | 5 | | New script? | no - yes? | 6 | | Related issues? | fixes #X, partially #Y, mentioned in #Z | 7 | 8 | ## What's in this Pull Request? 9 | 10 | > Please describe the changes in this PR. Sample description or details around bugs which are being fixed. 11 | > 12 | > _(DELETE THIS PARAGRAPH AFTER READING)_ 13 | 14 | ## Guidance 15 | 16 | > *Please update this PR information accordingly. We'll use this as part of our release notes in monthly communications.* 17 | > 18 | > *Please target your PR to `master` branch.* 19 | > 20 | > _(DELETE THIS PARAGRAPH AFTER READING)_ 21 | -------------------------------------------------------------------------------- /Scripts/SharePoint.SiteColProvisioning.Configuration/definetenantadminsite.ps1: -------------------------------------------------------------------------------- 1 | param 2 | ( 3 | [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] 4 | [String]$siteColUrl 5 | ) 6 | # 7 | # Set admin site type property to the site collection using PS for any site collection type. 8 | # This is needed to be set for the site collection which is used as the 9 | # "Connection point" for the CSOM when site collections are created in on-prem 10 | # 11 | 12 | $snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'} 13 | if ($snapin -eq $null) 14 | { 15 | Write-Host "Loading SharePoint Powershell Snapin" 16 | Add-PSSnapin "Microsoft.SharePoint.Powershell" 17 | } 18 | 19 | $site = get-spsite -Identity $siteColUrl 20 | $site.AdministrationSiteType = [Microsoft.SharePoint.SPAdministrationSiteType]::TenantAdministration 21 | 22 | Write-Host "Site $siteColUrl set to AdministrationSiteType" $site.AdministrationSiteType -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributing 3 | 4 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 5 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 6 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 7 | 8 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 9 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 10 | provided by the bot. You will only need to do this once across all repos using our CLA. 11 | 12 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 13 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 14 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 15 | -------------------------------------------------------------------------------- /Scripts/readme-template.md: -------------------------------------------------------------------------------- 1 | # Title of the Script (SEO friendly) # 2 | 3 | ## Summary ## 4 | 5 | Description of the script 6 | 7 | ### Applies to ### 8 | 9 | - OneDrive 10 | - Potentially SharePoint if applies there as well 11 | 12 | ### Prerequisites ### 13 | 14 | - if any 15 | 16 | ### Solution ### 17 | Solution | Author(s) 18 | ---------|---------- 19 | Name of the solution | name (company name) 20 | 21 | ### Version history ### 22 | Version | Date | Comments 23 | ---------| -----| -------- 24 | 1.0 | February 8th 2026 | Initial release 25 | 26 | ### Disclaimer ### 27 | 28 | **THIS SCRIPT 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.** 29 | 30 | ---------- 31 | 32 | # Introduction 33 | 34 | Description of the script and what it does with potential set of additional links, images and other references. 35 | 36 | -------------------------------------------------------------------------------- /Scripts/AzureAD.Principals.Expire/Principals.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | This cmdlet will list out all the expired service principals 4 | 5 | Goals 6 | · Prevent expired client id 7 | 8 | 9 | .EXAMPLE 10 | 11 | -------------------------- EXAMPLE 01 -------------------------- 12 | Get-ExpiredServicePrincipals 13 | 14 | #> 15 | 16 | function Get-ExpiredServicePrincipals { 17 | #filter out Microsoft and WorkFlow 18 | $applist = Get-MsolServicePrincipal -all | Where-Object -FilterScript { ($_.DisplayName -notlike "*Microsoft*") -and ($_.DisplayName -notlike "*WorkFlow*") } 19 | $today = get-date 20 | 21 | foreach ($appentry in $applist) { 22 | $pc = Get-MsolServicePrincipalCredential -AppPrincipalId $appentry.AppPrincipalId -ReturnKeyValues $false | Where-Object { ($_.Type -ne "Other") -and ($_.Type -ne "Asymmetric") -and ($_.EndDate -lt $today)} 23 | if($pc){ 24 | Write-Host $appentry.DisplayName, $appentry.AppPrincipalId , $pc[0].EndDate.DateTime 25 | } 26 | } 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 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 | -------------------------------------------------------------------------------- /Scripts/SharePoint.SiteColProvisioning.Configuration/allowtenantapiv16.ps1: -------------------------------------------------------------------------------- 1 | param 2 | ( 3 | [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] 4 | [String]$WebApplicationUrl 5 | ) 6 | # 7 | # Enable the remote site collection creation for on-prem in web application level 8 | # If this is not done, unknon object exception is raised by the CSOM code 9 | # 10 | $snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'} 11 | if ($snapin -eq $null) 12 | { 13 | Write-Host "Loading SharePoint Powershell Snapin" 14 | Add-PSSnapin "Microsoft.SharePoint.Powershell" 15 | } 16 | 17 | $webapp=Get-SPWebApplication $WebApplicationUrl 18 | $newProxyLibrary = New-Object "Microsoft.SharePoint.Administration.SPClientCallableProxyLibrary" 19 | $newProxyLibrary.AssemblyName = "Microsoft.Online.SharePoint.Dedicated.TenantAdmin.ServerStub, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" 20 | $newProxyLibrary.SupportAppAuthentication = $true 21 | $webapp.ClientCallableSettings.ProxyLibraries.Add($newProxyLibrary) 22 | $webapp.SelfServiceSiteCreationEnabled=$true 23 | $webapp.Update() 24 | Write-Host "Successfully added TenantAdmin ServerStub to ClientCallableProxyLibrary for web application" $WebApplicationUrl 25 | # Reset the memory of the web application 26 | Write-Host "IISReset..." 27 | Restart-Service W3SVC,WAS -force 28 | Write-Host "IISReset complete on this server, remember other servers in farm as well." -------------------------------------------------------------------------------- /Scripts/SharePoint.SiteColProvisioning.Configuration/allowtenantapiv15.ps1: -------------------------------------------------------------------------------- 1 | param 2 | ( 3 | [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] 4 | [String]$WebApplicationUrl 5 | ) 6 | # 7 | # Enable the remote site collection creation for on-prem in web application level 8 | # If this is not done, unknon object exception is raised by the CSOM code 9 | # 10 | $snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'} 11 | if ($snapin -eq $null) 12 | { 13 | Write-Host "Loading SharePoint Powershell Snapin" 14 | Add-PSSnapin "Microsoft.SharePoint.Powershell" 15 | } 16 | 17 | $webapp=Get-SPWebApplication $WebApplicationUrl 18 | $newProxyLibrary = New-Object "Microsoft.SharePoint.Administration.SPClientCallableProxyLibrary" 19 | $newProxyLibrary.AssemblyName = "Microsoft.Online.SharePoint.Dedicated.TenantAdmin.ServerStub, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" 20 | $newProxyLibrary.SupportAppAuthentication = $true 21 | $webapp.ClientCallableSettings.ProxyLibraries.Add($newProxyLibrary) 22 | $webapp.SelfServiceSiteCreationEnabled=$true 23 | $webapp.Update() 24 | Write-Host "Successfully added TenantAdmin ServerStub to ClientCallableProxyLibrary for web application" $WebApplicationUrl 25 | # Reset the memory of the web application 26 | Write-Host "IISReset..." 27 | Restart-Service W3SVC,WAS -force 28 | Write-Host "IISReset complete on this server, remember other servers in farm as well." 29 | -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.Search.Configuration/readme.md: -------------------------------------------------------------------------------- 1 | # Hybrid Configuration Wizard # 2 | 3 | ### Summary ### 4 | 5 | This script is for use in configuring an outbound search hybrid experience between SharePoint 2013 Server and SharePoint Online. In preliminary testing this also works with TAP builds of SharePoint 2016. 6 | 7 | See following blog post for additional details 8 | - [Cloud Hybrid Search Service Application](http://blogs.msdn.com/b/spses/archive/2015/09/15/cloud-hybrid-search-service-application.aspx) 9 | 10 | *work in progress* 11 | 12 | ### Applies to ### 13 | - SharePoint 2013 on-premises 14 | - SharePoint 2016 on-premises 15 | 16 | ### Prerequisites ### 17 | Any special pre-requisites? 18 | 19 | ### Solution ### 20 | Solution | Author(s) 21 | ---------|---------- 22 | Hybrid Configuration Wizard | Manas Biswas (Microsoft), Neil Hodgkinson (Microsoft) 23 | 24 | ### Version history ### 25 | Version | Date | Comments 26 | ---------| -----| -------- 27 | 1.0 | November 20th 2015 | Initial release 28 | 29 | ### Disclaimer ### 30 | **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.** 31 | 32 | 33 | ---------- 34 | 35 | # For detailed description of scenarios and steps, please refer to following documentation in the repository.# 36 | 37 | ## Hybrid Configuration Wizard ## 38 | Located under the *Documents* folder. Contains similar information as the mentioned blog post. 39 | 40 | -------------------------------------------------------------------------------- /Scripts/AzureAD.Principals.Expire/readme.md: -------------------------------------------------------------------------------- 1 | # Azure Active Directory Principals # 2 | 3 | ### Summary ### 4 | This script will assist you discovery of Client ID's that have expired in your Azure Active Directory Tenant 5 | 6 | *work in progress* 7 | 8 | ### Applies to ### 9 | - SharePoint 2013 on-premises - Low Trust Configuration 10 | - SharePoint 2016 on-premises - Low Trust Configuration 11 | - SharePoint Online MT and Dedicated Services 12 | 13 | ### Prerequisites ### 14 | [Microsoft Online Services Sign-In](https://www.microsoft.com/en-us/download/details.aspx?id=39267) Assistant is installed 15 | [Microsoft Online Services PowerShell Module](http://go.microsoft.com/fwlink/p/?linkid=236297) is installed 16 | 17 | 18 | ### Solution ### 19 | Solution | Author(s) 20 | ---------|---------- 21 | Principals | Frank Marasco (Microsoft) 22 | 23 | ### Version history ### 24 | Version | Date | Comments 25 | ---------| -----| -------- 26 | 1.0 | April 19th 2016 | Initial release 27 | 28 | ### Disclaimer ### 29 | **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.** 30 | 31 | 32 | ---------- 33 | 34 | ## Execution ## 35 | 36 | Connect-MSolService 37 | 38 | ![](http://i.imgur.com/kXMizJt.png) 39 | 40 | Get-ExpiredServicePrincipals 41 | 42 | ![](http://i.imgur.com/4jVYbWP.png) 43 | 44 | 45 | ## Resources ## 46 | Replace an expiring client secret in a SharePoint Add-in](https://msdn.microsoft.com/en-us/library/office/dn726681.aspx) 47 | 48 | -------------------------------------------------------------------------------- /Scripts/SharePoint.LowTrustACS.Configuration/LowTrustConfigurationSession.ps1: -------------------------------------------------------------------------------- 1 | 2 | param 3 | ( 4 | [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] [String]$PFXFile, 5 | [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] [String]$PFXPassword, 6 | [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] [String]$ConnectSPFarmToAADModulePath 7 | ) 8 | 9 | #Load the PS module when needed 10 | $snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'} 11 | if ($snapin -eq $null) 12 | { 13 | Write-Host "Loading SharePoint Powershell Snapin" 14 | Add-PSSnapin "Microsoft.SharePoint.Powershell" 15 | } 16 | 17 | #Import the signing certificate and reset the timer service 18 | $stsCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $PFXFile, $PFXPassword, 20 19 | Set-SPSecurityTokenServiceConfig –ImportSigningCertificate $stsCertificate -confirm:$false 20 | iisreset 21 | net stop SPTimerV4 22 | net start SPTimerV4 23 | 24 | #Load the custom module with the Connect-SPFarmToAAD command 25 | Import-Module ("{0}\Connect-SPFarmToAAD.psm1" -f $ConnectSPFarmToAADModulePath) 26 | ls function:\ | where {$_.Name -eq "Connect-SPFarmToAAD"} 27 | 28 | Write-Host 29 | Write-Host "Use the Connect-SPFarmToAAD cmdlet to realize the low trust connection between your on-premises farm and your Office 365 tenant." -ForegroundColor Green 30 | Write-Host "See below for typical sample usages:" 31 | 32 | Write-Host "Connect-SPFarmToAAD –AADDomain 'MyO365Domain.onmicrosoft.com' –SharePointOnlineUrl https://MyO365Domain.sharepoint.com" -ForegroundColor Cyan 33 | Write-Host "Connect-SPFarmToAAD –AADDomain 'MyO365Domain.onmicrosoft.com' –SharePointOnlineUrl https://MyO365Domain.sharepoint.com –SharePointWeb https://fabrikam.com" -ForegroundColor Cyan 34 | Write-Host "Connect-SPFarmToAAD –AADDomain 'MyO365Domain.onmicrosoft.com' –SharePointOnlineUrl https://MyO365Domain.sharepoint.com –SharePointWeb http://northwind.com -AllowOverHttp" -ForegroundColor Cyan 35 | Write-Host "Connect-SPFarmToAAD –AADDomain 'MyO365Domain.onmicrosoft.com' –SharePointOnlineUrl https://MyO365Domain.sharepoint.com –SharePointWeb http://northwind.com –AllowOverHttp –RemoveExistingACS –RemoveExistingSTS –RemoveExistingSPOProxy –RemoveExistingAADCredentials" -ForegroundColor Cyan 36 | Write-Host "More information can be found at https://msdn.microsoft.com/en-us/library/office/dn155905.aspx" 37 | Write-Host -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.CloudSSA.Configuration/WorkflowManagerfixUp.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .synopsis 3 | This script will detect the details of the workflow manager proxy on the farm and recreate the proxy connection 4 | .description 5 | This script will detect the details of the workflow manager proxy on the farm and recreate the proxy connection 6 | The proxy connection needs to be recreated due tot he change in AuthentivationRealm ID caused by hybrid deployment. 7 | 8 | Run the script as a farm and local admin on a SharePoint server. 9 | 10 | .example 11 | .\WorkflowManagerfixUp.ps1 12 | #> 13 | 14 | if ((Get-PSSnapin -Name "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) 15 | { 16 | Add-PSSnapin -Name "Microsoft.SharePoint.PowerShell" 17 | } 18 | cls 19 | 20 | 21 | function Update-WorkflowManagerProxyConnection 22 | { 23 | 24 | $workflowproxy = Get-SPWorkflowServiceApplicationProxy 25 | try 26 | { 27 | $webapp = get-spwebapplication 28 | } 29 | catch {} 30 | 31 | if ($webapp) 32 | { 33 | $webappurl = $webapp[0].url 34 | try 35 | { 36 | $Site=get-spsite $webappurl 37 | } 38 | catch {} 39 | 40 | if ($site) 41 | { 42 | $workflowaddress = $workflowproxy.GetWorkflowServiceAddress($site) 43 | $workflowscopename = $workflowproxy.GetWorkflowScopeName($site) 44 | $TrimScope = '/'+$workflowscopename+'/' 45 | $wfmaddress = $workflowaddress.TrimEnd($Trimscope) 46 | } 47 | Else 48 | { 49 | Write-Warning "There is no site collection at the root of the web application. Create a site collection at $webappurl to fix the workflow manager connection" 50 | } 51 | } 52 | else 53 | { 54 | Write-Warning "There are no web applications on this farm. Workflow Manager cannot be conencted to a farm with no web applications" 55 | } 56 | 57 | write-Warning "Deleting the Workflow proxy connection to $wfmaddress" 58 | $workflowproxy.delete() 59 | 60 | try 61 | { 62 | write-output "Recreating the Workflow manager proxy connection to $wfmaddress" 63 | Register-SPWorkflowService -SPSite $Site -WorkflowHostUri $wfmaddress -Force 64 | } 65 | catch 66 | { 67 | Write-Error "Failed to create the proxy connection to $wfmaddress . Please repair this connection manually before attempting to progress any workflow on this farm" 68 | } 69 | } 70 | 71 | Update-WorkflowManagerProxyConnection -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | > Use the following form to submit an issue only if it's related to samples in this repo. If you have an issue related to the OneDrive or its documentation, please submit the issue at [https://github.com/OneDrive/onedrive-api-docs/issues/new](https://github.com/OneDrive/onedrive-api-docs/issues/new). This will help us respond to your issue faster. 2 | > 3 | > ---- 4 | > 5 | > Thank you for reporting an issue or suggesting an enhancement. We appreciate your feedback - to help the team to understand your needs, please complete the below template to ensure we have the necessary details to assist you. 6 | > 7 | > _(DELETE THIS PARAGRAPH AFTER READING)_ 8 | 9 | ## Category 10 | 11 | - [ ] Question 12 | - [ ] Bug 13 | - [x] Enhancement 14 | 15 | > For the above list, an empty checkbox is [ ] as in [SPACE]. A checked checkbox is [x] with no space between the brackets. Use the `PREVIEW` tab at the top right to preview the rendering before submitting your issue. 16 | > 17 | > _(DELETE THIS PARAGRAPH AFTER READING)_ 18 | 19 | ## Expected or Desired Behavior 20 | 21 | > _If you are reporting a bug, please describe the expected behavior. If you are suggesting an enhancement please describe thoroughly the enhancement, how it can be achieved, and expected benefit._ 22 | > 23 | > _(DELETE THIS PARAGRAPH AFTER READING)_ 24 | 25 | ## Observed Behavior 26 | 27 | > _If you are reporting a bug, please describe the behavior you expected to occur when performing the action. If you are making a suggestion, you can delete this section._ 28 | > 29 | > _(DELETE THIS PARAGRAPH AFTER READING)_ 30 | 31 | ## Steps to Reproduce 32 | 33 | > _If you are reporting a bug please describe the steps to reproduce the bug in sufficient detail to allow testing. Only way to fix things properly, is to have sufficient details to reproduce it. If you are making a suggestion, you can delete this section._ 34 | > 35 | > _(DELETE THIS PARAGRAPH AFTER READING)_ 36 | 37 | ## Submission Guidelines 38 | 39 | > - All suggestions or bugs are welcome, please let us know what's on your mind. 40 | > - If you are reporting an issue around any of the samples, please ensure that you have clear reference on the sample and possibly script file, which should be fixed. 41 | > - Remember to include sufficient details and context. 42 | > - If you have multiple suggestions or bugs please submit them in separate bugs so we can track resolution. 43 | > 44 | > _(DELETE THIS PARAGRAPH AFTER READING)_ 45 | 46 | Thanks for your contribution! Sharing is caring. 47 | -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.CloudSSA.Configuration/DetectProviderHostedAddIns.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Script locates Provider Hosted AddIn Instance on the local farm and reports the AddIn name and site url . 4 | .Description 5 | Searches for provider hosted addins and need to be ran with a farm admin account 6 | .example 7 | .\DetectProviderHosterAddIns.ps1 8 | #> 9 | 10 | if ((Get-PSSnapin -Name "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) 11 | { 12 | Add-PSSnapin -Name "Microsoft.SharePoint.PowerShell" 13 | } 14 | cls 15 |   16 | function Find-AppInstances 17 | { 18 | 19 | #SUMMARY Get all app instances in each of the web applications 20 | $AppsforRemediation = @() 21 | $webApplications = Get-SPWebApplication 22 | 23 | foreach($webapp in $webapplications) 24 | { 25 | foreach($site in $webApp.Sites) 26 | { 27 | try{ 28 | foreach($web in $site.AllWebs) 29 | { 30 | $appInstance = Get-SPAppInstance -Web $web.Url | ? {$_.LaunchUrl -notlike "~appWebUrl*"} | select Title, AppPrincipalId 31 | if($appInstance -ne $null) 32 | { 33 | foreach ($instance in $appInstance) 34 | { 35 | $tmp = $instance.AppPrincipalId.Split('|@',[System.StringSplitOptions]::RemoveEmptyEntries) 36 | $appInfo = $instance.Title + " - " + $tmp[$tmp.Count - 2] + " - " + $web.Url 37 | 38 | $AppsforRemediation+=(,($instance.Title, $tmp[$tmp.Count - 2], $web.Url)) 39 | } 40 | } 41 | } 42 | } 43 | catch 44 | { 45 | # Typically this scenario would only arise when the Admin executing the script is not a farm admin, or the site is a Fast Site creation Master template site which is inaccessible by default. 46 | Write-Output "" 47 | write-warning "Unable to enumerate webs at Site: $site.url : If this is expected then ignore this message" 48 | Write-Output "" 49 | } 50 | } 51 | } 52 | } 53 | 54 | Find-AppInstances 55 | 56 | if($AppsforRemediation.Count -gt 0) 57 | { 58 | $AppCount = $AppsforRemediation.Count 59 | Write-Output "" 60 | Write-Output "Provider Hosted App Instances Discovered: $AppCount Total PHAs" 61 | 62 | for ($i = 0; $i -lt $AppCount; $i++) 63 | { 64 | 65 | $appTitle = $AppsforRemediation[$i][0] 66 | $clientID = $AppsforRemediation[$i][1] 67 | $targetWeb = Get-SPWeb $AppsforRemediation[$i][2] 68 | $appweb = $targetWeb.Url 69 | 70 | Write-Output "" 71 | Write-Output "Provider Hosted App $appTitle discovered on site $appweb" 72 | } 73 | } 74 | Else 75 | { 76 | Write-Output "" 77 | Write-Output "No Provider Hosted App Instances Discovered: Remediation not required" 78 | } -------------------------------------------------------------------------------- /Scripts/SharePoint.SiteColProvisioning.Configuration/readme.md: -------------------------------------------------------------------------------- 1 | # PowerShell to enable site collection creation with CSOM # 2 | 3 | ### Summary ### 4 | Scripts and instructions that explain how to enable CSOM based site collection creation in on-premises SharePoint 2013 or 2016. 5 | 6 | ### Applies to ### 7 | - SharePoint 2013 on-premises 8 | - SharePoint 2016 on-premises 9 | - SharePoint 2019 on-premises 10 | 11 | ### Prerequisites ### 12 | Capability is introduced in April 2014 CU for SP2013 and is included in SharePoint 2016 and SharePoint 2019. 13 | 14 | ### Solution ### 15 | Solution | Author(s) 16 | ---------|---------- 17 | Site Collection provisioning scripts | Vesa Juvonen, Bert Jansen (**Microsoft**) 18 | 19 | ### Version history ### 20 | Version | Date | Comments 21 | ---------| -----| -------- 22 | 1.1 | July 3rd 2018 | Adding notes on the SharePoint 2019 23 | 1.0 | February 8th 2016 | Initial release 24 | 25 | ### Disclaimer ### 26 | **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.** 27 | 28 | 29 | ---------- 30 | 31 | # Introduction 32 | In order to enable site collection using the CSOM CreateSite method you need to run the below two scripts on your SharePoint on-premises farm (SP2013, SP2016, SP2019). 33 | 34 | > **Important.** If you are enabling this capability in SharePoint 2019 farm, you can skip Step #1. 35 | 36 | ## Step 1: Flag a site as "tenant admin" site (SharePoint 2013, SharePoint 2016) 37 | 38 | The `CreateSite` CSOM operation will server side use the multi-tenant CreateSite API's which has as consequence that these API's will need a tenant admin site to function. Luckily you do not to setup the multi-tenant features in your environment, but rather simply **mark** a site as tenant admin site by setting it's `AdministrationSiteType` property to `SPAdministrationSiteType.TenantAdministration`. This site can be **any** site collection, but it's recommended to create a separate site collection with a meaningful name (e.g. TenantAdmin) as this will avoid accidental deletion. 39 | 40 | You can do this by running the `definetenantadminsite.ps1` script like shown below: 41 | 42 | ```PowerShell 43 | .\definetenantadminsite.ps1 -siteColUrl https://portal2016b4327.pnp.com/sites/tenantadmin 44 | ``` 45 | 46 | This will result in the following output: 47 | 48 | ``` 49 | Loading SharePoint Powershell Snapin 50 | Site https://portal2016b4327.pnp.com/sites/tenantadmin set to AdministrationSiteType TenantAdministration 51 | ``` 52 | 53 | 54 | ## Step 2: Prepare the web application(s) to enable the CreateSite CSOM method 55 | 56 | Each web application for which you want to be able to create site collections using the `CreateSite` CSOM method needs to be prepared by: 57 | 58 | - Adding the TenantAdmin CSOM stub to the list of allowed client callable proxy libraries 59 | - Enabling self service site collection creation 60 | 61 | You can perform the above 2 steps by running `allowtenantapiv15.ps1` when you're working with SharePoint 2013 or `allowtenantapiv16.ps1` when you're using SharePoint 2016 or SharePoint 2019 version.. 62 | 63 | **Note:** 64 | This will perform an IISReset on the server you run this. **Don't forget to perform an IISReset on the other servers in the farm.** 65 | 66 | 67 | ```PowerShell 68 | .\allowtenantapiv16.ps1 -WebApplicationUrl https://portal2016b4327.pnp.com 69 | ``` 70 | 71 | This will result in the following output: 72 | 73 | ``` 74 | Successfully added TenantAdmin ServerStub to ClientCallableProxyLibrary for web application https://portal2016b4327.pnp.com 75 | IISReset... 76 | WARNING: Waiting for service 'World Wide Web Publishing Service (W3SVC)' to stop... 77 | WARNING: Waiting for service 'Windows Process Activation Service (WAS)' to stop... 78 | IISReset complete on this server, remember other servers in farm as well. 79 | ``` 80 | To finalize this step you'll need to perform an IISReset on all the other servers in the farm. 81 | 82 | 83 | -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.CloudSSA.Configuration/AuthenticationRealmFixUp.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Script fixes the scenario where a hybrid workload has been onboarded to a farm and the result is broken PHAs. 4 | .Description 5 | This scripts will fix the PHAs and need to be ran with a farm admin account 6 | .EXAMPLE 7 | .\AuthenticationRealmFixUp.ps1 8 | Reports the PHAs that need to be fixed an the location where they are fixe 9 | #> 10 | 11 | if ((Get-PSSnapin -Name "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) 12 | { 13 | Add-PSSnapin -Name "Microsoft.SharePoint.PowerShell" 14 | } 15 | cls 16 |   17 | function Find-AppInstances{ 18 | 19 | #SUMMARY Get all app instances in each of the web applications 20 | $AppsforRemediation = @() 21 | $webApplications = Get-SPWebApplication 22 | 23 | foreach($webapp in $webapplications) 24 | { 25 | foreach($site in $webApp.Sites) 26 | { 27 | try 28 | { 29 | foreach($web in $site.AllWebs) 30 | { 31 | $appInstance = Get-SPAppInstance -Web $web.Url | ? {$_.LaunchUrl -notlike "~appWebUrl*"} | select Title, AppPrincipalId 32 | if($appInstance -ne $null) 33 | { 34 | foreach ($instance in $appInstance) 35 | { 36 | $tmp = $instance.AppPrincipalId.Split('|@',[System.StringSplitOptions]::RemoveEmptyEntries) 37 | $appInfo = $instance.Title + " - " + $tmp[$tmp.Count - 2] + " - " + $web.Url 38 | 39 | $AppsforRemediation+=(,($instance.Title, $tmp[$tmp.Count - 2], $web.Url)) 40 | } 41 | } 42 | } 43 | } 44 | catch 45 | { 46 | # Typically this scenario would only arise when the Admin executing the script is not a farm admin, or the site is a Fast Site creation Master template site which is inaccessible by default. 47 | Write-Output "" 48 | write-warning "Unable to enumerate webs at Site: $site.url : If this is expected then ignore this message" 49 | Write-Output "" 50 | } 51 | } 52 | } 53 | } 54 | 55 |   56 | function Repair-TrustedSecurityTokenIssuer { 57 | 58 | #SUMMARY Fix up the SPTrustedSecurityTokenIssuers with the new SPAuthenticationRealmID to match the Office365 59 | 60 |   61 | $NewRealm = Get-SPAuthenticationRealm 62 | $sts = Get-SPTrustedSecurityTokenIssuer | ? {$_.Name -ne 'EvoSTS-Trust' -and $_.Name -ne 'ACS_STS'} | Select RegisteredIssuerName 63 | $realm = $sts | ?{$_.RegisteredIssuerName -ne $null} | %{$($($_.RegisteredIssuerName).toString().split('@',2)[1]).toString()} | ?{$_ -ne '*' -and $_ -ne $newRealm} 64 | 65 | if($Realm.count -gt 0) 66 | { 67 | try{ 68 | $TempRealm = '*@$($NewRealm)' 69 | $Issuers = Get-SPTrustedSecurityTokenIssuer | ?{$_.Name -ne 'EvoSTS-Trust' -and $_.Name -ne 'ACS_STS' -and $_.RegisteredIssuerName -ne $null -and $_.RegisteredIssuerName -notlike '*@`*' -and $_.RegisteredIssuerName -notlike $TempRealm} 70 | 71 | $Guid = [guid]::NewGuid() 72 | foreach ($Issuer in $Issuers) 73 | { 74 | $NameCopy = $Issuer.Name 75 | $NewIssuerName = $Guid 76 | $IssuerCertificate = $Issuer.SigningCertificate 77 | $OldRegisteredIssuerID = $Issuer.RegisteredIssuerName 78 | $IssuerID = $OldRegisteredIssuerID.Split('@')[0] 79 | $NewRegisteredIssuerName = $IssuerID + '@' + $NewRealm 80 | 81 | $NewIssuer = New-SPTrustedSecurityTokenIssuer -Name $NewIssuerName -Certificate $IssuerCertificate -RegisteredIssuerName $NewRegisteredIssuerName -IsTrustBroker 82 | Remove-SPTrustedSecurityTokenIssuer $Issuer -Confirm:$false 83 | $NewIssuer.Name = $NameCopy 84 | $NewIssuer.Update() 85 | } 86 | } 87 | Catch{ 88 | Write-Output "" 89 | Write-Error "Failed to update SharePoint Trusted Security Token Issuer for $NewIssuerName. Investigate and correct before re-running the script else PHAs depending on this Issuer will fail" 90 | } 91 | } 92 | } 93 | 94 |   95 | function Repair-AppPermissions{ 96 | 97 | $AppCount = $AppsforRemediation.count 98 | 99 | for ($i = 0; $i -lt $AppCount; $i++) 100 | { 101 | 102 | $appTitle = $AppsforRemediation[$i][0] 103 | $clientID = $AppsforRemediation[$i][1] 104 | $targetWeb = Get-SPWeb $AppsforRemediation[$i][2] 105 | $appweb = $targetWeb.Url 106 | $Scope = 'Site' 107 | $Right = 'FullControl' 108 | $authRealm = Get-SPAuthenticationRealm -ServiceContext $targetWeb.Site 109 | $AppIdentifier = $clientID + '@' + $authRealm 110 | Write-Output "" 111 | Write-Output "Repairing Permissions for $appTitle on site $appweb" 112 | 113 | $regprincipal = Register-SPAppPrincipal -NameIdentifier $AppIdentifier -Site $targetWeb -DisplayName $appTitle 114 | $appPrincipal = Get-SPAppPrincipal -Site $targetWeb -NameIdentifier $AppIdentifier 115 | Set-SPAppPrincipalPermission -Site $targetWeb -AppPrincipal $appPrincipal -Scope $Scope -Right $Right 116 | 117 | } 118 | 119 | } 120 | 121 |   122 |   123 | Find-AppInstances 124 | 125 | if($AppsforRemediation.Count -gt 0){ 126 | 127 | Write-Output "" 128 | Write-Output "Provider Hosted App Instances Discovered: $AppCount Total PHAs" 129 | 130 | 131 | Write-Output "" 132 | Write-Output "Repairing the SPAuthenticationrealmID" 133 | 134 | Repair-TrustedSecurityTokenIssuer 135 | 136 | Write-Output "" 137 | Write-Output "Repairing the Individual App Permissions" 138 | 139 | Repair-AppPermissions 140 | 141 | } 142 | else 143 | { 144 | Write-Output "" 145 | Write-Output "There are no remediation actions required on this farm" 146 | } 147 | 148 | -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.CloudSSA.Configuration/readme.md: -------------------------------------------------------------------------------- 1 | # Cloud Search Service Application and Supporting Scripts for Deployment and Configuration # 2 | 3 | ## Summary ## 4 | This section of the PnP tools repository contains a series of scripts to help deploy and configure hybrid scenarios for SharePoint and Office 365 SharePoint Online. The following scripts are available 5 | 6 | ### CreateHybridCloudSSA.ps1 ### 7 | 8 | This script is designed for configuring a SharePoint Server farm with a hybrid Cloud Search Service Application 9 | 10 | It requires the following variables: 11 | 12 | *SearchApplicationPoolAccountName - this is the account for the search app pool. If there is an existing local SSA that same account can be reused. Note that this account must be a managed SharePoint service account. 13 | 14 | *DatabaseServer - this is the name of an existing SharePoint database server. 15 | 16 | *SearchServer1 - this is the name of the first new server for Hybrid Search services. This server must already be added to the farm and should not host any SharePoint roles other than what was created when the server was added. 17 | 18 | *SearchServer2 - this is the name of the second new server for Hybrid Search services. The presence of this server is optional if the customer does not have a highly available SharePoint farm. This server must already be added to the farm and should not host any SharePoint roles other than what was created when the server was added. 19 | 20 | The authors recommend that two servers be used to ensure high availability of the service application. 21 | 22 | 23 | #### Applies to #### 24 | - SharePoint 2016 on-premises 25 | - SharePoint 2013 on-premises 26 | 27 | #### Prerequisites #### 28 | Any special pre-requisites? 29 | 30 | #### Solution #### 31 | Solution | Author(s) 32 | ---------|---------- 33 | Hybrid Cloud Search Service Application Configuration Wizard | Neil Hodgkinson (Microsoft), Marcus Tiongson (Microsoft), Manas Biswas (Microsoft) 34 | 35 | #### Version history #### 36 | Version | Date | Comments 37 | ---------| -----| -------- 38 | 1.0 | October 3rd 2016 | Initial release 39 | 40 | 41 | ### SpHybridValidation.ps1 ### 42 | 43 | This script take a single input of the global admin credentials and validates the local farm hybrid connection to the tenant. 44 | 45 | #### Applies to #### 46 | - SharePoint 2016 on-premises 47 | - SharePoint 2013 on-premises 48 | 49 | #### Prerequisites #### 50 | Any special pre-requisites? 51 | 52 | #### Solution #### 53 | Solution | Author(s) 54 | ---------|---------- 55 | Sp Hybrid Configuration Validation | Neil Hodgkinson (Microsoft), Manas Biswas (Microsoft) 56 | 57 | #### Version history #### 58 | Version | Date | Comments 59 | ---------| -----| -------- 60 | 1.0 | October 3rd 2016 | Initial release 61 | 62 | 63 | ### DetectWorkflowConnection.ps1 ### 64 | 65 | This script requires no inputs and simply detects the presence of a WorkFlow Manager Connection on the local farm. 66 | 67 | #### Applies to #### 68 | - SharePoint 2016 on-premises 69 | - SharePoint 2013 on-premises 70 | 71 | #### Prerequisites #### 72 | Any special pre-requisites? 73 | 74 | #### Solution #### 75 | Solution | Author(s) 76 | ---------|---------- 77 | Provider Hosted Add Ins Detection | Neil Hodgkinson (Microsoft) 78 | 79 | #### Version history #### 80 | Version | Date | Comments 81 | ---------| -----| -------- 82 | 1.0 | October 3rd 2016 | Initial release 83 | 84 | 85 | ### DetectProviderHostedAddIns.ps1 ### 86 | 87 | This script requires no inputs and simply detects the presence of Provider Hosted Addins on the local farm, reporting back the AddIn name and the web url of each instance deployed to the farm. It then repairs the TrustedSecurityTokenIssuer registration in the farm and regenerates the App Principals and permission for each app instance. 88 | 89 | #### Applies to #### 90 | - SharePoint 2016 on-premises 91 | - SharePoint 2013 on-premises 92 | 93 | #### Prerequisites #### 94 | Any special pre-requisites? 95 | 96 | #### Solution #### 97 | Solution | Author(s) 98 | ---------|---------- 99 | Provider Hosted Add Ins Detection | Neil Hodgkinson (Microsoft) 100 | 101 | #### Version history #### 102 | Version | Date | Comments 103 | ---------| -----| -------- 104 | 1.0 | October 3rd 2016 | Initial release 105 | 106 | 107 | 108 | 109 | ### AuthenticationRealmFixUp.ps1 ### 110 | 111 | This script requires no inputs and simply detects the presence of Provider Hosted Addins on the local farm, reporting back the AddIn name and the web url of each instance deployed to the farm. 112 | 113 | #### Applies to #### 114 | - SharePoint 2016 on-premises 115 | - SharePoint 2013 on-premises 116 | 117 | #### Prerequisites #### 118 | Any special pre-requisites? 119 | 120 | #### Solution #### 121 | Solution | Author(s) 122 | ---------|---------- 123 | Provider Hosted Add Ins Detection | Neil Hodgkinson (Microsoft) 124 | 125 | #### Version history #### 126 | Version | Date | Comments 127 | ---------| -----| -------- 128 | 1.0 | October 3rd 2016 | Initial release 129 | 130 | 131 | ### WorkFlowManagerFixUp.ps1 ### 132 | 133 | This script requires no inputs and simply regenerates the WorkFlow Manager Connection on the local farm. 134 | 135 | #### Applies to #### 136 | - SharePoint 2016 on-premises 137 | - SharePoint 2013 on-premises 138 | 139 | #### Prerequisites #### 140 | Any special pre-requisites? 141 | 142 | #### Solution #### 143 | Solution | Author(s) 144 | ---------|---------- 145 | Provider Hosted Add Ins Detection | Neil Hodgkinson (Microsoft) 146 | 147 | #### Version history #### 148 | Version | Date | Comments 149 | ---------| -----| -------- 150 | 1.0 | October 3rd 2016 | Initial release 151 | 152 | 153 | 154 | 155 | ### Disclaimer ### 156 | **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.** 157 | ---------- 158 | 159 | ### For detailed description of scenarios and steps, please refer to following documentation in the repository. 160 | 161 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidance 2 | 3 | If you'd like to contribute to this repository, please read the following guidelines. Contributors are more than welcome to share your learnings with others from centralized location. 4 | 5 | ## Code of Conduct 6 | 7 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 8 | For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 9 | 10 | ## Question or Problem? 11 | 12 | Please do not open GitHub issues for general support questions as the GitHub list should be used for script requests and bug reports. This way we can more easily track actual issues or bugs from the scripts and keep the general discussion separate from the actual script samples. 13 | 14 | ## Typos, Issues, Bugs and contributions 15 | 16 | Whenever you are submitting any changes to the SharePoint repositories, please follow these recommendations. 17 | 18 | * Always fork repository to your own account for applying modifications 19 | * Do not combine multiple changes to one pull request, please submit for example any samples and documentation updates using separate PRs 20 | * If you are submitting multiple samples, please create specific PR for each of them 21 | * If you are submitting typo or documentation fix, you can combine modifications to single PR where suitable 22 | 23 | ## Sample Naming and Structure Guidelines 24 | 25 | When you are submitting a new sample, it has to follow up below guidelines 26 | 27 | * You will need to have a README file for your contribution, which is based on [provided template](../samples/README-template.md) under the scripts folder. Please copy this template and update accordingly. README has to be named as README.md with capital letters. 28 | * Please include as much as possible information on the exact use case of your script. More information will help on others to understand the value of your script. You can add links and images as needed. 29 | 30 | * README template contains specific tracking image as a final entry in the page with img tag by default to https://telemetry.sharepointpnp.com/sp-admin-scripts/scripts/readme-template. This is transparent image, which is used to track popularity of individual samples in GitHub. 31 | 32 | * Updated the image src element according with repository name and folder information. If your sample is for example in samples folder and named as known-folder-move, src element should be updated as https://telemetry.sharepointpnp.com/sp-admin-scripts/script/known-folder-move 33 | 34 | * When you are submitting a new script, please name the sample solution folder accordingly 35 | * Do not use words "sample", "script" or "SharePoint" in the folder or sample name - these are scripts for SharePoint management, so no reason to repeat that in the name 36 | 37 | * Do not use period/dot in the folder name of the provided sample 38 | 39 | ## Submitting Pull Requests 40 | 41 | Here's a high level process for submitting new samples or updates to existing ones. 42 | 43 | 1. Sign the Contributor License Agreement (see below) 44 | 1. Fork this repository [SharePoint/sp-admin-scripts](https://github.com/SharePoint/sp-admin-scripts) to your GitHub account 45 | 1. Create a new branch off the `master` branch for your fork for the contribution 46 | 1. Include your changes to your branch 47 | 1. Commit your changes using descriptive commit message * These are used to track changes on the repositories for monthly communications 48 | 1. Create a pull request in your own fork and target `master` branch 49 | 1. Fill up the provided PR template with the requested details 50 | 51 | Before you submit your pull request consider the following guidelines: 52 | 53 | * Make sure you have a link in your local cloned fork to the [SharePoint/sp-admin-scripts](https://github.com/SharePoint/sp-admin-scripts): 54 | 55 | ```shell 56 | # check if you have a remote pointing to the Microsoft repo: 57 | git remote -v 58 | 59 | # if you see a pair of remotes (fetch & pull) that point to https://github.com/SharePoint/sp-admin-scripts, you're ok... otherwise you need to add one 60 | 61 | # add a new remote named "upstream" and point to the Microsoft repo 62 | git remote add upstream https://github.com/SharePoint/sp-admin-scripts.git 63 | ``` 64 | 65 | * Make your changes in a new git branch: 66 | 67 | ```shell 68 | git checkout -b my-awesome-script-name master 69 | ``` 70 | 71 | * Ensure your fork is updated and not behind the upstream **sp-admin-scripts** repo. Refer to these resources for more information on syncing your repo: 72 | * [GitHub Help: Syncing a Fork](https://help.github.com/articles/syncing-a-fork/) 73 | * [Keep Your Forked Git Repo Updated with Changes from the Original Upstream Repo](http://www.andrewconnell.com/blog/keep-your-forked-git-repo-updated-with-changes-from-the-original-upstream-repo) 74 | * For a quick cheat sheet: 75 | 76 | ```shell 77 | # assuming you are in the folder of your locally cloned fork.... 78 | git checkout master 79 | 80 | # assuming you have a remote named `upstream` pointing official **sp-admin-scripts** repo 81 | git fetch upstream 82 | 83 | # update your local master to be a mirror of what's in the main repo 84 | git pull --rebase upstream master 85 | 86 | # switch to your branch where you are working, say "my-awesome-script-name" 87 | git checkout my-awesome-script-name 88 | 89 | # update your branch to update it's fork point to the current tip of master & put your changes on top of it 90 | git rebase master 91 | ``` 92 | 93 | * Push your branch to GitHub: 94 | 95 | ```shell 96 | git push origin my-awesome-script-name 97 | ``` 98 | 99 | ## Merging your Existing Github Projects with this Repository 100 | 101 | If the sample you wish to contribute is stored in your own Github repository, you can use the following steps to merge it with the this repository: 102 | 103 | * Fork the `sp-admin-scripts` repository from GitHub 104 | * Create a local git repository 105 | 106 | ```shell 107 | md sp-admin-scripts 108 | cd sp-admin-scripts 109 | git init 110 | ``` 111 | 112 | * Pull your forked copy of sp-admin-scripts into your local repository 113 | 114 | ```shell 115 | git remote add origin https://github.com/yourgitaccount/sp-admin-scripts.git 116 | git pull origin dev 117 | ``` 118 | 119 | * Pull your other project from github into the scripts folder of your local copy of sp-admin-scripts 120 | 121 | ```shell 122 | git subtree add --prefix=scripts/projectname https://github.com/yourgitaccount/projectname.git master 123 | ``` 124 | 125 | * Push the changes up to your forked repository 126 | 127 | ```shell 128 | git push origin master 129 | ``` 130 | 131 | ## Signing the CLA 132 | 133 | Before we can accept your pull requests you will be asked to sign electronically Contributor License Agreement (CLA), which is prerequisite for any contributions to PnP repository. This will be one time process, so for any future contributions you will not be asked to re-sign anything. After the CLA has been signed, our PnP core team members will have a look on your submission for final verification of the submission. Please do not delete your development branch until the submission has been closed. 134 | 135 | You can find Microsoft CLA from the following address - https://cla.microsoft.com. 136 | 137 | Thank you for your contribution. 138 | 139 | > Sharing is caring. -------------------------------------------------------------------------------- /Scripts/SharePoint.LowTrustACS.Configuration/Connect-SPFarmToAAD.psm1: -------------------------------------------------------------------------------- 1 | function Connect-SPFarmToAAD 2 | { 3 | param( 4 | [Parameter(Mandatory)][String] $AADDomain, 5 | [Parameter(Mandatory)][String] $SharePointOnlineUrl, 6 | #Specify this parameter if you don't want to use the default SPWeb returned 7 | [Parameter()][String] $SharePointWeb, 8 | [Parameter()][System.Management.Automation.PSCredential] $O365Credentials, 9 | #Use these switches if you're replacing an existing connection to AAD. 10 | [Parameter()][Switch] $RemoveExistingACS, 11 | [Parameter()][Switch] $RemoveExistingSTS, 12 | [Parameter()][Switch] $RemoveExistingSPOProxy, 13 | #Use this switch if you're replacing the Office 365 SharePoint site. 14 | [Parameter()][Switch] $RemoveExistingAADCredentials, 15 | #Use this switch if you don't want to use SSL when you launch your app. 16 | [Parameter()][Switch] $AllowOverHttp 17 | ) 18 | #Prompt for credentials right away. 19 | if (-not $O365Credentials) 20 | { 21 | $O365Credentials = Get-Credential -Message "Admin credentials for $AADDomain" 22 | } 23 | 24 | Add-PSSnapin Microsoft.SharePoint.PowerShell 25 | #Import the Microsoft Online Services Sign-In Assistant. 26 | Import-Module -Name MSOnline 27 | #Import the Microsoft Online Services Module for Windows Powershell. 28 | Import-Module MSOnlineExtended �force -verbose 29 | #Set values for Constants. 30 | New-Variable -Option Constant -Name SP_APPPRINCIPALID -Value '00000003-0000-0ff1-ce00-000000000000' | Out-Null 31 | New-Variable -Option Constant -Name ACS_APPPRINCIPALID -Value '00000001-0000-0000-c000-000000000000' | Out-Null 32 | New-Variable -Option Constant -Name ACS_APPPROXY_NAME -Value ACS 33 | New-Variable -Option Constant -Name SPO_MANAGEMENT_APPPROXY_NAME -Value 'SPO Add-in Management Proxy' 34 | New-Variable -Option Constant -Name ACS_STS_NAME -Value ACS-STS 35 | 36 | # Use following values for AAD_METADATAEP_FSTRING depending on the environment where your Office 365 tenant is hosted 37 | # Default: https://accounts.accesscontrol.windows.net/{0}/metadata/json/1 38 | # Germany: https://login.microsoftonline.de/{0}/metadata/json/1 39 | # China: https://accounts.accesscontrol.chinacloudapi.cn/{0}/metadata/json/1 40 | 41 | New-Variable -Option Constant -Name AAD_METADATAEP_FSTRING -Value 'https://accounts.accesscontrol.windows.net/{0}/metadata/json/1' 42 | New-Variable -Option Constant -Name SP_METADATAEP_FSTRING -Value '{0}/_layouts/15/metadata/json/1' 43 | #Get the default SPWeb from the on-premises farm if no $SharePointWeb parameter is specified. 44 | if ([String]::IsNullOrEmpty($SharePointWeb)) 45 | { 46 | $SharePointWeb = Get-SPSite | Select-Object -First 1 | Get-SPWeb | Select-Object -First 1 | % Url 47 | } 48 | 49 | #Configure the realm ID for local farm so that it matches the AAD realm. 50 | $ACSMetadataEndpoint = $AAD_METADATAEP_FSTRING -f $AADDomain 51 | $ACSMetadata = Invoke-RestMethod -Uri $ACSMetadataEndpoint 52 | $AADRealmId = $ACSMetadata.realm 53 | 54 | Set-SPAuthenticationRealm -ServiceContext $SharePointWeb -Realm $AADRealmId 55 | 56 | $LocalSTS = Get-SPSecurityTokenServiceConfig 57 | $LocalSTS.NameIdentifier = '{0}@{1}' -f $SP_APPPRINCIPALID,$AADRealmId 58 | $LocalSTS.Update() 59 | 60 | #Allow connections over HTTP if the switch is specified. 61 | if ($AllowOverHttp.IsPresent -and $AllowOverHttp -eq $True) 62 | { 63 | $serviceConfig = Get-SPSecurityTokenServiceConfig 64 | $serviceConfig.AllowOAuthOverHttp = $true 65 | $serviceConfig.AllowMetadataOverHttp = $true 66 | $serviceConfig.Update() 67 | } 68 | 69 | #Step 1: Set up the ACS proxy in the on-premises SharePoint farm. Remove the existing ACS proxy 70 | #if the switch is specified. 71 | if ($RemoveExistingACS.IsPresent -and $RemoveExistingACS -eq $True) 72 | { 73 | Get-SPServiceApplicationProxy | ? DisplayName -EQ $ACS_APPPROXY_NAME | Remove-SPServiceApplicationProxy -RemoveData -Confirm:$false 74 | } 75 | if (-not (Get-SPServiceApplicationProxy | ? DisplayName -EQ $ACS_APPPROXY_NAME)) 76 | { 77 | $AzureACSProxy = New-SPAzureAccessControlServiceApplicationProxy -Name $ACS_APPPROXY_NAME -MetadataServiceEndpointUri $ACSMetadataEndpoint -DefaultProxyGroup 78 | } 79 | 80 | #Remove the existing security token service if the switch is specified. 81 | if ($RemoveExistingSTS.IsPresent) 82 | { 83 | Get-SPTrustedSecurityTokenIssuer | ? Name -EQ $ACS_STS_NAME | Remove-SPTrustedSecurityTokenIssuer -Confirm:$false 84 | } 85 | if (-not (Get-SPTrustedSecurityTokenIssuer | ? DisplayName -EQ $ACS_STS_NAME)) 86 | { 87 | $AzureACSSTS = New-SPTrustedSecurityTokenIssuer -Name $ACS_STS_NAME -IsTrustBroker -MetadataEndPoint $ACSMetadataEndpoint 88 | } 89 | 90 | #Update the ACS Proxy for OAuth authentication. 91 | $ACSProxy = Get-SPServiceApplicationProxy | ? Name -EQ $ACS_APPPROXY_NAME 92 | $ACSProxy.DiscoveryConfiguration.SecurityTokenServiceName = $ACS_APPPRINCIPALID 93 | $ACSProxy.Update() 94 | 95 | #Retrieve the local STS signing key from JSON metadata. 96 | $SPMetadata = Invoke-RestMethod -Uri ($SP_METADATAEP_FSTRING -f $SharePointWeb) 97 | $SPSigningKey = $SPMetadata.keys | ? usage -EQ "Signing" | % keyValue 98 | $CertValue = $SPSigningKey.value 99 | 100 | #Connect to Office 365. 101 | Connect-MsolService -Credential $O365Credentials 102 | #Remove existing connection to an Office 365 SharePoint site if the switch is specified. 103 | if ($RemoveExistingAADCredentials.IsPresent -and $RemoveExistingAADCredentials -eq $true) 104 | { 105 | $msolserviceprincipal = Get-MsolServicePrincipal -AppPrincipalId $SP_APPPRINCIPALID 106 | [Guid[]] $ExistingKeyIds = Get-MsolServicePrincipalCredential -ObjectId $msolserviceprincipal.ObjectId -ReturnKeyValues $false | % {if ($_.Type -ne "Other") {$_.KeyId}} 107 | Remove-MsolServicePrincipalCredential -AppPrincipalId $SP_APPPRINCIPALID -KeyIds $ExistingKeyIds 108 | } 109 | #Step 2: Upload the local STS signing certificate 110 | New-MsolServicePrincipalCredential -AppPrincipalId $SP_APPPRINCIPALID -Type Asymmetric -Value $CertValue -Usage Verify 111 | 112 | #Step 3: Add the service principal name of the local web application, if necessary. 113 | $indexHostName = $SharePointWeb.IndexOf('://') + 3 114 | $HostName = $SharePointWeb.Substring($indexHostName) 115 | $NewSPN = '{0}/{1}' -f $SP_APPPRINCIPALID, $HostName 116 | $SPAppPrincipal = Get-MsolServicePrincipal -AppPrincipalId $SP_APPPRINCIPALID 117 | if ($SPAppPrincipal.ServicePrincipalNames -notcontains $NewSPN) 118 | { 119 | $SPAppPrincipal.ServicePrincipalNames.Add($NewSPN) 120 | Set-MsolServicePrincipal -AppPrincipalId $SPAppPrincipal.AppPrincipalId -ServicePrincipalNames $SPAppPrincipal.ServicePrincipalNames 121 | } 122 | 123 | #Remove the existing SharePoint Online proxy if the switch is specified. 124 | if ($RemoveExistingSPOProxy.IsPresent -and $RemoveExistingSPOProxy -eq $True) 125 | { 126 | Get-SPServiceApplicationProxy | ? DisplayName -EQ $SPO_MANAGEMENT_APPPROXY_NAME | Remove-SPServiceApplicationProxy -RemoveData -Confirm:$false 127 | } 128 | #Step 4: Add the SharePoint Online proxy 129 | if (-not (Get-SPServiceApplicationProxy | ? DisplayName -EQ $SPO_MANAGEMENT_APPPROXY_NAME)) 130 | { 131 | $spoproxy = New-SPOnlineApplicationPrincipalManagementServiceApplicationProxy -Name $SPO_MANAGEMENT_APPPROXY_NAME -OnlineTenantUri $SharePointOnlineUrl -DefaultProxyGroup 132 | } 133 | } -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.CloudSSA.Configuration/SPHybridValidation.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .synopsis 3 | Script does several checks on the farm and Office 365 if a hybrid connection can be setup 4 | .description 5 | This script needs to be ran on a SharePoint server that has access to internet 6 | .example 7 | .\SPHybridValidation.ps1 8 | #> 9 | 10 | if ((Get-PSSnapin -Name "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) 11 | { 12 | Add-PSSnapin -Name "Microsoft.SharePoint.PowerShell" 13 | } 14 | cls 15 | 16 | #Connect to the O365 Tenant 17 | Write-Host "Please Conenct to the Microsoft Online tenant you wish to validate this on premises farm with" -ForegroundColor Yellow 18 | Connect-MsolService 19 | 20 | #Validate Certificate is not expired - checks all Msol Principals not just current farm 21 | Write-Host "Validating MSOL Principals still within valid date range" -ForegroundColor Yellow 22 | Write-Host 23 | Write-Host "Collecting All MSOL Principals" -ForegroundColor Yellow 24 | $MsolSPC = Get-MsolServicePrincipalCredential -AppPrincipalId "00000003-0000-0ff1-ce00-000000000000" -ReturnKeyValues:$false|ft startdate,enddate ,keyid -autosize 25 | Write-Host 26 | # Validate that the local STS Signing Certificate matches a valid Microsoft Online Service Principal 27 | Write-Host "Validating that the local STS Signing Certificate matches a valid Microsoft Online Service Principal" -ForegroundColor Yellow 28 | 29 | $StsThumbprint = (Get-SPSecurityTokenServiceConfig).LocalLoginProvider.SigningCertificate.thumbprint 30 | #Changed to /sharepoint 31 | $StsCertificate = get-item -Path CERT:\localmachine\SharePoint\$StsThumbprint 32 | $StsCertificateBin = $StsCertificate.GetRawCertData() 33 | $StsCredentialValue = [System.Convert]::ToBase64String($StsCertificateBin) 34 | $MsolServicePrincipalCredential = Get-MsolServicePrincipalCredential -AppPrincipalId "00000003-0000-0ff1-ce00-000000000000" -ReturnKeyValues $true | Where-Object {$_.Value -eq $StsCredentialValue} 35 | 36 | if($MsolServicePrincipalCredential) 37 | { 38 | # Check for valid date 39 | if($MsolServicePrincipalCredential.EndDate -gt (get-date) -and $MsolServicePrincipalCredential.StartDate -lt (get-date)) 40 | { 41 | Write-Host 42 | write-host "Msol Service Principal is found and is Valid until :"$MsolServicePrincipalCredential.EndDate -ForegroundColor Green 43 | } 44 | Else 45 | { 46 | Write-Host 47 | write-host "Msol Service Principal is found but expired on " + $MsolServicePrincipalCredential.EndDate + " You should update the ACS trust certificates for hybrid workloads to function" -ForegroundColor Yellow 48 | } 49 | } 50 | else 51 | { 52 | Write-Host 53 | Write-host "No matching Msol Service Principal found for the local farm. Hybrid workloads will not function correctly on this farm" -foregroundcolor Red 54 | } 55 | 56 | #Validate SPNs setup properly in WAAD 57 | Write-Host 58 | Write-Host "Validating that the Microsoft online Service Principal Names are correct" -ForegroundColor Yellow 59 | 60 | $apps = (Get-MsolServicePrincipal -AppPrincipalId "00000003-0000-0ff1-ce00-000000000000").serviceprincipalnames 61 | 62 | $webapps = Get-SPWebApplication 63 | $foundmatch = $false 64 | Foreach($WebApp in $WebApps) 65 | { 66 | $webappurl = (($WebApp.url).split(":")).split("//") 67 | 68 | Foreach($app in $apps) 69 | { 70 | $spn = ((($app).split("/")) -replace "\*.", "") 71 | 72 | if(($webappurl[3] -match $spn[1]) -and ($spn[1] -ne $null )) 73 | { 74 | Write-Host 75 | write-host "It seems the local farm has a matching SPN and URL combination " $webappurl[3] " matched with " $spn[1] " on this farm" -ForegroundColor Green 76 | write-host "This is required for hybrid scenarios requiring outbound OAuthN" -ForegroundColor Green 77 | $foundmatch=$true 78 | } 79 | } 80 | } 81 | if($foundmatch = $false) 82 | { 83 | Write-Host 84 | write-host "No matching SPN and URL combinations found on this farm" -ForegroundColor Red 85 | } 86 | 87 | # Validate Directory Synchronization 88 | Write-Host "Checking Directory Synchronization is Operational" -ForegroundColor Yellow 89 | $msolcompany = Get-MsolCompanyInformation 90 | $IsDirSyncEnabled = $msolcompany.DirectorySynchronizationEnabled 91 | 92 | Write-Host "Directory Sync Enabled Status" $IsDirSyncEnabled -ForegroundColor Green 93 | Write-Host 94 | 95 | $LastDirsynctime = $msolcompany.LastDirSyncTime 96 | Write-Host "Last Directory Sync Time" $LastDirsynctime -ForegroundColor Green 97 | Write-Host 98 | 99 | Write-Host "Checking license state of users" -ForegroundColor Yellow 100 | $licensed = Get-MsolUser | where-object {$_.IsLicensed -eq $true} 101 | $unlicensed = get-msoluser -UnlicensedUsersOnly 102 | $licenses = (MSOnline\Get-MsolSubscription).TotalLicenses 103 | 104 | Write-Host "Total number of licensed users is " $licensed.count -ForegroundColor Green 105 | Write-Host "Total number of unlicensed users is " $unlicensed.count -ForegroundColor Green 106 | Write-Host "Total number of purchased licenses is " $licenses -ForegroundColor Green 107 | Write-Host 108 | 109 | #Validate Service Applications 110 | Write-Host "Checking On Premises Services" -ForegroundColor Yellow 111 | $upa=Get-SPServiceApplication | where-object {$_.TypeName -match "User profile Service Application"} 112 | if ($upa -ne $null -and $upa.Status -eq "online") 113 | { 114 | Write-Host ("User Profile Service Application is available with status ") $upa.status -ForegroundColor Green 115 | } 116 | elseif ($upa -ne $null -and $upa.Status -ne "online") 117 | { 118 | Write-Host ("User Profile Service Application is availble but status is ") $upa.status -ForegroundColor Red 119 | } 120 | else 121 | { 122 | Write-Host ("User Profile Service Application is not available. ") $upa.status -ForegroundColor Red 123 | } 124 | Write-Host 125 | $app=Get-SPServiceApplication | where-object {$_.TypeName -match "App Management Service Application"} 126 | 127 | if ($app -ne $null -and $app.Status -eq "online") 128 | { 129 | Write-Host ("App Management Service Application is available with status ") $app.status -ForegroundColor Green 130 | } 131 | elseif ($app -ne $null -and $app.Status -ne "online") 132 | { 133 | Write-Host ("App Management Service Application is available but status is ") $app.status -ForegroundColor Red 134 | } 135 | else 136 | { 137 | Write-Host ("App Management Service Application is not available. ") $app.status -ForegroundColor Red 138 | } 139 | Write-Host 140 | Write-Host "Checking On Proxies" -ForegroundColor Yellow 141 | 142 | #Validate ACS Proxy 143 | 144 | $proxy =Get-SPServiceApplicationProxy | ? {$_.TypeName -eq "Azure Access Control Service Application Proxy"} 145 | if ($proxy -ne $null -and $proxy.Status -eq "online") 146 | { 147 | Write-Host ("ACS proxy is available with status ") $proxy.status -ForegroundColor Green 148 | } 149 | elseif ($proxy -ne $null -and $proxy.Status -ne "online") 150 | { 151 | Write-Host ("ACS proxy is available but status is ") $proxy.status -ForegroundColor Red 152 | } 153 | else 154 | { 155 | Write-Host ("ACS proxy is not available. ") -ForegroundColor Red 156 | } 157 | 158 | Write-Host 159 | # Validate SPO proxy 160 | $spoProxy = Get-SPServiceApplicationProxy | ? {$_.TypeName -eq "SharePoint Online Application Principal Management Service Application Proxy"} 161 | if ($spoproxy -ne $null -and $spoproxy.Status -eq "online") 162 | { 163 | Write-Host ("SPO proxy is available with status ") $spoProxy.status -ForegroundColor Green 164 | } 165 | elseif ($spoproxy -ne $null -and $spoproxy.Status -ne "online") 166 | { 167 | Write-Host ("SPO proxy is available but status is ") $spoProxy.status -ForegroundColor Red 168 | } 169 | else 170 | { 171 | Write-Host ("SPO proxy is not available. ") -ForegroundColor Red 172 | } -------------------------------------------------------------------------------- /Scripts/SharePoint.Sandbox.ListSolutionsFromTenant/README.MD: -------------------------------------------------------------------------------- 1 | # Sandbox solutions inventory script for SharePoint Online # 2 | This script can be used to analyze what kind of sandbox solutions exists in specific SharePoint Online tenant. You will need to use tenant administrator account to connect to SharePoint Online and script will generate a list of sandbox solutions to separate txt file, which can be imported to Excel for further analyses. 3 | 4 | >**Note**: This script is relatively simple and does not use multi-threading, so execution in larger tenants might take a while. We are looking for further enhancing the script with multi-threading support, if there's demand for this. Also community contributions on this side are more than welcome. 5 | 6 | Output file has following columns 7 | * URL of the site collection 8 | * Name of the sandbox solution 9 | * Author field from the sandbox solution - who uploaded the file. If value contains a comma, it will be removed in output 10 | * Created field from the sandbox solution - when solution was uploaded 11 | * Status field - 1=Activated, 0=Not activated 12 | * HasAssemblies field - 1=solution has assemblies , 0=solution does not have assemblies 13 | * SolutionHash field - hash of the solution. If solution is exactly the same cross site collections, has is the same. If solution has small adjustments or it's different version regardless of the wsp name matching, it's a different solution 14 | 15 | Example output file, which can be easily imported to Excel for further analyses 16 | ```PowerShell 17 | SiteURL,WSPName,Author,CreatedDate,Activated,HasAssemblies,SolutionHash 18 | https://contoso.sharepoint.com/sites/635993483643159661,MyCoolWebPart.wsp,Vesa Juvonen,07/27/2016 00:55:22,0,1,IEYyOmzpYRAWRTLIuh0VbtUQFNJEsNxP6vVbECvVIY0= 19 | https://contoso.sharepoint.com/sites/devpub,PnPRocks.wsp,System Account,07/27/2016 01:03:36,0,1,4KmaeOO1r7vw8/MDBuEmBzKMUtXxYhvc42vv/mw+Nnw= 20 | https://contoso.sharepoint.com/sites/team,WhosReadingThese.wsp,Vesa Juvonen,06/07/2016 12:58:05,1,0,l8oO15G6LKX61wbTHZCCGyzNxZhYC3bbz5F+KsMbWYU= 21 | https://contoso.sharepoint.com/sites/team,HiMom.wsp,Vesa Juvonen,06/22/2016 12:41:04,1,1,cdLgVhgD3uZCuoSl0VF/wBBF903ldJQJAG7sZWcAojw= 22 | https://contoso.sharepoint.com/sites/team,WhatsUp.wsp,Vesa Juvonen,07/27/2016 00:47:54,0,0,tRB8KTZc6VTzJ6rGqtYCeFMozMroeIksQO2Bg0RJzcw= 23 | https://contoso.sharepoint.com/sites/team,MrVanRules.wsp,Vesa Juvonen,07/29/2016 22:26:43,1,1,a48UeIRwd8HTReQ+UNnvH9w3NIKu2u4hYXK412riFgg= 24 | https://contoso.sharepoint.com/sites/templatesite,RememberIgniteOnSeptember.wsp,Vesa Juvonen,07/27/2016 00:50:50,0,1,DsZBtAYAHjfNtHL8qytqI3//VwzSL3kR7rgkOG03Hl0= 25 | https://contoso.sharepoint.com/sites/templatesite,WhatsUp.wsp,Vesa Juvonen,07/27/2016 00:56:32,1,0,MZ8BAIfCKdDhUx2rzQi9TlhVZ1lBn6f1F4/7+q0WekE= 26 | https://contoso.sharepoint.com/sites/visiodemos,UsefullForYouGiveFeedback.wsp,Provisioning User 0,03/24/2014 21:44:25,1,0,xoCOeSDyhnYAY6nkXNpDpCL0A5TbLUTU4qX0q25ZFgE= 27 | 28 | ``` 29 | 30 | **What will be reported?** 31 | Scripts reports all sandbox solution from solution gallery regardless if they contain code behind or regardless how they were created. Here's different kind of sandbox solutions, which you can have in the report. 32 | * Site templates 33 | * Design Manager Packages 34 | * InfoPath Forms with code behind 35 | * Custom solutions created with Visual Studio (web parts, web templates, event receivers) 36 | 37 | 38 | >**Note**: This is an **Open Source** project, and any contribution from the community 39 | is more than welcome. Feel free to review the code and submit any [Issues](https://github.com/OfficeDev/PnP-Tools/issues) or [Pull Requests](https://github.com/OfficeDev/PnP-Tools/pulls), using GitHub. If you want to assist the community on this journey around sandbox solutions, we are looking for example improvements on identifying sandbox solution type, code behind existence or to add multi-threading support. 40 | 41 | # Setup Instructions # 42 | In order to get list of sandbox solutions using this script, you'll need to: 43 | * [Download the files included in this solution](#download) 44 | * [Setup software requirements](#requirements) 45 | * [Execute the *Get-SPOnlineSandboxSolutionList* cmdlet](#execute) 46 | 47 | 48 | ## Download the files 49 | You can download the script file manually or you can download 50 | a ZIP file with all the content from PnP-Tools repository, simply following 51 | this link. 52 | Within the ZIP file, under the /Scripts/SharePoint.Sandbox.ListSolutionsFromTenant folder, you will 53 | find all the required files. 54 | 55 | 56 | ## Setup software requirements 57 | This scripts requires SharePoint Online PowerShell commands, which you can install 58 | from the following link: 59 | 60 | * [SharePoint PowerShell commands](https://www.microsoft.com/en-us/download/details.aspx?id=35588) 61 | 62 | 63 | ## Execute the *Get-SPOnlineSandboxSolutionList* cmdlet 64 | Once you have installed the SharePoint PowerShell commands, you can simply open a 65 | PowerShell console, go to the path where you stored the files and execute the *Get-SPOnlineSandboxSolutionList* 66 | cmdlet, which is included in the 67 | Get-SPOnlineSandboxSolutionList.ps1 script file of this solution. 68 | 69 | The *Get-SPOnlineSandboxSolutionList* cmdlet accepts the following three parameters: 70 | * **AdminUrl**: it is a mandatory parameter, which declares the URL of the admin site for the tenant where the sandbox solution scan will be performed. It has to be provided as a full URL, like for example: https://contoso-admin.sharepoint.com 71 | * **Credentials**: it is an optional parameter, which defines the user credentials that will be used to authenticate against both the target Site Collection and the infrastructure Site Collection, if any. Should be the credentials of a user, who is Site Collection Administrator for the target Site Collections. If you don't provide this parameter, the script will directly prompt you for credentials. 72 | * **Delimiter**: it is an optional parameter, by default is ',' and can be used to specify a different separation character for CSV output. 73 | 74 | Here you can see a couple of examples about how to invoke the *Get-SPOnlineSandboxSolutionList.ps1* script: 75 | 76 | ###EXAMPLE 1 77 | ```PowerShell 78 | PS C:\> .\Get-SPOnlineSandboxSolutionList.ps1 -AdminUrl "https://contoso-admin.sharepoint.com" 79 | ``` 80 | 81 | The example above performs as sandbox solution scan in contoso tenant with admin URL https://contoso-admin.sharepoint.com. The user's credentials are not provided, so the cmdlet will directly prompt the user. 82 | 83 | ###EXAMPLE 2 84 | ```PowerShell 85 | PS C:\> .\Get-SPOnlineSandboxSolutionList.ps1 -AdminUrl "https://contoso-admin.sharepoint.com" -Delimiter ';' 86 | ``` 87 | 88 | This example above shows how to specify a custom character as delimiter for CSV output 89 | 90 | 91 | ###EXAMPLE 3 92 | ```PowerShell 93 | PS C:\> $creds = Get-Credential 94 | PS C:\> .\Get-SPOnlineSandboxSolutionList.ps1 -AdminUrl "https://contoso-admin.sharepoint.com" -Credentials $creds 95 | ``` 96 | 97 | The example above performs as sandbox solution scan in contoso tenant with admin URL https://contoso-admin.sharepoint.com. The user's credentials are provided through the *$creds* variable. 98 | 99 | 100 | -- 101 | 102 | ### Applies to ### 103 | - Office 365 Multi Tenant (MT) 104 | 105 | ### Prerequisites ### 106 | Following software installation packages have to be downloaded and installed on the machine where script will execute 107 | - [SharePoint Online Client Components SDK](https://www.microsoft.com/en-us/download/details.aspx?id=42038) 108 | - [SharePoint Online Management Shell](https://www.microsoft.com/en-us/download/details.aspx?id=35588) 109 | - [SharePoint PowerShell CmdLets](https://www.microsoft.com/en-us/download/details.aspx?id=35588) 110 | 111 | ### **Note** ### 112 | `You will need to use tenant administrator credentials to be able to list site collections from target tenant. 113 | This account must have as well access to all site collections, in order to be able to access their solutions gallery.` 114 | 115 | ### Script ### 116 | Script | Author(s) 117 | ---------|---------- 118 | SharePoint.Sandbox.ListSolutionsFromTenant | Karine Bosch (Microsoft), Vesa Juvonen (Microsoft), Daniel Budimir (Microsoft), Massimo Prota (Rapid Circle) 119 | 120 | ### Version history ### 121 | Version | Date | Comments 122 | ---------| -----| -------- 123 | 1.3 | August 9th 2016 | Added hash of the solution as output 124 | 1.2 | August 4th 2016 | Added possibility to specify CSV delimiter, headers to output, better ClientContext handling 125 | 1.1 | August 3rd 2016 | Added HasAssemblies to output 126 | 1.0 | August 3rd 2016 | Initial release 127 | 128 | ### Disclaimer ### 129 | **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.** 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /Scripts/SharePoint.LowTrustACS.Configuration/readme.md: -------------------------------------------------------------------------------- 1 | # PowerShell to enable low trust authentication model at on-premises # 2 | 3 | ### Summary ### 4 | 5 | This document and scripts explain how to setup low trust authentication between your SharePoint 2013/2016 on-premises farm and an Office 365 tenant. 6 | 7 | ### Applies to ### 8 | 9 | - SharePoint 2013 on-premises 10 | - SharePoint 2016 on-premises 11 | 12 | ### Prerequisites ### 13 | - [An Office 365 tenant which you'll use for the low trust association](https://msdn.microsoft.com/en-us/library/office/fp179924.aspx) 14 | - [Setup app management in your on-premises farm](https://msdn.microsoft.com/en-us/library/office/fp179923.aspx) 15 | 16 | ### Solution ### 17 | Solution | Author(s) 18 | ---------|---------- 19 | Enable low trust in on-premises | Vesa Juvonen, Bert Jansen (**Microsoft**) 20 | 21 | ### Version history ### 22 | Version | Date | Comments 23 | ---------| -----| -------- 24 | 1.0 | February 8th 2016 | Initial release 25 | 26 | ### Disclaimer ### 27 | **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.** 28 | 29 | 30 | ---------- 31 | 32 | # Introduction 33 | This document and scripts explain how to setup low trust authentication between your SharePoint 2013/2016 on-premises farm and an Office 365 tenant. Setting up low trust for your on-premises farms will allow you to use Azure ACS as OAuth broker for your on-premises environment and as such run your apps and client side applications in the same manner as you would do for SharePoint Online. 34 | 35 | The [detailed steps for this task are documented in MSDN](https://msdn.microsoft.com/en-us/library/office/dn155905.aspx), you can consider this document as a shortened and easier set of instructions. 36 | 37 | Below chapters describe the individual steps needed to make this happen 38 | 39 | ## Step 1: Obtain a new signing certificate for the on-premises SharePoint Token Service (STS) 40 | You’ll need to replace the default security token service (STS) certificate of your on-premises installation of SharePoint 2013/2016 with your own certificate. This section describes how to obtain this certificate by making use of [makecert.exe which is available as part of the Windows SDK](https://msdn.microsoft.com/library/windows/desktop/aa386968.aspx). If you do not want to use makecert.exe you can also use IIS Manager to create a certificate as described [here](https://msdn.microsoft.com/en-us/library/office/dn155905.aspx). 41 | 42 | Using `makecert.exe` allows you to choose a certificate with a longer lifetime which means less maintenance on your low trust setup. In below sample we create our own trusted root authority and then individual certs that have our trusted root authority as issuer. See [Mike O'Brien's blog](http://www.mikeobrien.net/blog/creating-self-signed-wildcard/) for more details. 43 | 44 | Import detail for the token signing certificate is that it **requires a key length of at least 2048** which is in below command provided via the **len** parameter. 45 | 46 | Navigate to folder **C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin** and execute the following commands: 47 | 48 | ```Cmd 49 | #creates the trusted root authority 50 | ./makecert.exe -n "CN=PnP Development Root CA,O=PnP,OU=Development,L=Bree,S=Limburg,C=Belgium" -pe -ss Root -sr LocalMachine -sky exchange -m 120 -a sha256 -len 2048 -r 51 | 52 | #creates the token signing cert 53 | ./makecert.exe -n "CN=STSTokenSigning" -pe -ss My -sr LocalMachine -sky exchange -m 120 -in "PnP Development Root CA" -is Root -ir LocalMachine -len 2048 -a sha256 -eku 1.3.6.1.5.5.7.3.1 54 | ``` 55 | 56 | **Note:** 57 | You can create these certificates an any machine that has `makecert.exe` available, no need to deploy the SDK to your SharePoint servers. 58 | 59 | Once you've created the token signing certificate you'll need to export it to a PFX file via the following steps: 60 | - Start `mmc.exe` 61 | - Load the **Certificates** snap-in for the **Computer Account** 62 | - Locate the created token signing certificate in the **Personal --> Certificates** node, right-click and choose the **Export** task 63 | - Choose to export the **private key** 64 | - The PFX option will be pre-selected, chech the "Include all certificates in the certification path if possible" and deselect the other options 65 | - Select the **Password** check box and provide a password 66 | - Provide a name and path for the PFX file (use .pfx extension) 67 | - Press **Finish** 68 | - Copy the created pfx file to your SharePoint 2013/2016 server or a share that you can reach from that server 69 | 70 | 71 | ## Step 2: Install the binary dependencies and download the custom PowerShell module 72 | Before you can load and execute the needed module in step 3 you'll need to first install the following two dependencies on the SharePoint 2013/2016 server you're executing these steps on: 73 | - [The 64-bit edition of Microsoft Online Services Sign-In Assistant](https://www.microsoft.com/en-us/download/details.aspx?id=41950) 74 | - [Microsoft Online Services Module for Windows Powershell (64-bit)](http://go.microsoft.com/fwlink/p/?linkid=236297) 75 | 76 | Once that's done you'll need to copy the `Connect-SPFarmToAAD.psm1` PowerShell module from the scripts folder to a folder or file share on the file system. 77 | 78 | ## Step 3: Apply the new signing certificate and setup the low trust association 79 | 80 | ### What if you're connecting to an Office 365 tenant which lives in the Germany or China environment? 81 | If your Office 365 tenant is hosted in either the Germany or China Office 365 environment then you'll need to adjust the `Connect-SPFarmToAAD.psm1` script as outlined below: 82 | 83 | ```PowerShell 84 | ... 85 | 86 | # Use following values for AAD_METADATAEP_FSTRING depending on the environment where your Office 365 tenant is hosted 87 | # Default: https://accounts.accesscontrol.windows.net/{0}/metadata/json/1 88 | # Germany: https://login.microsoftonline.de/{0}/metadata/json/1 89 | # China: https://accounts.accesscontrol.chinacloudapi.cn/{0}/metadata/json/1 90 | 91 | New-Variable -Option Constant -Name AAD_METADATAEP_FSTRING -Value 'https://accounts.accesscontrol.windows.net/{0}/metadata/json/1' 92 | ... 93 | ``` 94 | 95 | 96 | ### Setup the low trust association 97 | Start this step by running the `LowTrustConfigurationSession.ps1` script and provide as input: 98 | - **PFXFile**: the location to the PFX file created in step 1 99 | - **PFXPassword**: the password of the PFX file created in step 1 100 | - **ConnectSPFarmToAADModulePath**: the path to the module named `Connect-SPFarmToAAD.psm1` downloaded in step 2 101 | 102 | This script will perform the following tasks: 103 | - Set the new STS signing certificate 104 | - Reset the SharePoint Timer service 105 | - Import the `Connect-SPFarmToAAD.psm1` module 106 | 107 | ```PowerShell 108 | .\LowTrustConfigurationSession.ps1 -PFXFile "\\dc1\admin\certificates\STSTokenSigning.pfx" -PFXPassword "****" -ConnectSPFarmToAADModulePath "\\dc1\admin\lowtrust" 109 | ``` 110 | 111 | Once the above is done you've setup a session that's ready for the final step, performing the actual low trust configuration. You can do this by issuing the `Connect-SPFarmToAAD` cmdlet like shown in below samples: 112 | 113 | ```PowerShell 114 | Connect-SPFarmToAAD –AADDomain 'MyO365Domain.onmicrosoft.com' –SharePointOnlineUrl https://MyO365Domain.sharepoint.com –SharePointWeb https://fabrikam.com 115 | 116 | Connect-SPFarmToAAD –AADDomain 'MyO365Domain.onmicrosoft.com' –SharePointOnlineUrl https://MyO365Domain.sharepoint.com –SharePointWeb http://northwind.com -AllowOverHttp 117 | 118 | Connect-SPFarmToAAD –AADDomain 'MyO365Domain.onmicrosoft.com' –SharePointOnlineUrl https://MyO365Domain.sharepoint.com –SharePointWeb http://northwind.com –AllowOverHttp –RemoveExistingACS –RemoveExistingSTS –RemoveExistingSPOProxy –RemoveExistingAADCredentials 119 | ``` 120 | 121 | The final steps are the doing an IISReset all the farm servers + perform a SharePoint Timer Server restart on all the servers of the farm except the one where you did run the `Connect-SPFarmToAAD` cmdlet as that was already done. 122 | 123 | If you want to also enable low trust on other web applications you do not need to repeat the above procedure but rather use below PowerShell script: 124 | 125 | ```PowerShell 126 | $SPAppPrincipal = Get-MsolServicePrincipal -AppPrincipalId 00000003-0000-0ff1-ce00-000000000000 127 | $id = "00000003-0000-0ff1-ce00-000000000000/" 128 | 129 | Get-SPWebApplication | ForEach-Object { 130 | $hostName = $_.Url.substring($_.Url.indexof("//") + 2) 131 | $hostName = $hostName.Remove($hostName.Length - 1, 1) 132 | 133 | $NewSPN = $id + $hostName 134 | 135 | Write-Host "Adding SPN for" $NewSPN 136 | 137 | if ($SPAppPrincipal.ServicePrincipalNames -notcontains $NewSPN) { 138 | $SPAppPrincipal.ServicePrincipalNames.Add($NewSPN) 139 | Set-MsolServicePrincipal -AppPrincipalId $SPAppPrincipal.AppPrincipalId -ServicePrincipalNames $SPAppPrincipal.ServicePrincipalNames 140 | } 141 | } 142 | ``` 143 | 144 | -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.CloudSSA.Configuration/CreateHybridCloudSSA.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | This script is designed specifically to deploy a hybrid cloud Search Service Application to a SharePoint Server farm 4 | 5 | .description 6 | This script is designed specifically to deploy a hybrid cloud Search Service Application to a SharePoint Server farm 7 | All components are configured on the services selected 8 | Change the script if you have more services or want certain components on certain servers 9 | 10 | It requires the following variables: 11 | *SearchApplicationPoolAccountName - this is the account for the search app pool. If there is an existing local SSA that same account can be reused. Note that this account must be a managed SharePoint service account 12 | *DatabaseServer - this is the name of an existing SharePoint database server 13 | *SearchServer1 - this is the name of the first new server for Hybrid Search services. This server must already be added to the farm and should not host any SharePoint roles other than what was created when the server was added 14 | *SearchServer2 - this is the name of the second new server for Hybrid Search services. The presence of this server is optional if the customer does not have a highly available SharePoint farm. This server must already be added to the farm and should not host any SharePoint roles other than what was created when the server was added 15 | The Authors recommend that two servers be used for high availability of the search service application 16 | 17 | .example 18 | .\CreateHybridCloudSSA.ps1 -SearchApplicationPoolAccountName "appoolname" -DatabaseServer "spsql" -SearchServer1 "spba01" -SearchServer2 "SPfe01" 19 | #> 20 | 21 | 22 | Param( 23 | [Parameter(Mandatory=$true)][string] $SearchApplicationPoolAccountName, 24 | [Parameter(Mandatory=$true)][string] $DatabaseServer, 25 | [Parameter(Mandatory=$true)][string] $SearchServer1, 26 | [Parameter(Mandatory=$false)][string] $SearchServer2 27 | ) 28 | 29 | #============================================================== 30 | #Set name constants 31 | #============================================================== 32 | Add-PSSnapin Microsoft.SharePoint.Powershell 33 | $SearchServiceApplicationName = "HybridSearchServiceApplication" 34 | $DatabaseName = "HybridSearchServiceApplication" 35 | 36 | #============================================================== 37 | #Search Application Pool 38 | #============================================================== 39 | Write-Host -ForegroundColor DarkGray "Checking if Search Application Pool exists" 40 | $SPServiceApplicationPool = Get-SPServiceApplicationPool -Identity $SearchServiceApplicationName -ErrorAction SilentlyContinue 41 | 42 | if (!$SPServiceApplicationPool) 43 | { 44 | Write-Host -ForegroundColor Yellow "Creating Search Application Pool" 45 | $SPServiceApplicationPool = New-SPServiceApplicationPool -Name $SearchServiceApplicationName -Account $SearchApplicationPoolAccountName -Verbose 46 | } 47 | 48 | #============================================================== 49 | #Search Service Application 50 | #============================================================== 51 | Write-Host -ForegroundColor DarkGray "Checking if SSA exists" 52 | $SearchServiceApplication = Get-SPEnterpriseSearchServiceApplication -Identity $SearchServiceApplicationName -ErrorAction SilentlyContinue 53 | if (!$SearchServiceApplication) 54 | { 55 | Write-Host -ForegroundColor Yellow "Creating Search Service Application" 56 | $SearchServiceApplication = New-SPEnterpriseSearchServiceApplication -Name $SearchServiceApplicationName -ApplicationPool $SPServiceApplicationPool.Name -DatabaseServer $DatabaseServer -DatabaseName $DatabaseName -CloudIndex $true 57 | } 58 | 59 | Write-Host -ForegroundColor DarkGray "Checking if SSA Proxy exists" 60 | $SearchServiceApplicationProxy = Get-SPEnterpriseSearchServiceApplicationProxy -Identity ($SearchServiceApplicationName + "_Proxy") -ErrorAction SilentlyContinue 61 | if (!$SearchServiceApplicationProxy) 62 | { 63 | Write-Host -ForegroundColor Yellow "Creating SSA Proxy" 64 | New-SPEnterpriseSearchServiceApplicationProxy -Name ($SearchServiceApplicationName + "_Proxy") -SearchApplication $SearchServiceApplicationName 65 | } 66 | 67 | #============================================================== 68 | #Start Search Service Instance on Server1 69 | #============================================================== 70 | $SearchServiceInstanceServer1 = Get-SPEnterpriseSearchServiceInstance $SearchServer1 71 | Write-Host -ForegroundColor DarkGray "Checking if SSI is Online on SearchServer1" 72 | if($SearchServiceInstanceServer1.Status -ne 'Online') 73 | { 74 | Write-Host -ForegroundColor Yellow "Starting Search Service Instance" 75 | Start-SPEnterpriseSearchServiceInstance -Identity $SearchServiceInstanceServer1 76 | While ($SearchServiceInstanceServer1.Status -ne 'Online') 77 | { 78 | Start-Sleep -s 5 79 | Write-Host "Sleeping for 5 seconds" 80 | $SearchServiceInstanceServer1 = Get-SPEnterpriseSearchServiceInstance -Identity $SearchServer1 81 | } 82 | Write-Host -ForegroundColor Yellow "SSI on SearchServer1 is started" 83 | } 84 | 85 | #============================================================== 86 | #Start Search Service Instance on Server2 (if specified) 87 | #============================================================== 88 | If ($SearchServer2) 89 | { 90 | $SearchServiceInstanceServer2 = Get-SPEnterpriseSearchServiceInstance $SearchServer2 91 | Write-Host -ForegroundColor DarkGray "Checking if SSI is Online on SearchServer2" 92 | if($SearchServiceInstanceServer2.Status -ne 'Online') 93 | { 94 | Write-Host -ForegroundColor Yellow "Starting Search Service Instance" 95 | Start-SPEnterpriseSearchServiceInstance -Identity $SearchServiceInstanceServer2 96 | While ($SearchServiceInstanceServer2.Status -ne 'Online') 97 | { 98 | Start-Sleep -s 5 99 | Write-Host "Sleeping for 5 seconds" 100 | $SearchServiceInstanceServer2 = Get-SPEnterpriseSearchServiceInstance -Identity $SearchServer2 101 | } 102 | Write-Host -ForegroundColor Yellow "SSI on SearchServer2 is started" 103 | } 104 | 105 | } 106 | #============================================================== 107 | #Cannot make changes to topology in Active State. 108 | #Create new topology to add components 109 | #============================================================== 110 | 111 | $InitialSearchTopology = $SearchServiceApplication | Get-SPEnterpriseSearchTopology -Active 112 | $NewSearchTopology = $SearchServiceApplication | New-SPEnterpriseSearchTopology 113 | 114 | #============================================================== 115 | #Search Service Application Components on SearchServer1 116 | #Creating all components except Index (created later) 117 | #============================================================== 118 | New-SPEnterpriseSearchAnalyticsProcessingComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer1 119 | New-SPEnterpriseSearchContentProcessingComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer1 120 | New-SPEnterpriseSearchQueryProcessingComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer1 121 | New-SPEnterpriseSearchCrawlComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer1 122 | New-SPEnterpriseSearchAdminComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer1 123 | 124 | #============================================================== 125 | #Search Service Application Components on SearchServer2 (if specified) 126 | #Creating all components except Index (created later) 127 | #============================================================== 128 | If ($SearchServer2) 129 | { 130 | New-SPEnterpriseSearchAnalyticsProcessingComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer2 131 | New-SPEnterpriseSearchContentProcessingComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer2 132 | New-SPEnterpriseSearchQueryProcessingComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer2 133 | New-SPEnterpriseSearchCrawlComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer2 134 | New-SPEnterpriseSearchAdminComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer2 135 | } 136 | #============================================================== 137 | #Index Components with replicas on SearchServer1 and SearchServer2 (if specified) 138 | #============================================================== 139 | 140 | New-SPEnterpriseSearchIndexComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer1 -IndexPartition 0 141 | New-SPEnterpriseSearchIndexComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer1 -IndexPartition 1 142 | 143 | If ($SearchServer2) 144 | { 145 | New-SPEnterpriseSearchIndexComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer2 -IndexPartition 0 146 | New-SPEnterpriseSearchIndexComponent -SearchTopology $NewSearchTopology -SearchServiceInstance $SearchServiceInstanceServer2 -IndexPartition 1 147 | } 148 | 149 | $NewSearchTopology.Activate() 150 | 151 | #================================================= 152 | 153 | $ssa = Get-SPEnterpriseSearchServiceApplication | ?{$_.CloudIndex -eq $true} 154 | Get-SPEnterpriseSearchTopology -Active -SearchApplication $ssa 155 | Get-SPEnterpriseSearchStatus -SearchApplication $ssa -Text |ft Name, state,Partition,Host -AutoSize 156 | $ssa.CloudIndex -------------------------------------------------------------------------------- /Scripts/SharePoint.Hybrid.Search.Configuration/HybridWizard.ps1: -------------------------------------------------------------------------------- 1 | <# Disclaimer 2 | 3 | Microsoft provides programming examples for illustration only, without warranty either expressed or 4 | implied, including, but not limited to, the implied warranties of merchantability and/or fitness 5 | for a particular purpose. 6 | 7 | This sample assumes that you are familiar with the programming language being demonstrated and the 8 | tools used to create and debug procedures. Microsoft support professionals can help explain the 9 | functionality of a particular procedure, but they will not modify these examples to provide added 10 | functionality or construct procedures to meet your specific needs. if you have limited programming 11 | experience, you may want to contact a Microsoft Certified Partner or the Microsoft fee-based consulting 12 | line at (800) 936-5200. 13 | 14 | # Added to Github PnP-Tools Repository 15 | 16 | # HYBRID CONFIGURATION WIZARD # 17 | # 20/11/2015 - Release v0.9 18 | # 20/11/2015 - Added pre req checks and more graceful exit 19 | # 11/11/2015 - Fixed up dirsync report format; Make http call to spsite after iisreset, single domain name url fixed, debug text cleanup 20 | # 09/04/2015 - Implemented Form.Focus, added cleanup option (not quite ready) and fixed Wizard Exit on Completion 21 | # 20/03/2015 - Changed text boxes to labels. Added Dirsync check and local admin check. Removed IISReset Warning and updated Start/Exit button behaviour 22 | # 09/01/2015 - Fixed problem installing .MSI files 23 | # 18/12/2014 - V0.3 released for testing 24 | # 10/12/2014 - Self Signed Cert bug fixed by implementing a -1 day to start date 25 | # 09/12/2014 - Fixed certificate export bug - missing move to root auth section 26 | # 09/12/2014 - Added code to remove existing certs from my and root if same self signed name is used. 27 | # 08/12/2014 - Added multiple error checking for failed SPO logins 28 | # 05/12/2014 - Fixed naming conventions for functions 29 | 30 | # Version Control 31 | 32 | #Update this version number for each release 33 | #> 34 | 35 | $HWVersion = " v0.9" 36 | 37 | #Useful references - PowerShell forms and Controls - http://technet.microsoft.com/en-us/library/ff730941.aspx 38 | Add-PSSnapin Microsoft.SharePoint.PowerShell -EA 0 39 | Add-Type -AssemblyName System.Windows.Forms 40 | 41 | #region FunctionDefs 42 | 43 | ###################################################################### 44 | # Import-ModulesAndConnect # 45 | # Prompts for O365 tenant login creds # 46 | ###################################################################### 47 | function Import-ModulesAndConnect() 48 | { 49 | Write-Host "Entering Import-Modules and Connect" 50 | 51 | Update-WizardProgress "Importing required PowerShell Modules and Connecting to O365" 52 | 53 | # Import MSOnline Modules 54 | # To Add - if msol modules are not available we need to add a section to prompt for download and install 55 | 56 | #Import the Microsoft Online Services Sign-In Assistant. 57 | Import-Module -Name MSOnline 58 | #Import the Microsoft Online Services Module for Windows Powershell. 59 | Import-Module MSOnlineExtended –force 60 | $O365Creds = "" 61 | $ExitConnect = $false 62 | #We are going to use the $error output to track the last error message to see if it corresponds to an invalid login attempt 63 | $error.Clear() 64 | do 65 | { 66 | $error.Clear() 67 | $O365Creds = Get-Credential -Message "Tenant Admin credentials" 68 | Connect-MsolService -Credential $O365Creds 69 | $Theuser = $O365Creds.UserName 70 | If ($error[0].Exception -match "The user name or password is incorrect") 71 | { 72 | Update-WizardProgress "Login Unsuccessful" 73 | $O365Connected = $false, $Theuser 74 | $ExitConnect = $false 75 | } 76 | else 77 | { 78 | Update-WizardProgress "Logged into MSOL as $TheUser" 79 | $O365Connected = $true, $Theuser 80 | $ExitConnect = $true 81 | } 82 | 83 | if ($ExitConnect -eq $false) 84 | { 85 | Update-WizardProgress "Connection to MSOL failed - Try Again?" 86 | 87 | $msgBox = Show-MessageBox "You failed to authenticate to Office 365 as a global admin.`nWould you like to try again?" -YesNo 88 | 89 | # Checking if user wants to exit the login attempt 90 | if ($msgbox -eq "No") 91 | { 92 | $ExitConnect = $true 93 | } 94 | else 95 | { 96 | $ExitConnect = $false 97 | } 98 | } 99 | } 100 | until ($ExitConnect -eq $true) 101 | 102 | 103 | #Check for dirsync active - warn if not 104 | #Report last time sync - warn is last dirsync time > 24 hours 105 | 106 | $msolcompany = Get-MsolCompanyInformation 107 | $IsDirSyncEnabled = $msolcompany.DirectorySynchronizationEnabled 108 | $LastDirsynctime = $msolcompany.LastDirSyncTime 109 | $thedate = Get-Date 110 | 111 | $SyncDelay = (get-date) - ($msolcompany.LastDirSyncTime) 112 | $SyncDelayDays = $SyncDelay.Days 113 | $SyncDelayHours = $SyncDelay.Hours 114 | $SyncDelayMinutes = $SyncDelay.Minutes 115 | 116 | if ($IsDirSyncEnabled -eq $true) 117 | { 118 | Update-WizardProgress "Dirsync is enabled for the O365 Tenancy" 119 | Write-Host "Dirsync is enabled for the O365 Tenancy" 120 | Update-WizardProgress "Last Dirsync was $SyncDelayHours hours and $SyncDelayMinutes minutes ago" 121 | Write-Host "Last Dirsync was $SyncDelayHours hours and $SyncDelayMinutes minutes ago" 122 | 123 | if($SyncDelay.Days -gt 0) 124 | { 125 | Show-MessageBox -Title "Dirsync Warning" "Your Dirsync process has not completed for $SyncDelayDays Days and $SyncDelayHours Hours`nYou can continue with the Wizard but it is recommended you investigate and fix and errors with the sync process as soon as possible" -Warning | out-null 126 | Update-WizardProgress "Dirsync Warning - Over 24 Hours since last sync" 127 | } 128 | } 129 | else 130 | { 131 | Show-MessageBox -Title "Dirsync Critcal" "Dirsync is not enabled for the Tenancy!`n`nYou can continue with the Wizard but it is required that you complete this process to enable hybrid user experiences" -Critical | out-null 132 | Update-WizardProgress "Dirsync is NOT enabled for the O365 Tenancy" 133 | } 134 | 135 | return $O365Connected 136 | 137 | } 138 | 139 | ###################################################################### 140 | # Register-ServicePrincipalO365 # 141 | # Registers the service principal for O365 using the certificate # 142 | # $spo_appid = Standared SPO App ID GUID # 143 | # $cred_value = Base64 encoding of the STS.cer certificate # 144 | ###################################################################### 145 | function Register-ServicePrincipalO365($spo_appid, $cred_value) 146 | { 147 | write-host "Entering Register-ServicePrincipalO365 with parameters" $spo_appid $cred_value 148 | 149 | Update-WizardProgress "Registering Service App Principal" 150 | 151 | #Register the On-Premise STS as Service Principal in Office 365 152 | 153 | New-MsolServicePrincipalCredential -AppPrincipalId $spo_appid -Type asymmetric -Usage Verify -Value $cred_Value 154 | $spocontextID = (Get-MsolCompanyInformation).ObjectID 155 | $spoappprincipalID = (Get-MsolServicePrincipal -ServicePrincipalName $spo_appid).ObjectID 156 | $sponameidentifier = "$spoappprincipalID@$spocontextID" 157 | 158 | $SPO365 = $spocontextID, $sponameidentifier 159 | 160 | return $SPO365 161 | } 162 | 163 | ###################################################################### 164 | # Establish-ACSTrust # 165 | # Creates the ACS proxy and Adds ACS as security token issues # 166 | # $sp_site = defines the site for app prinicpal registeration # 167 | # $spo_name_identifier = SPOID and Tenant ContextID # 168 | # $spo_context_ID = Establishes Authentication Realm # 169 | ###################################################################### 170 | function Establish-ACSTrust($SPSite, $spo_name_identifier, $spo_context_ID) 171 | { 172 | write-host "Entering Establish_ACSTrust with parameters" $spsite $spo_name_identifier $spo_context_ID 173 | 174 | Update-WizardProgress "Establishing ACS Trust and Deploying Proxy" 175 | 176 | #First we remove old ACS Proxy and SecurityTokenIssues 177 | $OldACSProxy = Get-SPServiceApplicationProxy | ? {$_.typename -match "Azure Access Control Service Application Proxy"} | Remove-SPServiceApplicationProxy 178 | $OldTSTI = Get-SPTrustedSecurityTokenIssuer | ? {$_.name -match "ACS"} | Remove-SPTrustedSecurityTokenIssuer 179 | 180 | #Finally Establish in the On-Premise Farm a Trust with the ACS 181 | 182 | $rootsite = Get-SPSite $SPSite 183 | 184 | $appPrincipal = Register-SPAppPrincipal -site $rootsite.rootweb -nameIdentifier $spo_name_identifier -displayName "SharePoint Online" #Error here 185 | Set-SPAuthenticationRealm -realm $spo_context_ID 186 | New-SPAzureAccessControlServiceApplicationProxy -Name "ACS" -MetadataServiceEndpointUri "https://accounts.accesscontrol.windows.net/metadata/json/1/" -DefaultProxyGroup 187 | New-SPTrustedSecurityTokenIssuer -MetadataEndpoint "https://accounts.accesscontrol.windows.net/metadata/json/1/" -IsTrustBroker -Name "ACS" 188 | } 189 | 190 | ###################################################################### 191 | # Manage-STSCertificate # 192 | # Sequence of steps to implement selected Certificates Process # 193 | # Options are SelfSigned, Default or Public # 194 | # v1 = SelfSigned only # 195 | # $spoapplid = SPO App ID GUID # 196 | # $spcname = on premises SP domain name for SPN # 197 | ###################################################################### 198 | function Manage-STSCertificate($spoapplid, $SPSite, $CommonName) 199 | { 200 | Write-Host "Entering manage-stscertificate with parameters $spoapplid $SPSite $commonname" 201 | 202 | Update-WizardProgress "Beginning Certificate Management Process" 203 | 204 | $indexHostName = $SPSite.IndexOf('://') + 3 205 | $HostName = $SPSite.Substring($indexHostName) 206 | $indexHostName = $HostName.IndexOf('/') 207 | if ($indexhostName -ge 0) { 208 | $HostName = $HostName.Substring(0,$indexHostName) 209 | } 210 | 211 | $partfqdn = $Hostname.Indexof('.') 212 | 213 | # Check for single part domain name, ie http://spweb as this will result in $partfqdn value of -1 214 | if($partfqdn -lt 0) 215 | { 216 | $Hostname = "*" + $Hostname 217 | } 218 | else 219 | { 220 | $Hostname = "*" + $Hostname.Substring($partfqdn) ##substring error here 221 | } 222 | 223 | $NewSPN = '{0}/{1}' -f $spoapplid, $HostName 224 | 225 | $SPAppPrincipal = Get-MsolServicePrincipal -AppPrincipalId $spoapplid 226 | if ($SPAppPrincipal.ServicePrincipalNames -notcontains $NewSPN) 227 | { 228 | $SPAppPrincipal.ServicePrincipalNames.Add($NewSPN) 229 | Set-MsolServicePrincipal -AppPrincipalId $SPAppPrincipal.AppPrincipalId -ServicePrincipalNames $SPAppPrincipal.ServicePrincipalNames 230 | } 231 | 232 | $UpdateWizardProgress = "SPN in O365 configured for $Hostname" 233 | 234 | Update-WizardProgress $UpdateWizardProgress 235 | 236 | if($radiobuttonUsePublicAuthoritySi.Checked) 237 | { 238 | #Use Public Authority Certificate 239 | } 240 | 241 | if($radiobuttonUseNewSelfSignedSTSC.Checked) 242 | { 243 | #Use Auto Generated Self Signed Certificate 244 | 245 | Update-WizardProgress "New selfsigned certificate selected" 246 | $CertPass = read-host -Prompt "Please enter the password to secure the self signed certificate" -AsSecureString 247 | Update-WizardProgress "Creating selfsigned certificate and adding to trusted root store" 248 | $CreateCert = Add-SelfSignedCertificate $CommonName 249 | Update-WizardProgress "Updating Farm Secure Token Service with new Certificate" 250 | $UpdateFarmSTS = Update-FarmSTS $CommonName $CertPass 251 | Update-WizardProgress "Generating Credentials for O365 S2S trust" 252 | $CredentialValue = Convert-CertsForUpload $CommonName $CertPass 253 | Update-WizardProgress "Registering the Service App Principal" 254 | $RegServiceAppPrin = Register-ServicePrincipalO365 $spoapplid $CredentialValue 255 | 256 | $spo_contextID = $RegServiceAppPrin[0] 257 | $spo_nameidentifier = $RegServiceAppPrin[1] 258 | Update-WizardProgress "Setting up the S2S trust and deploying ACS Proxy" 259 | $EstablishACSTrust = Establish-ACSTrust $SPSite $spo_nameidentifier $spo_contextID 260 | 261 | #At this Point Hybrid identity setup is complete for NewSelfSignedCertificate 262 | 263 | Update-WizardProgress "Hybrid Certificate Management process is complete" 264 | Write-Host "Hybrid Certificate Management process is complete" 265 | } 266 | 267 | if($radiobuttonUseBuiltInSharePoint.Checked) 268 | { 269 | #Use Built In STS Certificate 270 | 271 | Update-WizardProgress"Built in certificate selected" 272 | #$sp_site = $labelOnPremisesSharePoin.Text # future where user gets option to choose which on prem site to configure 273 | Update-WizardProgress"Exporting Default STS Cert" 274 | $LocalCertCred = Export-LocalSTSCert 275 | #Register the Service Principal 276 | Update-WizardProgress"Registering the Service App Principal" 277 | $RegServiceAppPrin = Register-ServicePrincipalO365 $spoapplid $LocalCertCred 278 | 279 | $spo_contextID = $RegServiceAppPrin[0] 280 | $spo_nameidentifier = $RegServiceAppPrin[1] 281 | Update-WizardProgress"Setting up the S2S trust and deploying ACS Proxy" 282 | $EstablishACSTrust = Establish-ACSTrust $SPSite $spo_nameidentifier $spo_contextID 283 | 284 | #At this Point Hybrid identity setup is complete for ExportingTheDefaultCertificate 285 | 286 | Update-WizardProgress "Hybrid Certificate Management process is complete" 287 | Write-Host "Hybrid Certificate Management process is complete" 288 | } 289 | } 290 | 291 | ###################################################################### 292 | # Export-LocalSTSCert # 293 | # Exports local STS Cert and converts for use as CredValue # 294 | # for settings up the trust # 295 | ###################################################################### 296 | function Export-LocalSTSCert() 297 | { 298 | #Uses the local signing key for upload to O365 instead of creating a new one 299 | $SPSigningCert = (Get-SPSecurityTokenServiceConfig).LocalLoginProvider.SigningCertificate 300 | $ExportedCert = $SPSigningCert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert) 301 | $CertValue = [System.Convert]::ToBase64String($ExportedCert,[System.Base64formattingoptions]::InsertLineBreaks) 302 | 303 | return $CertValue 304 | } 305 | 306 | ###################################################################### 307 | # Update-FarmSTS # 308 | # Updates the Farm STS with the specified certificate # 309 | # $commonname = Certificate common name # 310 | # $CertSecret = Password to use to secure the certificate # 311 | ###################################################################### 312 | function Update-FarmSTS($commonname, $SecCertSecret) 313 | { 314 | write-host "Entering Update-FarmSTS with parameters $commonname $SecCertSecret" 315 | #$SecCertSecret = ConvertTo-SecureString $CertSecret -AsPlainText -Force 316 | #Export the required certificates for Updating STS and Uploading to ACS 317 | 318 | $certstore = dir Cert:\LocalMachine\Root ` 319 | | where-object {$_.Subject -eq "CN=$commonname"} ` 320 | | foreach-object{ 321 | [system.IO.file]::WriteAllBytes( "$home\$($_.subject).pfx", ($_.Export('PFX', $SecCertSecret)) ) 322 | [system.IO.file]::WriteAllBytes( "$home\$($_.subject).cer", ($_.Export('CER', $SecCertSecret)) ) 323 | } 324 | 325 | $pfxcertname = "$home\CN=$commonname"+".pfx" 326 | 327 | $pfxCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $pfxcertname, $SecCertSecret, 20 328 | Set-SPSecurityTokenServiceConfig -ImportSigningCertificate $pfxCertificate 329 | 330 | #Restart IIS so STS Picks up the New Certificate 331 | Update-WizardProgress "The IIS Services and the SharePoint Timer Service are now going to be recycled." 332 | 333 | & iisreset 334 | & net stop SPTimerV4 335 | & net start SPTimerV4 336 | 337 | #(Get-SPSecurityTokenServiceConfig).LocalLoginProvider.SigningCertificate #DEBUG ONLY 338 | } 339 | 340 | ###################################################################### 341 | # Convert-CertsforUpload # 342 | # Converts Certificate to Base 64 for use as App Principal Cred # 343 | # $LocalDN = Certificate common name # 344 | # $CertSecret = Password to use to secure the certificate # 345 | ###################################################################### 346 | function Convert-CertsForUpload($LocalCN, $CertSecret) 347 | { 348 | #Do Some Conversions With the Certificates to Base64 349 | #Return $credValue for use in Adding App Principal 350 | 351 | $stscertpfx = "$home\CN=$LocalCN.pfx" 352 | $stscertpassword = $CertSecret 353 | $stscertcer = "$home\CN=$LocalCN.cer" 354 | 355 | $pfxCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $stscertpfx,$stscertpassword 356 | $pfxCertificateBin = $pfxCertificate.GetRawCertData() 357 | $cerCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 358 | $cerCertificate.Import($stscertcer) 359 | $cerCertificateBin = $cerCertificate.GetRawCertData() 360 | $credValue = [System.Convert]::ToBase64String($cerCertificateBin) 361 | 362 | Return $credValue 363 | } 364 | 365 | ###################################################################### 366 | # Add-SelfSignedCertificate # 367 | # Adds a Self Signed Certificate to the Local Machine Personal Store # 368 | # $commonname defines the certificate subject to be used # 369 | ###################################################################### 370 | function Add-SelfSignedCertificate($commonname) 371 | { 372 | 373 | #Remove and existing certificates with the same common name from personal and root stores 374 | #Need to be very wary of this as could break something 375 | 376 | $certs = dir Cert:\LocalMachine\my | ?{$_.Subject -eq "CN=$commonname"} 377 | $mystore = get-item Cert:\LocalMachine\My 378 | $mystore.open("ReadWrite") 379 | Foreach($acert in $certs) { $mystore.Remove($acert) } 380 | $mystore.close() 381 | 382 | $certs = dir Cert:\LocalMachine\Root | ?{$_.Subject -eq "CN=$commonname"} 383 | $rootstore = get-item Cert:\LocalMachine\Root 384 | $rootstore.open("ReadWrite") 385 | Foreach($acert in $certs) { $rootstore.Remove($acert) } 386 | $rootstore.close() 387 | 388 | $name = new-object -com "X509Enrollment.CX500DistinguishedName.1" 389 | $name.Encode("CN=$CommonName", 0) 390 | 391 | $key = new-object -com "X509Enrollment.CX509PrivateKey.1" 392 | $key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider" 393 | $key.KeySpec = 1 394 | $key.Length = 2048 # Modified to 2048 395 | $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)" 396 | $key.MachineContext = 1 397 | $key.ExportPolicy = 1 # This is required to allow the private key to be exported 398 | $key.Create() 399 | 400 | $serverauthoid = new-object -com "X509Enrollment.CObjectId.1" 401 | $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") 402 | $ekuoids = new-object -com "X509Enrollment.CObjectIds.1" 403 | $ekuoids.add($serverauthoid) 404 | $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1" 405 | $ekuext.InitializeEncode($ekuoids) 406 | 407 | $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1" 408 | $cert.InitializeFromPrivateKey(2, $key, "") 409 | $cert.Subject = $name 410 | $cert.Issuer = $cert.Subject 411 | $cert.NotBefore = get-date 412 | $cert.NotBefore = $cert.NotBefore.AddDays(-1) # Make the certificate valid to the previous day. 413 | $cert.NotAfter = $cert.NotBefore.AddDays(720) 414 | $cert.X509Extensions.Add($ekuext) 415 | $cert.Encode() 416 | 417 | $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1" 418 | $enrollment.InitializeFromRequest($cert) 419 | $certdata = $enrollment.CreateRequest(0) 420 | $enrollment.InstallResponse(2, $certdata, 0, "") 421 | 422 | $newcert = dir Cert:\LocalMachine\my | ?{$_.Subject -eq "CN=$commonname"} 423 | #$thecert = "Cert:\localmachine\my\$newcert" 424 | $store = get-item Cert:\LocalMachine\Root 425 | $store.open("ReadWrite") 426 | $store.add($newcert) 427 | $store.close() 428 | } 429 | 430 | ###################################################################### 431 | # Show-MessageBox # 432 | # Supports alert boxes with various button combinations # 433 | # $Msg = Message to send # 434 | # $Title = Alert box title # 435 | # Various button option in parameters 436 | ###################################################################### 437 | function Show-MessageBox() 438 | { 439 | Param( 440 | [Parameter(Mandatory=$True)][Alias('M')][String]$Msg, 441 | [Parameter(Mandatory=$False)][Alias('T')][String]$Title = "", 442 | [Parameter(Mandatory=$False)][Alias('OC')][Switch]$OkCancel, 443 | [Parameter(Mandatory=$False)][Alias('OCI')][Switch]$AbortRetryIgnore, 444 | [Parameter(Mandatory=$False)][Alias('YNC')][Switch]$YesNoCancel, 445 | [Parameter(Mandatory=$False)][Alias('YN')][Switch]$YesNo, 446 | [Parameter(Mandatory=$False)][Alias('RC')][Switch]$RetryCancel, 447 | [Parameter(Mandatory=$False)][Alias('C')][Switch]$Critical, 448 | [Parameter(Mandatory=$False)][Alias('Q')][Switch]$Question, 449 | [Parameter(Mandatory=$False)][Alias('W')][Switch]$Warning, 450 | [Parameter(Mandatory=$False)][Alias('I')][Switch]$Informational) 451 | 452 | #Set Message Box Style 453 | IF($OkCancel){$Type = 1} 454 | Elseif($AbortRetryIgnore){$Type = 2} 455 | Elseif($YesNoCancel){$Type = 3} 456 | Elseif($YesNo){$Type = 4} 457 | Elseif($RetryCancel){$Type = 5} 458 | Else{$Type = 0} 459 | 460 | #Set Message box Icon 461 | If($Critical){$Icon = 16} 462 | ElseIf($Question){$Icon = 32} 463 | Elseif($Warning){$Icon = 48} 464 | Elseif($Informational){$Icon = 64} 465 | Else{$Icon = 0} 466 | 467 | #Loads the WinForm Assembly, Out-Null hides the message while loading. 468 | [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null 469 | 470 | #Display the message with input 471 | $Answer = [System.Windows.Forms.MessageBox]::Show($MSG , $TITLE, $Type, $Icon) 472 | 473 | #Return Answer 474 | Return $Answer 475 | } 476 | 477 | ###################################################################### 478 | # Check-FarmAdmin # 479 | # Checks if current user is a farm admin and returns true or false # 480 | ###################################################################### 481 | function Check-FarmAdmin() 482 | { 483 | #Must return true else send message to use different user and exit app 484 | 485 | #(Get-SPFarm).DefaultServiceAccount.Name 486 | $FarmAdmin = (Get-Spfarm).CurrentUserIsAdministrator() 487 | Return $FarmAdmin 488 | } 489 | 490 | ###################################################################### 491 | # Get-SPFarmAdministrators # 492 | # Returns the farm adminstrators group membership # 493 | ###################################################################### 494 | function Get-SPfarmAdministrators() 495 | { 496 | $adminwebapp = Get-SPwebapplication -includecentraladministration | where {$_.IsAdministrationWebApplication} 497 | $adminsite = Get-SPweb($adminwebapp.Url) 498 | $AdminGroupName = $adminsite.AssociatedOwnerGroup 499 | $farmAdministratorsGroup = $adminsite.SiteGroups[$AdminGroupName] 500 | return $farmAdministratorsGroup.users 501 | } 502 | 503 | ###################################################################### 504 | # Validate-ServiceApps # 505 | # Checks if the required service applications are deployed # 506 | # Checks if the required service application instances are enabled # 507 | # Warning or Error message is delivered to user # 508 | ###################################################################### 509 | function Validate-ServiceApps() 510 | { 511 | #Create Response to Required Service App Check" 512 | $ServiceCheck = "" 513 | $ServiceStatus = 1 514 | 515 | #Validate User Profile Service Application Status 516 | $upa=Get-SPServiceApplication | where-object {$_.TypeName -match "User profile"} 517 | if ($upa.status -eq "Online") { $ServiceCheck = "UPA Service Application Check Successful`r`n" } 518 | else 519 | { 520 | $ServiceCheck = "UPA Service Application Check Failed`r`n" 521 | $ServiceStatus = 0 522 | } 523 | #$upa | Out-Null 524 | 525 | #validate userprofile service instance status 526 | $upaservinst = Get-SPServiceInstance | where-object{$_.typename -match "User Profile Service" -AND $_.status -eq "Online"} 527 | if($upaservinst) { $ServiceCheck = $ServiceCheck + "UPA Service Instance Check Successful`r`n" } 528 | else 529 | { 530 | $ServiceCheck = $ServiceCheck + "UPA Service Instance Check Failed`r`n" 531 | $ServiceStatus = 0 532 | } 533 | 534 | #validate user profile sync service instance status 535 | $upasyncinst = Get-SPServiceInstance | where-object{$_.typename -match "User Profile Synchronization Service" -AND $_.status -eq "Online"} 536 | if($upasyncinst) { $ServiceCheck = $ServiceCheck + "UPA Sync Service Instance Check Successful`r`n" } 537 | else 538 | { 539 | if($upa.NoILMUsed -eq $true) { $ServiceCheck = $ServiceCheck + "Sync Service is disabled, ensure you have run AD import synchronization `r`n" } 540 | else 541 | { 542 | #We cannot yet determine the difference between internal and external FIM so do not fail just in case - see windows service on sync machine 543 | $ServiceCheck = $ServiceCheck + "UPA Sync Service Instance Check Failed - Check UPA Import Config `r`n"} 544 | } 545 | 546 | #Validate Search Service Application Status 547 | $ssa=Get-SPServiceApplication | where-object {$_.TypeName -match "Search Service"} 548 | if ($ssa.status -eq "Online") { $ServiceCheck = $ServiceCheck + "Search Service Application Check Successful`r`n" } 549 | else 550 | { 551 | $ServiceCheck = "Search Service Application Check Failed`r`n" 552 | $ServiceStatus = 0 553 | } 554 | 555 | #Validate Search Admin Service Application Status 556 | $sas=Get-SPServiceApplication | where-object {$_.TypeName -match "Search Admin"} 557 | if ($sas.status -eq "Online") { $ServiceCheck = $ServiceCheck + "Search Admin Service Application Check Successful`r`n" } 558 | else 559 | { 560 | $ServiceCheck = "Search Admin Service Application Check Failed`r`n" 561 | $ServiceStatus = 0 562 | } 563 | 564 | #validate Search host controller service instance status 565 | $shcservinst = Get-SPServiceInstance | where-object {$_.typename -match "Search Host Controller Service" -AND $_.status -eq "Online"} 566 | if($shcservinst) { $ServiceCheck = $ServiceCheck + "Search Host Controller Service Instance Check Successful`r`n" } 567 | else 568 | { 569 | $ServiceCheck = $ServiceCheck + "Search Host Controller Service Instance Check Failed`r`n" 570 | $ServiceStatus = 0 571 | } 572 | 573 | #validate SharePoint Server Search service instance status 574 | $seaservinst = Get-SPServiceInstance | where-object{$_.typename -match "SharePoint Server Search" -AND $_.status -eq "Online"} 575 | if($seaservinst) { $ServiceCheck = $ServiceCheck + "SharePoint Server Search Service Instance Check Successful`r`n" } 576 | else 577 | { 578 | $ServiceCheck = $ServiceCheck + "SharePoint Server Search Service Instance Check Failed`r`n" 579 | $ServiceStatus = 0 580 | } 581 | 582 | #validate Search Query and Site Settings Service instance status 583 | $sqsservinst = Get-SPServiceInstance | where-object{$_.typename -match "Search Query and Site Settings Service" -AND $_.status -eq "Online"} 584 | if($sqsservinst) { $ServiceCheck = $ServiceCheck + "Search Query and Site Settings Service Instance Check Successful`r`n" } 585 | else 586 | { 587 | $ServiceCheck = $ServiceCheck + "Search Query and Site Settings Service Instance Check Failed`r`n" 588 | $ServiceStatus = 0 589 | } 590 | 591 | #Validate Subscription Settings Application Status 592 | $sss=Get-SPServiceApplication | where-object {$_.TypeName -match "Subscription"} 593 | if ($sss.status -eq "Online") { $ServiceCheck = $ServiceCheck + "Subscription Settings Service Application Check Successful`r`n" } 594 | else 595 | { 596 | $ServiceCheck = "Subscription Settings Service Application Check Failed`r`n" 597 | $ServiceStatus = 0 598 | } 599 | 600 | #Validate Microsoft SharePoint Foundation Subscription Settings Service Instance Status 601 | $sfsservinst = Get-SPServiceInstance | where-object{$_.typename -match "Microsoft SharePoint Foundation Subscription Settings Service" -AND $_.status -eq "Online"} 602 | if($sfsservinst) { $ServiceCheck = $ServiceCheck + "SharePoint Subscription Settings Service Instance Check Successful`r`n" } 603 | else 604 | { 605 | $ServiceCheck = $ServiceCheck + "SharePoint Subscription Settings Service Instance Check Failed`r`n" 606 | $ServiceStatus = 0 607 | } 608 | 609 | #Validate App Management Application Status 610 | $app=Get-SPServiceApplication | where-object {$_.TypeName -match "App Management"} 611 | if ($app.status -eq "Online") { $ServiceCheck = $ServiceCheck + "App Management Service Application Check Successful`r`n" } 612 | else 613 | { 614 | $ServiceCheck = "App Management Service Application Check Failed`r`n" 615 | $ServiceStatus = 0 616 | } 617 | 618 | #Validate App Management Service Instance Status 619 | $samservinst = Get-SPServiceInstance | where-object{$_.typename -match "App Management Service" -AND $_.status -eq "Online"} 620 | if($samservinst) { $ServiceCheck = $ServiceCheck + "App Management Service Instance Check Successful`r`n" } 621 | else 622 | { 623 | $ServiceCheck = $ServiceCheck + "App Management Service Instance Check Failed`r`n" 624 | $ServiceStatus = 0 625 | } 626 | 627 | #Validate Security Token Service Application Status 628 | $sts=Get-SPServiceApplication | where-object {$_.TypeName -match "Security Token"} 629 | if ($sts.status -eq "Online") { $ServiceCheck = $ServiceCheck + "Security Token Service Check Successful`r`n" } 630 | else 631 | { 632 | $ServiceCheck = "Security Token Service Check Failed`r`n" 633 | $ServiceStatus = 0 634 | } 635 | 636 | if ($ServiceStatus -eq 1) { Show-MessageBox "All Required Services are deployed and Online `r`n$ServiceCheck" | out-null } 637 | else 638 | { 639 | Show-MessageBox "Services not correctly setup `r `n$ServiceCheck" -Critical | out-null 640 | Show-MessageBox "Wizard will now exit!" | Out-Null 641 | } 642 | return $ServiceStatus, $ServiceCheck 643 | } 644 | 645 | <# 646 | ###################################################################### 647 | # DEPRECATED FUNCTION # 648 | # Prepares the server by deploying the MSOL/ADCRL pieces # 649 | # Recycles services after deployment # 650 | ###################################################################### 651 | function Deprecated-Prepare-Environment(){ 652 | 653 | ## Future - look for new version of MSOL/IDCRL online and download/update if required/prompted ## 654 | 655 | $scriptFolder = "C:\scripts\Resources" 656 | 657 | $MSOIdCRLRegKey = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\MSOIdentityCRL" -ErrorAction SilentlyContinue 658 | if($MSOIdCRLRegKey -eq $null) 659 | { 660 | Update-WizardProgress "Installing Office Single Sign On Assistant" 661 | #Install-MSI (Get-AbsolutePath "\msoidcli_64.msi") 662 | Start-Process "$scriptFolder\msoidcli_64.msi" -ArgumentList " /q /norestart" -Wait 663 | Update-WizardProgress "Successfully installed!" 664 | } 665 | else 666 | { 667 | Update-WizardProgress "Office Single Sign On Assistant already Installed" 668 | } 669 | $MSOLPSRegKey = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\MSOnlinePowershell" -ErrorAction SilentlyContinue 670 | if($MSOLPSRegKey -eq $null) 671 | { 672 | Update-WizardProgress "Installing Active Directory PowerShell" 673 | Start-Process "$scriptFolder\AdministrationConfig-EN.msi" -ArgumentList " /q /norestart" -wait 674 | Update-WizardProgress "Creating Taskbar Shortcuts" 675 | #New-Shortcut -ShortcutName "AAD PowerShell" -IconPath ($scriptFolder + "\AzurePS.ico") -ApplicationPath "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command ""Import-Module MSOnline""" 676 | Update-WizardProgress "Successfully installed!" 677 | } 678 | else 679 | { 680 | Update-WizardProgress "Azure Active Directory Powershell already Installed" 681 | } 682 | 683 | Update-WizardProgress "Restarting MSO IDCRL Service" 684 | Stop-Service -Name msoidsvc -Force -WarningAction SilentlyContinue -ErrorAction SilentlyContinue 685 | $svc = Get-Service msoidsvc 686 | $svc.WaitForStatus("Stopped") 687 | Start-Service -Name msoidsvc 688 | $svc = Get-Service msoidsvc 689 | $svc.WaitForStatus("Running") 690 | Update-WizardProgress "MSO IDCRL Service Restarted!" 691 | 692 | } 693 | #> 694 | 695 | ###################################################################### 696 | # Checks the Server for the AAD PowerShell and Sign In Assistant # 697 | # Recycles services if they are deployed # 698 | # Raises error and exits if they are not installed # 699 | ###################################################################### 700 | function Prepare-Environment() 701 | { 702 | $MSOIdCRLRegKey = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\MSOIdentityCRL" -ErrorAction SilentlyContinue 703 | if ($MSOIdCRLRegKey -eq $null) 704 | { 705 | Write-Host "Office Single Sign On Assistant required, see http://www.microsoft.com/en-us/download/details.aspx?id=39267." -Foreground Red 706 | Update-WizardProgress "Office Single Sign on Assistant not found" 707 | } 708 | else 709 | { 710 | Write-Host "Found Office Single Sign On Assistant!" -Foreground Green 711 | Update-WizardProgress "Office Single Sign on Assistant found" 712 | } 713 | 714 | $MSOLPSRegKey = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\MSOnlinePowershell" -ErrorAction SilentlyContinue 715 | if ($MSOLPSRegKey -eq $null) 716 | { 717 | Write-Host "AAD PowerShell required, see http://go.microsoft.com/fwlink/p/?linkid=236297." -Foreground Red 718 | Update-WizardProgress "AAD PowerShell not found" 719 | } 720 | else 721 | { 722 | Write-Host "Found AAD PowerShell!" -Foreground Green 723 | Update-WizardProgress "AAD PowerShell found" 724 | } 725 | 726 | if ($MSOIdCRLRegKey -eq $null -or $MSOLPSRegKey -eq $null) 727 | { 728 | Update-WizardProgress "Please manually install the prerequisites." 729 | throw "Manual installation of prerequisites required." 730 | } 731 | 732 | Write-Host "Configuring Azure AD settings..." -Foreground Yellow 733 | 734 | $regkey = "HKLM:\SOFTWARE\Microsoft\MSOnlinePowerShell\Path" 735 | Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\MSOIdentityCRL" -Name "ServiceEnvironment" -Value "Production" 736 | Set-ItemProperty -Path $regkey -Name "WebServiceUrl" -Value "https://provisioningapi.microsoftonline.com/provisioningwebservice.svc" #$PROVISIONINGAPI_WEBSERVICEURL 737 | Set-ItemProperty -Path $regkey -Name "FederationProviderIdentifier" -Value "microsoftonline.com" 738 | 739 | Write-Host "Restarting MSO IDCRL Service..." -Foreground Yellow 740 | Update-WizardProgress "Restarting MSO IDCRL Service" 741 | 742 | # Service takes time to get provisioned, retry restart. 743 | for ($i = 1; $i -le 10; $i++) 744 | { 745 | try 746 | { 747 | Stop-Service -Name msoidsvc -Force -WarningAction SilentlyContinue -ErrorAction SilentlyContinue 748 | $svc = Get-Service msoidsvc 749 | $svc.WaitForStatus("Stopped") 750 | Start-Service -Name msoidsvc 751 | } 752 | catch 753 | { 754 | Write-Host "Failed to start msoidsvc service, retrying..." 755 | Update-WizardProgress "Failed to start msoidsvc service, retrying..." 756 | Start-Sleep -seconds 2 757 | continue 758 | } 759 | Write-Host "Service Restarted!" -Foreground Green 760 | Update-WizardProgress "Service Restrated" 761 | break 762 | } 763 | } 764 | 765 | ###################################################################### 766 | # Validate-MSOLDomain # 767 | # Checks for domains added to the tenant and prompts to use dirsync # 768 | ###################################################################### 769 | function Validate-MSOLDomain() 770 | { 771 | $domainlist = "" 772 | $domains = get-msoldomain | ?{$_.name -notmatch "onmicrosoft.com"} 773 | 774 | foreach ($domain in $domains) 775 | { 776 | $domainlist = $domainlist + $domain.name + "`n" 777 | } 778 | $updatetxt = "The following domain(s) are associated with your tenant. Please ensure you have completed the Azure AD Sync process for these domains. `n `n$domainlist`n" 779 | Update-WizardProgress $updatetxt 780 | 781 | $spodomains = get-msoldomain | ?{$_.name -match "onmicrosoft.com"} 782 | $firstspodomainname=$spodomains[0].name 783 | $thespotenantdomain=$firstspodomainname.split(".") 784 | $SPORootSite="https://" + $thespotenantdomain[0] +".sharepoint.com" 785 | $labelSPOTenantURL.text = $SPORootSite 786 | 787 | #Need to isolate a domain for later when adding an SPN - Grab the first returned SPWeb and use that 788 | #Might need to consider adding a selection for the web app into here 789 | 790 | $SharePointWeb = Get-SPSite | Select-Object -First 1 | Get-SPWeb | Select-Object -First 1 | % Url 791 | $labelOnPremisesSharePoin.Text = $SharePointWeb 792 | return $SharePointWeb 793 | } 794 | 795 | ###################################################################### 796 | # Creates new query rule and search result source # 797 | # # 798 | ###################################################################### 799 | function New-SCSearchResultSourceAndQueryRule($siteUrl, $remoteUrl, $resultSourceName, $queryRuleName) 800 | { 801 | 802 | #$sspApp = Get-SPEnterpriseSearchServiceApplication | select -first 1 803 | #$SearchServiceApplicationName = $sspApp.Name 804 | $RootSiteCollection = Get-SPSite $siteUrl -ErrorAction SilentlyContinue 805 | 806 | #----------------------------------------------------- 807 | # Get the Search Service application 808 | #----------------------------------------------------- 809 | # Select the first search service application in case there are multiple - can add choices later 810 | $SearchServiceApplication = Get-SPEnterpriseSearchServiceApplication | select -first 1 # -Identity $SearchServiceApplicationName -ErrorAction SilentlyContinue 811 | $FederationManager = New-Object Microsoft.Office.Server.Search.Administration.Query.FederationManager($SearchServiceApplication) 812 | 813 | #-------------------------------------------------------------------------- 814 | # The below line creates a Search Object owner at the site collection level 815 | # and this can be changed to Search Application or Site level by passing 816 | # different SearchObjectLevel argument. 817 | #-------------------------------------------------------------------------- 818 | $SearchOwner = New-Object Microsoft.Office.Server.Search.Administration.SearchObjectOwner –ArgumentList @([Microsoft.Office.Server.Search.Administration.SearchObjectLevel]::SPSite,$RootSiteCollection.RootWeb) 819 | $Query = "{searchTerms}" 820 | $ResultSource = $FederationManager.GetSourceByName($resultSourceName,$SearchOwner) 821 | 822 | if($ResultSource) 823 | { 824 | Update-WizardProgress "Result Source : $ResultSourceName exist - appending remote url to name" 825 | $resultsourcename = $resultsourcename + "-" + $remoteurl 826 | } 827 | 828 | Update-WizardProgress "Creating Result Source : $ResultSourceName" 829 | 830 | $resultSource = $FederationManager.CreateSource($SearchOwner) 831 | $resultSource.Name = $resultSourceName 832 | $resultSource.CreateQueryTransform($queryProperties, $query) 833 | $resultSource.ConnectionUrlTemplate = $remoteUrl 834 | $resultSource.ProviderId = $FederationManager.ListProviders()["Remote SharePoint Provider"].Id 835 | $ResultSource.Activate() 836 | $resultSource.Commit() 837 | 838 | 839 | #------------------------------------------------------------------- 840 | # Configure a Query Rule 841 | #------------------------------------------------------------------- 842 | 843 | #$QueryRuleConditionTerm = "test" 844 | $QueryRuleManager = New-Object Microsoft.Office.Server.Search.Query.Rules.QueryRuleManager($SearchServiceApplication) 845 | 846 | # Create a search object filter using a $SearchOwner object (Site collection level - in this case) 847 | $SearchObjectFilter = New-Object Microsoft.Office.Server.Search.Administration.SearchObjectFilter($SearchOwner) 848 | 849 | $QueryRules = $QueryRuleManager.GetQueryRules($SearchObjectFilter) 850 | ForEach($Rule in $QueryRules) 851 | { 852 | if($Rule.DisplayName -eq $queryRuleName) 853 | { 854 | Update-WizardProgress "Query Rule : $QueryRuleName already exist. Appending remoteurl to name." 855 | $queryrulename = $queryrulename + "-" + $remoteurl 856 | } 857 | } 858 | 859 | Update-WizardProgress "Creating Query Rule : $QueryRuleName" 860 | 861 | $QueryRules = $QueryRuleManager.GetQueryRules($SearchObjectFilter) 862 | 863 | # Create a new rule as a active one. 864 | $QueryRule = $QueryRules.CreateQueryRule($QueryRuleName,$null,$null,$true) 865 | 866 | # Set the Query Rule condition... 867 | #[string[]] $QueryRuleTerms = @($QueryRuleConditionTerm) 868 | #$QueryRuleConditions = $QueryRule.QueryConditions 869 | #$QueryRuleCondition = $QueryRuleConditions.CreateKeywordCondition($QueryRuleTerms,$true) 870 | 871 | #Bind it to the Result Source... 872 | #$QuerySourceContextCondition = $QueryRule.CreateSourceContextCondition($ResultSource) 873 | 874 | # Set the Query Condition action to change ranked results... 875 | #$QueryRuleAction = $QueryRule.CreateQueryAction([Microsoft.Office.Server.Search.Query.Rules.QueryActionType]::ChangeQuery) 876 | #$QueryRuleAction.QueryTransform.OverrideProperties = new-object Microsoft.Office.Server.Search.Query.Rules.QueryTransformProperties 877 | #$QueryRuleAction.QueryTransform.SourceId = $ResultSource.Id 878 | 879 | # define a custom sorting - Order by FileName 880 | #$QueryRuleSortCollection = New-Object Microsoft.Office.Server.Search.Query.SortCollection 881 | #$QueryRuleSortCollection.Add("FileName", [Microsoft.Office.Server.Search.Query.SortDirection]::Descending) 882 | 883 | #$QueryRule.ChangeQueryAction.QueryTransform.OverrideProperties["SortList"] = [Microsoft.Office.Server.Search.Query.SortCollection]$QueryRuleSortCollection 884 | #$QueryRule.ChangeQueryAction.QueryTransform.QueryTemplate = "{searchTerms}" 885 | 886 | $difqueryblock = $QueryRule.CreateQueryAction("CreateResultBlock") 887 | $difqueryblock.ResultTitle.DefaultLanguageString = "Results from {searchTerms}" 888 | 889 | #look into changing the number of returned items within the result block 890 | $difqueryblock.QueryTransform.SourceId = $resultSource.Id 891 | $difqueryblock.QueryTransform.QueryTemplate = "{searchTerms}" 892 | $difqueryblock.AlwaysShow = $true 893 | 894 | $QueryRule.Update() 895 | } 896 | 897 | ################################################## 898 | #Update-WizardProgress # 899 | #Adds status messages to the progress check box # 900 | ################################################## 901 | function Update-WizardProgress($update) 902 | { 903 | $progress = $textboxWizardProgress.text + "`r`n" 904 | $progress = $progress + $update 905 | $textboxWizardProgress.Text = $progress 906 | 907 | $textboxWizardProgress.SelectionStart= $textboxWizardProgress.TextLength 908 | $textboxWizardProgress.ScrollToCaret() 909 | } 910 | 911 | ########################################## 912 | # CHECK IF CURRENT USER IS A LOCAL ADMIN # 913 | # Todo: check all farm servers # 914 | ########################################## 915 | function Check-IsLocalAdmin 916 | { 917 | $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()   918 | $principal = new-object System.Security.Principal.WindowsPrincipal($identity)   919 | $admin = [System.Security.Principal.WindowsBuiltInRole]::Administrator   920 | $principal.IsInRole($admin)   921 | }  922 | 923 | ########################################## 924 | # CLEAN UP HYBRID CONFIGURATION # 925 | # 1. REMOVE SPN # 926 | # 2. REMOVE ACS PROXY # 927 | # 3. LOOK FOR AND REMOVE DEFAULT RESULT # 928 | # SOURCE AND QUERY RULE # 929 | ########################################## 930 | function Remove-HybridConfiguration($SPSite) 931 | { 932 | $app = Get-MsolServicePrincipal -AppPrincipalId "00000003-0000-0ff1-ce00-000000000000" 933 | $app.ServicePrincipalNames 934 | 935 | $indexHostName = $SPSite.IndexOf('://') + 3 936 | $HostName = $SPSite.Substring($indexHostName) 937 | $indexHostName = $HostName.IndexOf('/') 938 | if ($indexhostName -ge 0) { 939 | $HostName = $HostName.Substring(0,$indexHostName) 940 | } 941 | 942 | $partfqdn = $Hostname.Indexof('.') 943 | 944 | # Check for single part domain name, ie http://spweb as this will result in $partfqdn value of -1 945 | if($partfqdn -lt 0) 946 | { 947 | $Hostname = $Hostname #No change since single name website 948 | } 949 | else 950 | { 951 | $Hostname = "*" + $Hostname.Substring($partfqdn) 952 | } 953 | 954 | # Loop through the service principal names and clean up the one matching the local SharePoint url 955 | 956 | for ($i = 0; $i -lt $app.ServicePrincipalNames.count; $i++) 957 | { 958 | if($app[$i] -match $Hostname) 959 | { 960 | $app.ServicePrincipalNames.RemoveAt($i) 961 | } 962 | } 963 | 964 | Set-MsolServicePrincipal -AppPrincipalId $app.AppPrincipalId -ServicePrincipalNames $app.ServicePrincipalNames 965 | 966 | # Remove the ACS Proxy - will remove them all so be careful 967 | Get-SPServiceApplicationProxy | ? {$_.TypeName -eq "Azure Access Control Service Application Proxy"} | Remove-SPServiceApplicationProxy 968 | Update-WizardProgress "Azure ACS Proxy has been removed" 969 | 970 | #Remove the TrustedSecurityTokenIssuer based on metadata endpoint 971 | Get-SPTrustedSecurityTokenIssuer |?{$_.MetadataEndPoint -eq "https://accounts.accesscontrol.windows.net/metadata/json/1/"} | Remove-SPTrustedSecurityTokenIssuer 972 | 973 | Update-WizardProgress "Trusted Security Token Issuer has been removed" 974 | } 975 | 976 | ########################################## 977 | # WARMS UP THE ROOT SITE # 978 | # After IISRESET # 979 | ########################################## 980 | function Warmup-SPSite() 981 | { 982 | $Warmup = get-spsite -Limit 1 983 | $warmupurl = $warmup.Url 984 | 985 | Update-WizardProgress "Warming up site $warmupurl after IISRESET" 986 | Write-Host "Warming up site $warmupurl after IISRESET" 987 | 988 | $WarmItUp = Invoke-WebRequest -Uri $warmupurl -UseDefaultCredentials 989 | } 990 | 991 | #endregion 992 | 993 | ###################################################################### 994 | # mainflow # 995 | # Main program execution flow # 996 | ###################################################################### 997 | function mainflow() 998 | { 999 | 1000 | $spsite= "" 1001 | $spoappid="00000003-0000-0ff1-ce00-000000000000" 1002 | $Update = "" 1003 | $wizstatus=$true 1004 | $wizstatusmsg = "" 1005 | ############################################################# 1006 | # CHECK IF CURRENT USER IS A LOCAL ADMIN ON ALL FARM SERVERS# 1007 | # REQUIRED # 1008 | ############################################################# 1009 | 1010 | $Isboxadmin = Check-IsLocalAdmin 1011 | 1012 | If($Isboxadmin -eq $false) 1013 | { 1014 | Update-WizardProgress "Is User Local Admin returns FALSE" 1015 | Show-MessageBox "You are not logged in as a Local Machine administrator account.`nPlease ensure you are logged in with an account that has local machine admin rights and is a SharePoint Farm Administrator then re-start this wizard`n`nThe Hybrid Wizard will now Exit!`n" -Critical | out-null 1016 | #Show-MessageBox "Wizard will now exit!" | out-null 1017 | $wizstatus=$false 1018 | $wizstatusmsg = "`nLocal Admin Check Failed" 1019 | } 1020 | Else 1021 | { 1022 | Show-MessageBox "Current User is Local Machine Admin`nPlease ensure the user is a local admin on all other farm servers before proceeding" | out-null 1023 | Update-WizardProgress "Is User Local Admin returns TRUE" 1024 | } 1025 | 1026 | ################################################ 1027 | #CHECK CURRENT USER IS A MEMBER OF FARM ADMINS.# 1028 | #IF NOT THE DISPLAY LIST OF ADMINS AND EXIT # 1029 | # REQUIRED # 1030 | ################################################ 1031 | 1032 | $IsFarmAdmin = Check-FarmAdmin 1033 | if($IsFarmAdmin){} 1034 | else 1035 | { 1036 | $farmadmins = Get-SPfarmAdministrators | ? {$_.Name -notmatch "BUILTIN"} 1037 | 1038 | $listoffarmadmins = "" 1039 | foreach ($farmadmin in $farmadmins) 1040 | { 1041 | $listoffarmadmins = $listoffarmadmins + $farmadmin.Name + "`n" 1042 | } 1043 | Update-WizardProgress "Is User Farm Admin returns FALSE" 1044 | Show-MessageBox "You are not logged in as a farm administrator account. Please login as one of the following accounts and rerun this wizard `n`n$listoffarmadmins" -Critical | out-null 1045 | 1046 | $wizstatus=$false 1047 | $wizstatusmsg = $wizstatusmsg + "`nFarm Admin Check Failed" 1048 | #Show-MessageBox "Wizard will now exit!" | out-null 1049 | #break 1050 | } 1051 | Update-WizardProgress "Is User Farm Admin returns TRUE" 1052 | 1053 | ####################################################### 1054 | #VALIDATE ALL REQUIRED SERVICE APPLICATIONS ARE ONLINE# 1055 | #IF NOT THE DISPLAY LIST OF APP STATUSES AND QUIT # 1056 | # REQUIRED # 1057 | ####################################################### 1058 | 1059 | $validateserviceapps = Validate-ServiceApps 1060 | 1061 | Update-WizardProgress $validateserviceapps[1] 1062 | if($validateserviceapps[0] -eq 0) 1063 | { 1064 | try 1065 | { 1066 | #$MainForm.Close() 1067 | Update-WizardProgress "Service Application minimum configuration is not setup correctly" 1068 | $wizstatus=$false 1069 | $wizstatusmsg = $wizstatusmsg + "`nService Application Check Failed " 1070 | } 1071 | catch [Exception] { } 1072 | } 1073 | Update-WizardProgress "All Service Application minimum requirements are met" 1074 | 1075 | 1076 | ####################################################### 1077 | #CHECK FOR MSOL AND IDCRL INSTALLED # 1078 | #REQUIREMENTs .NET 3.5SP1 .NET 4.5 # 1079 | # REQUIRED # 1080 | ####################################################### 1081 | try 1082 | { 1083 | $prepareenv = prepare-environment 1084 | } 1085 | catch 1086 | { 1087 | Update-WizardProgress "Prerequisite Software not met. Exiting Wizard. Please refer to the pre requisites section of the documentation" 1088 | Write-Host "Prerequisite Software not met. Exiting Wizard. Please refer to the pre requisites section of the documentation" 1089 | $wizstatus=$false 1090 | $wizstatusmsg = $wizstatusmsg + "`nPrerequisite Software Check Failed " 1091 | 1092 | #$MainForm.close() 1093 | #[environment]::exit(0) 1094 | #break 1095 | } 1096 | 1097 | 1098 | ####################################################### 1099 | # Check if all Required Checks Passed or Failed # 1100 | # # 1101 | ####################################################### 1102 | 1103 | if($wizstatus -eq $false) 1104 | { 1105 | Update-WizardProgress $wizstatusmsg 1106 | Write-Host $wizstatusmsg 1107 | Show-MessageBox "Required Checks Failed`n$wizstatusmsg `nThe wizard cannot continue until these errors are remediated" -Critical 1108 | 1109 | $mainform.close() 1110 | 1111 | #[environment]::exit(0) 1112 | pause 1113 | } 1114 | 1115 | 1116 | ####################################################### 1117 | #IMPORT MSOL AND IDCRL MODULES # 1118 | #CONNECT TO O365 TENANT # 1119 | ####################################################### 1120 | 1121 | $connect = Import-ModulesAndConnect 1122 | 1123 | if ($connect[0] -eq $true) { Update-WizardProgress "continue login success" } 1124 | else { Update-WizardProgress "quit failed login" } 1125 | 1126 | ####################################################### 1127 | #VALIDATE MSOLDOMAIN # 1128 | #The $SharePointWeb will match the tenant root site # 1129 | ####################################################### 1130 | 1131 | $SharePointWeb = Validate-MSOLDomain 1132 | 1133 | if($SharePointWeb -eq "") { break } #Started seeing some odd WCF errors causing blank Urls and we must stop if this happens 1134 | 1135 | # We can test for clean up here since $SharePointWeb will match the SPN we want to remove (hopefully) 1136 | 1137 | ####################################################### 1138 | #REMOVE HYBRID CONFIG if Selected # 1139 | ####################################################### 1140 | 1141 | if($checkboxcleanuphybridstatus.checked) 1142 | { 1143 | Remove-HybridConfiguration $SharePointWeb 1144 | Update-WizardProgress "Hybrid Configuration Removed - Exiting Wizard" 1145 | Break 1146 | } 1147 | 1148 | ####################################################### 1149 | #MANAGE STS CERTIFICATE # 1150 | #Lot goes on here to set cert for ACS trust and SPN # 1151 | ####################################################### 1152 | 1153 | $spoappid="00000003-0000-0ff1-ce00-000000000000" 1154 | $CommonName = $textboxSelfSignedCertCN.Text 1155 | $stscertificate = Manage-STSCertificate $spoappid $SharePointWeb $CommonName 1156 | 1157 | ####################################################### 1158 | #WARM UP WEB APP # 1159 | #Hits the first site collection from get-spsite # 1160 | ####################################################### 1161 | 1162 | Warmup-spsite 1163 | 1164 | ####################################################### 1165 | #CREATE RESULT SOURCE # 1166 | #Uses Certificate Common Name as ResultSource Name # 1167 | #Uses Certificate Common Name as the Query Rule Name # 1168 | ####################################################### 1169 | 1170 | New-SCSearchResultSourceAndQueryRule $labelOnPremisesSharePoin.text $labelSPOTenantURL.Text $textboxSelfSignedCertCN.Text $textboxSelfSignedCertCN.Text 1171 | 1172 | Update-WizardProgress "Hybrid wizard setup is completed - Please test to validate success" 1173 | 1174 | $buttonStart.Enabled=$true 1175 | $buttonStart.Text = "Exit Wizard" 1176 | #ALL DONE 1177 | 1178 | #GUI 1179 | #Things to Capture 1180 | #LocalCN for SelfSignedCert 1181 | #Use New SelfSigned STS Cert or Use Existing STS Cert or public 1182 | #On Premises Site Url 1183 | #SPO Url of Tenant 1184 | #Check for Farm Account and Local Admin or prompt for admin creds 1185 | } 1186 | 1187 | #region Generate Wizard Form 1188 | 1189 | Add-Type -AssemblyName System.Windows.Forms 1190 | 1191 | #region Generated Form Objects 1192 | #---------------------------------------------- 1193 | [System.Windows.Forms.Application]::EnableVisualStyles() 1194 | $MainForm = New-Object 'System.Windows.Forms.Form' 1195 | $groupbox1 = New-Object 'System.Windows.Forms.GroupBox' 1196 | $radiobuttonUsePublicAuthoritySi = New-Object 'System.Windows.Forms.RadioButton' 1197 | $radiobuttonUseNewSelfSignedSTSC = New-Object 'System.Windows.Forms.RadioButton' 1198 | $radiobuttonUseBuiltInSharePoint = New-Object 'System.Windows.Forms.RadioButton' 1199 | $labelOnPremisesSharePoint = New-Object 'System.Windows.Forms.Label' 1200 | $labelSPOTenantURLegHttpsw = New-Object 'System.Windows.Forms.Label' 1201 | $labelSPOTenantURL = New-Object 'System.Windows.Forms.Label' 1202 | $labelOnPremisesSharePoin = New-Object 'System.Windows.Forms.Label' 1203 | $textboxSelfSignedCertCN = New-Object 'System.Windows.Forms.TextBox' 1204 | $textboxPubAuthSignedCertCN = New-Object 'System.Windows.Forms.TextBox' 1205 | $labelHybridConfigurationW = New-Object 'System.Windows.Forms.Label' 1206 | $buttonStart = New-Object 'System.Windows.Forms.Button' 1207 | $InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState' 1208 | $textboxWizardProgress = New-Object 'System.Windows.Forms.TextBox' 1209 | $checkboxcleanuphybridstatus = new-object 'System.Windows.Forms.CheckBox' 1210 | $labelcleanuphybridstatus = new-object 'System.Windows.Forms.Label' 1211 | $labelcontactinfo = new-object 'System.Windows.Forms.Label' 1212 | 1213 | #endregion Generated Form Objects 1214 | 1215 | #---------------------------------------------- 1216 | # User Generated Script 1217 | #---------------------------------------------- 1218 | 1219 | $OnLoadFormEvent={ 1220 | #TODO: Initialize Form Controls here 1221 | $MainForm.Focused 1222 | } 1223 | 1224 | $Form_FormClosing={ 1225 | # Capture form closing event ie user clicked red X. Prompt for validation and cancel event if user has exietd by mistake 1226 | 1227 | If ($wizstatus -eq $false) 1228 | { 1229 | #Pre requisites failed so kill form 1230 | [environment]::exit(0) 1231 | } 1232 | 1233 | $closeme = Show-MessageBox "Do you want to close down the Wizard?" -YesNo 1234 | 1235 | If ($closeme -eq "Yes") {} 1236 | Else 1237 | { 1238 | $_.Cancel = $true # $_.Cancel actually cancels the FormClosing Event and so FormClosed never fires 1239 | Show-MessageBox "Carry on regardless" 1240 | } 1241 | } 1242 | 1243 | $buttonStart_Click={ 1244 | #$buttonStart.Text = "Exit Wizard" #debug 1245 | 1246 | if($buttonStart.Text -eq "Exit Wizard") 1247 | { 1248 | $MainForm.close() 1249 | [environment]::exit(0) 1250 | break 1251 | } 1252 | 1253 | $buttonStart.Text = "Running" 1254 | $buttonStart.Enabled=$false 1255 | mainflow 1256 | } 1257 | 1258 | $buttonStart_MouseHover={ 1259 | $buttonStart.BackColor = 'Blue' 1260 | } 1261 | 1262 | $Form_StateCorrection_Load= 1263 | { 1264 | #Correct the initial state of the form to prevent the .Net maximized form issue 1265 | $MainForm.WindowState = $InitialFormWindowState 1266 | } 1267 | 1268 | $Form_StoreValues_Closing= 1269 | { 1270 | #Store the control values 1271 | $script:MainForm_radiobuttonUsePublicAuthoritySi = $radiobuttonUsePublicAuthoritySi.Checked 1272 | $script:MainForm_radiobuttonUseNewSelfSignedSTSC = $radiobuttonUseNewSelfSignedSTSC.Checked 1273 | $script:MainForm_radiobuttonUseBuiltInSharePoint = $radiobuttonUseBuiltInSharePoint.Checked 1274 | $script:MainForm_textbox1 = $textbox1.Text 1275 | } 1276 | 1277 | $Form_Cleanup_FormClosed= 1278 | { 1279 | #Remove all event handlers from the controls 1280 | try 1281 | { 1282 | $radiobuttonUseBuiltInSharePoint.remove_CheckedChanged($radiobuttonUseBuiltInSharePoint_CheckedChanged) 1283 | $labelSPOTenantURLegHttpsw.remove_Click($labelSPOTenantURLegHttpsw_Click) 1284 | $buttonStart.remove_Click($buttonStart_Click) 1285 | $MainForm.remove_Load($OnLoadFormEvent) 1286 | $MainForm.remove_Load($Form_StateCorrection_Load) 1287 | $MainForm.remove_Closing($Form_StoreValues_Closing) 1288 | $MainForm.remove_FormClosed($Form_Cleanup_FormClosed) 1289 | } 1290 | catch [Exception] 1291 | { } 1292 | } 1293 | 1294 | #region Generated Form Code 1295 | #---------------------------------------------- 1296 | $MainForm.SuspendLayout() 1297 | $groupbox1.SuspendLayout() 1298 | # 1299 | #region MainForm 1300 | # 1301 | $MainForm.Controls.Add($groupbox1) 1302 | $MainForm.Controls.Add($labelOnPremisesSharePoint) 1303 | $MainForm.Controls.Add($labelSPOTenantURLegHttpsw) 1304 | $MainForm.Controls.Add($labelSPOTenantURL) 1305 | $MainForm.Controls.Add($labelOnPremisesSharePoin) 1306 | $MainForm.Controls.Add($labelHybridConfigurationW) 1307 | $MainForm.Controls.Add($buttonStart) 1308 | $MainForm.Controls.Add($textboxWizardProgress) 1309 | $MainForm.Controls.Add($checkboxcleanuphybridstatus) 1310 | $MainForm.Controls.Add($labelcleanuphybridstatus) 1311 | $Mainform.Controls.Add($labelcontactinfo) 1312 | $MainForm.Name = "MainForm" 1313 | $MainForm.StartPosition = 'CenterScreen' 1314 | $MainForm.Text = "Hybrid Configuration Wizard" + $HWVersion 1315 | $MainForm.add_Load($OnLoadFormEvent) 1316 | $MainForm.Size = "650,650" 1317 | # 1318 | #endregion Mainform 1319 | 1320 | #region groupbox1 1321 | # 1322 | $groupbox1.Controls.Add($radiobuttonUsePublicAuthoritySi) 1323 | $groupbox1.Controls.Add($radiobuttonUseNewSelfSignedSTSC) 1324 | $groupbox1.Controls.Add($radiobuttonUseBuiltInSharePoint) 1325 | $groupbox1.Controls.Add($textboxSelfSignedCertCN) 1326 | $groupbox1.Controls.Add($textboxPubAuthSignedCertCN) 1327 | $groupbox1.Location = '13, 193' 1328 | $groupbox1.Name = "groupbox1" 1329 | $groupbox1.Size = '538, 138' 1330 | $groupbox1.TabIndex = 6 1331 | $groupbox1.TabStop = $False 1332 | $groupbox1.Text = "STS Certificate Replacement" 1333 | # 1334 | # radiobuttonUsePublicAuthoritySi 1335 | # 1336 | $radiobuttonUsePublicAuthoritySi.Font = "Microsoft Sans Serif, 8pt" 1337 | $radiobuttonUsePublicAuthoritySi.Location = '15, 87' 1338 | $radiobuttonUsePublicAuthoritySi.Name = "radiobuttonUsePublicAuthoritySi" 1339 | $radiobuttonUsePublicAuthoritySi.Size = '270, 24' 1340 | $radiobuttonUsePublicAuthoritySi.TabIndex = 5 1341 | $radiobuttonUsePublicAuthoritySi.TabStop = $True 1342 | $radiobuttonUsePublicAuthoritySi.Text = "Use Public Authority Signed STS Cert" 1343 | $radiobuttonUsePublicAuthoritySi.UseVisualStyleBackColor = $True 1344 | $radiobuttonUsePublicAuthoritySi.Enabled = $False 1345 | # 1346 | # radiobuttonUseNewSelfSignedSTSC 1347 | # 1348 | $radiobuttonUseNewSelfSignedSTSC.Font = "Microsoft Sans Serif, 8pt" 1349 | $radiobuttonUseNewSelfSignedSTSC.Location = '15, 56' 1350 | $radiobuttonUseNewSelfSignedSTSC.Name = "radiobuttonUseNewSelfSignedSTSC" 1351 | $radiobuttonUseNewSelfSignedSTSC.Size = '270, 24' 1352 | $radiobuttonUseNewSelfSignedSTSC.TabIndex = 4 1353 | $radiobuttonUseNewSelfSignedSTSC.TabStop = $True 1354 | $radiobuttonUseNewSelfSignedSTSC.Text = "Use New Self Signed STS Cert" 1355 | $radiobuttonUseNewSelfSignedSTSC.UseVisualStyleBackColor = $True 1356 | $radiobuttonUseNewSelfSignedSTSC.Checked = $True 1357 | # 1358 | # radiobuttonUseBuiltInSharePoint 1359 | # 1360 | $radiobuttonUseBuiltInSharePoint.Font = "Microsoft Sans Serif, 8pt" 1361 | $radiobuttonUseBuiltInSharePoint.Location = '15, 26' 1362 | $radiobuttonUseBuiltInSharePoint.Name = "radiobuttonUseBuiltInSharePoint" 1363 | $radiobuttonUseBuiltInSharePoint.Size = '270, 24' 1364 | $radiobuttonUseBuiltInSharePoint.TabIndex = 3 1365 | $radiobuttonUseBuiltInSharePoint.TabStop = $True 1366 | $radiobuttonUseBuiltInSharePoint.Text = "Use Built In SharePoint STS Cert" 1367 | $radiobuttonUseBuiltInSharePoint.UseVisualStyleBackColor = $True 1368 | $radiobuttonUseBuiltInSharePoint.add_CheckedChanged($radiobuttonUseBuiltInSharePoint_CheckedChanged) 1369 | # 1370 | # textboxNewSelfSignedCertCN 1371 | # 1372 | $textboxSelfSignedCertCN.Font = "Microsoft Sans Serif, 8pt" 1373 | $textboxSelfSignedCertCN.Location = '300, 56' 1374 | $textboxSelfSignedCertCN.Name = "textboxSelfSignedCertCN" 1375 | $textboxSelfSignedCertCN.Size = '200, 20' 1376 | $textboxSelfSignedCertCN.TabIndex = 8 1377 | $textboxSelfSignedCertCN.Text = "HybridWizard" 1378 | # 1379 | # textboxPubAuthSignedCertCN 1380 | # 1381 | $textboxPubAuthSignedCertCN.Font = "Microsoft Sans Serif, 8pt" 1382 | $textboxPubAuthSignedCertCN.Location = '300, 87' 1383 | $textboxPubAuthSignedCertCN.Name = "textboxPubAuthSignedCertCN" 1384 | $textboxPubAuthSignedCertCN.Size = '200, 20' 1385 | $textboxPubAuthSignedCertCN.TabIndex = 7 1386 | $textboxPubAuthSignedCertCN.Text = "Coming Soon" 1387 | $textboxPubAuthSignedCertCN.Enabled = $False 1388 | # 1389 | # labelOnPremisesSharePoint 1390 | # 1391 | $labelOnPremisesSharePoint.Font = "Microsoft Sans Serif, 8pt" 1392 | $labelOnPremisesSharePoint.Location = '12, 136' 1393 | $labelOnPremisesSharePoint.Name = "labelOnPremisesSharePoint" 1394 | $labelOnPremisesSharePoint.Size = '228, 38' 1395 | $labelOnPremisesSharePoint.TabIndex = 5 1396 | $labelOnPremisesSharePoint.Text = "On Premises SharePoint Url" 1397 | # 1398 | # labelSPOTenantURLegHttpsw 1399 | # 1400 | $labelSPOTenantURLegHttpsw.Font = "Microsoft Sans Serif, 8pt" 1401 | $labelSPOTenantURLegHttpsw.Location = '12, 95' 1402 | $labelSPOTenantURLegHttpsw.Name = "labelSPOTenantURLegHttpsw" 1403 | $labelSPOTenantURLegHttpsw.Size = '228, 38' 1404 | $labelSPOTenantURLegHttpsw.TabIndex = 4 1405 | $labelSPOTenantURLegHttpsw.Text = "SPO Tenant URL" 1406 | #$labelSPOTenantURLegHttpsw.add_Click($labelSPOTenantURLegHttpsw_Click) 1407 | # 1408 | # labelSPOTenantURL 1409 | # 1410 | $labelSPOTenantURL.Font = "Microsoft Sans Serif, 8pt" 1411 | $labelSPOTenantURL.Location = '246, 95' 1412 | $labelSPOTenantURL.Name = "labelSPOTenantURL" 1413 | $labelSPOTenantURL.Size = '260, 20' 1414 | $labelSPOTenantURL.TabIndex = 3 1415 | $labelSPOTenantURL.Text = "Not Connected Yet" 1416 | # 1417 | # labelOnPremisesSharePoin 1418 | # 1419 | $labelOnPremisesSharePoin.Font = "Microsoft Sans Serif, 8pt" 1420 | $labelOnPremisesSharePoin.Location = '246, 130' 1421 | $labelOnPremisesSharePoin.Name = "labelOnPremisesSharePoin" 1422 | $labelOnPremisesSharePoin.Size = '260, 20' 1423 | $labelOnPremisesSharePoin.TabIndex = 6 1424 | $labelOnPremisesSharePoin.Text = "Not Connected Yet" 1425 | # 1426 | # labelHybridConfigurationW 1427 | # 1428 | $labelHybridConfigurationW.Font = "Microsoft Sans Serif, 15.75pt" 1429 | $labelHybridConfigurationW.Location = '12, 9' 1430 | $labelHybridConfigurationW.Name = "labelHybridConfigurationW" 1431 | $labelHybridConfigurationW.Size = '543, 58' 1432 | $labelHybridConfigurationW.TabIndex = 2 1433 | $labelHybridConfigurationW.Text = "Hybrid Configuration Wizard" 1434 | $labelHybridConfigurationW.TextAlign = 'MiddleCenter' 1435 | # 1436 | # labelcleanuphybridstatus 1437 | # 1438 | $labelcleanuphybridstatus.Font = "Microsoft Sans Serif, 8pt" 1439 | $labelcleanuphybridstatus.ForeColor = "Red" 1440 | $labelcleanuphybridstatus.Location = '60,350' 1441 | $labelcleanuphybridstatus.Size = '500,58' 1442 | $labelcleanuphybridstatus.TabIndex = 10 1443 | $labelcleanuphybridstatus.Text = "Select this box to Cleanup Existing Hybrid Config (Coming Soon)" 1444 | #$labelcleanuphybridstatus.TextAlign = 'Left' 1445 | # $labelcleanuphybridstatus.Enabled = $false 1446 | # 1447 | # checkboxcleanuphybridstatus 1448 | $checkboxcleanuphybridstatus.Font = "Microsoft Sans Serif, 8pt" 1449 | $checkboxcleanuphybridstatus.Location = '30,350' 1450 | # 1451 | $checkboxcleanuphybridstatus.Size = '20,20' 1452 | $checkboxcleanuphybridstatus.TabIndex = 10 1453 | $checkboxcleanuphybridstatus.Enabled = $false 1454 | # 1455 | # textboxWizardProgress 1456 | # 1457 | $textboxWizardProgress.Font = "Microsoft Sans Serif, 8pt" 1458 | $textboxWizardProgress.Location = '13, 390' 1459 | $textboxWizardProgress.Name = "textboxWizardProgress" 1460 | $textboxWizardProgress.Size = '543, 150' 1461 | $textboxWizardProgress.TabIndex = 2 1462 | $textboxWizardProgress.Text = "Hybrid Configuration Wizard Progress`r`n" 1463 | $textboxWizardProgress.TextAlign = 'Left' 1464 | $textboxWizardProgress.Multiline = $true 1465 | $textboxWizardProgress.ScrollBars = "Vertical" 1466 | $textboxWizardProgress.AcceptsReturn = "true" 1467 | $textboxWizardProgress.WordWrap = "true" 1468 | $textboxWizardProgress.AutoScrollOffset = 1 1469 | # 1470 | # buttonStart 1471 | # 1472 | $buttonStart.Location = '268, 550' 1473 | $buttonStart.Name = "buttonStart" 1474 | $buttonStart.Size = '75, 20' 1475 | $buttonStart.TabIndex = 0 1476 | $buttonStart.Text = "Start" 1477 | $buttonStart.UseVisualStyleBackColor = $True 1478 | $buttonStart.add_Click($buttonStart_Click) 1479 | $buttonStart.Cursor = "Hand" 1480 | $groupbox1.ResumeLayout() 1481 | $MainForm.ResumeLayout() 1482 | 1483 | # 1484 | #Contact Info 1485 | # 1486 | $labelcontactinfo 1487 | $labelcontactinfo.Font = "Microsoft Sans Serif, 10pt" 1488 | $labelcontactinfo.ForeColor = "Red" 1489 | $labelcontactinfo.Location = '20,580' 1490 | $labelcontactinfo.Size = '500,58' 1491 | $labelcontactinfo.TabIndex = 12 1492 | $labelcontactinfo.Text = "Send feedback via the comments on the blog at (https://blogs.msdn.com/spses)" 1493 | 1494 | 1495 | #Save the initial state of the form 1496 | $InitialFormWindowState = $MainForm.WindowState 1497 | #Init the OnLoad event to correct the initial state of the form 1498 | $MainForm.add_Load($Form_StateCorrection_Load) 1499 | #Clean up the control events 1500 | $MainForm.add_FormClosed($Form_Cleanup_FormClosed) 1501 | #Store the control values when form is closing 1502 | $MainForm.add_Closing($Form_FormClosing) 1503 | #Show the Form 1504 | return $MainForm.ShowDialog() 1505 | #endregion Generated Form Code 1506 | #endregion Generate Wizard Form --------------------------------------------------------------------------------