Import-module AzureRM.profile 
Import-module AzureRM.Resources
Import-module Microsoft.PowerShell.Security
Import-module Microsoft.PowerShell.Utility
Import-module SharePointPnPPowerShellOnline -DisableNameChecking -Force
Import-Module MSOnline
try {
    Import-module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
} catch {
    Throw "Importing the Microsoft.Online.SharePoint.Powershell Module failed. Try uninstalling and installing the SharePoint Online Management Shell, and then restart PowerShell."
}

$moduletest = get-installedmodule AzureAD -ErrorAction SilentlyContinue
if ($moduletest -ne $null) {
    Import-Module AzureAD -NoClobber
} else {
    Import-Module AzureADPreview -NoClobber
}

$waitVeryLong = 20
$waitLong = 10
$waitShort = 5
$UserAgentString = "ISV|Wizdom|WizdomIntranet/1.0"

Function Write-WizdomHost () #Helper Function: write formatted output
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateSet('PROCESS', 'PROCESSATTENTION', 'OK', 'WARNING', 'ERROR')]$messageType,
        [Parameter(Mandatory=$false)]
        [String]$message,
        [Parameter(Mandatory=$false)]
        [int]$outputMaxLength,
        [Parameter(Mandatory=$false)]
        [String]$afterOutputMessage,
        [Parameter(Mandatory=$false)]
        [int]$initialStringLength

    )
        switch ($messageType) {
        PROCESS {
            if ($WhatIfPreference) {
                Write-Host $message -ForegroundColor DarkGray
            } else {
                Write-Host $message -ForegroundColor White -NoNewline
            }
            return $message.Length
        }
        PROCESSATTENTION {
            if ($WhatIfPreference) {
                Write-Host $message -ForegroundColor DarkYellow
            } else {
                Write-Host $message -ForegroundColor Yellow -NoNewline
            }
            return $message.Length
        }
        OK {
            if (-not $WhatIfPreference) {
                if ($message -ne "") {
                    Write-Host $message -ForegroundColor Yellow -NoNewline
                }
                Write-Host ("." * [math]::max(($outputMaxLength - $initialStringLength - $message.Length),0)) -ForegroundColor White -NoNewline
                Write-Host "OK" -ForegroundColor Green
            }
        }
        WARNING {
            if (-not $WhatIfPreference) {
                if ($message -ne "") {
                    Write-Host $message -ForegroundColor Yellow -NoNewline
                }
                Write-Host ("." * [math]::max(($outputMaxLength - $initialStringLength - $message.Length - 5),0)) -ForegroundColor White -NoNewline
                Write-Host "WARNING" -ForegroundColor Yellow
                if ($afterOutputMessage -ne "") {
                    Write-Host $afterOutputMessage -ForegroundColor White            
                }
            }
        }
        ERROR {
            if (-not $WhatIfPreference) {
                if ($message -ne "") {
                    Write-Host $message -ForegroundColor Red -NoNewline
                }
                Write-Host ("." * [math]::max(($outputMaxLength - $initialStringLength - $message.Length - 3),0)) -ForegroundColor White -NoNewline
                Write-Host "ERROR" -ForegroundColor Red
                if ($afterOutputMessage -ne "") {
                    Write-Host $afterOutputMessage -ForegroundColor White
                }
            }
        }
    }
}    

Function pause ($message = "Press any key to continue...") #Helper Function: "Press anykey to continue"
{
    # Check if running in PowerShell ISE
    If ($psISE) {
        # "ReadKey" not supported in PowerShell ISE.
        # Show MessageBox UI
        $Shell = New-Object -ComObject "WScript.Shell"
        $Button = $Shell.Popup("Click OK to continue.", 0, "Hello", 0)
        Return
    } else {
 
    $Ignore =
        16,  # Shift (left or right)
        17,  # Ctrl (left or right)
        18,  # Alt (left or right)
        20,  # Caps lock
        91,  # Windows key (left)
        92,  # Windows key (right)
        93,  # Menu key
        144, # Num lock
        145, # Scroll lock
        166, # Back
        167, # Forward
        168, # Refresh
        169, # Stop
        170, # Search
        171, # Favorites
        172, # Start/Home
        173, # Mute
        174, # Volume Down
        175, # Volume Up
        176, # Next Track
        177, # Previous Track
        178, # Stop Media
        179, # Play
        180, # Mail
        181, # Select Media
        182, # Application 1
        183  # Application 2
 
        Write-Host -NoNewline $Message
        While ($KeyInfo.VirtualKeyCode -Eq $Null -Or $Ignore -Contains $KeyInfo.VirtualKeyCode) {
            $KeyInfo = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown")
        }
    }
}

Function Get-RandomCharacters($length, $characters) #Helper Function: Generate number of random characters from array
{ 
    $random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length } 
    $private:ofs="" 
    return [String]$characters[$random]
}

Function ConvertTo-ScrambledString([string]$inputString) #Helper Function: Scrample inputstring
{     
    $characterArray = $inputString.ToCharArray()   
    $scrambledStringArray = $characterArray | Get-Random -Count $characterArray.Length     
    $outputString = -join $scrambledStringArray
    return $outputString 
}

Function Get-RandomPassword() #Helper Function: Generate random password. Parameters define complexity
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
   [Parameter(Mandatory=$false)]
   [int]$lowercaseChars = 5,
      [Parameter(Mandatory=$false)]
   [int]$uppercaseChars = 5,
      [Parameter(Mandatory=$false)]
   [int]$numbers = 2,
      [Parameter(Mandatory=$false)]
   [int]$specialChars = 3

    )

    $password = Get-RandomCharacters -length $lowercaseChars -characters 'abcdefghijklmnopqrstuvwxyz'
    $password += Get-RandomCharacters -length $uppercaseChars -characters 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    $password += Get-RandomCharacters -length $numbers -characters '1234567890'
    #2018-11-19 Christoffer: Removed § as it's not allowed in o365 passwords
    $password += Get-RandomCharacters -length $specialChars -characters '!$%&/()=?}][{@#*+-:'
    $password = (Get-RandomCharacters -length 1 -characters 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890').ToString() + (ConvertTo-ScrambledString($password)).ToString()
    return $password
}

<#Function CheckSiteExists() #Helper Function: Checks if web exists on SharePoint - returns $true if so.
{
    [CmdletBinding(SupportsShouldProcess=$True)]
	param(
		[Parameter(Mandatory=$true)][string]$url,
        [Parameter(Mandatory=$true)][Microsoft.SharePoint.Client.SharePointOnlineCredentials]$credentials
    )
    try {
        $context = New-Object Microsoft.SharePoint.Client.ClientContext($url)
        $context.Credentials = $credentials 
        $context.add_ExecutingWebRequest({
            param($Source, $EventArgs)
            $request = $EventArgs.WebRequestExecutor.WebRequest
            $request.UserAgent = $UserAgentString
        })
                    
        $web = $context.Web            
        $context.Load($web) 
        csomExecuteWithRetry $context
        return $true
    }
    catch {
        if ($_.Exception.InnerException.Response.StatusCode -eq "Unauthorized" -or $_.FullyQualifiedErrorId -eq "ServerUnauthorizedAccessException") {
            return $true
        } else {
            return $false
            return $_
        }
    }
    finally {
        $context.Dispose()
    }
}#>

<#Function ActivatePublishingFeatures () #Helper Function: Activates publishing features on SharePoint Site and Web
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$True)]
        [string]$webURL,
        [Parameter(Mandatory=$True)]
        [Microsoft.SharePoint.Client.SharePointOnlineCredentials]$credentials
    )

        $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($webURL)
        $ctx.Credentials = $credentials
        $ctx.add_ExecutingWebRequest({
            param($Source, $EventArgs)
            $request = $EventArgs.WebRequestExecutor.WebRequest
            $request.UserAgent = $UserAgentString
        })

        #get the subsite
        $site = $ctx.Site
        $web = $ctx.Web
        $ctx.Load($site)
        $ctx.Load($web)
        csomExecuteWithRetry $ctx

        #Feature GUID for SharePoint Server Publishing Infrastructure
        [Guid]$siteFeatureId = "f6924d36-2fa8-4f0b-b16d-06b7250180fa"
        
        #Feature GUID for SharePoint Server Publishing
        [Guid]$webFeatureId = "94c94ca6-b32f-4da9-a9e3-1f3d343d7ecb"
                        
        $siteFeatures = $ctx.Site.Features
        $webFeatures = $ctx.Web.Features
                                
        $ctx.Load($siteFeatures)
        $ctx.Load($webFeatures)

        #Added timeout just in case if the operation timeouts
        $ctx.RequestTimeout = -1
        csomExecuteWithRetry $ctx
                        
        $result = $siteFeatures.Add($siteFeatureId, $true, [Microsoft.SharePoint.Client.FeatureDefinitionScope]::None)
        $result = $webFeatures.Add($webFeatureId, $true, [Microsoft.SharePoint.Client.FeatureDefinitionScope]::None)
        csomExecuteWithRetry $ctx
        $ctx.Dispose()
}#>

function csomExecuteWithRetry () {
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$True)]
        [Microsoft.SharePoint.Client.ClientContext]$context
    )

    $queryExecuted = $false
    $retryCount = 0
    while (-not $queryExecuted) {
        try {
            $context.ExecuteQuery()
            $queryExecuted = $True
        } catch {
            if ($_.Exception.Response.StatusCode.value__ -eq 429 -or $_.Exception.Response.StatusCode.value__ -eq 503) {
                $retryCount++
                Start-Sleep -Seconds ($waitShort * $retryCount)
                $queryExecuted = $false
            } else {
                Throw
            }
            
        }
    }        


}

<#Function DeactivateMobileBrowserViewFeature () #Helper Function: Deactivates Mobile Browser View Feature on SharePoint Web
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$True)]
        [string]$webURL,
        [Parameter(Mandatory=$True)]
        [Microsoft.SharePoint.Client.SharePointOnlineCredentials]$credentials
    )

        $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($webURL)
        $ctx.Credentials = $credentials
        $ctx.add_ExecutingWebRequest({
            param($Source, $EventArgs)
            $request = $EventArgs.WebRequestExecutor.WebRequest
            $request.UserAgent = $UserAgentString
        })

        
        #get the subsite
        $web = $ctx.Web
        $ctx.Load($web)
        csomExecuteWithRetry $ctx

        #Feature GUID for Mobile Browser View
        [Guid]$webFeatureId = "d95c97f3-e528-4da2-ae9f-32b3535fbb59"
                        
        $webFeatures = $ctx.Web.Features
                                
        $ctx.Load($webFeatures)

        #Added timeout just in case if the operation timeouts
        $ctx.RequestTimeout = -1
        csomExecuteWithRetry $ctx
        
        if($webFeatures |? {$_.DefinitionId -eq $webFeatureId}){
            $result = $webFeatures.Remove($webFeatureId, $true)
            csomExecuteWithRetry $ctx
        }
        $ctx.Dispose()
}#>

<#Function Get-TenantSettings() #Gets information about the SharePoint Tenant - used to get url for app catalog
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$True)]
        [string]$sharepointURL,
        [Parameter(Mandatory=$true)]
        [Microsoft.SharePoint.Client.SharePointOnlineCredentials]$credentials
    )

    $Context = New-Object Microsoft.SharePoint.Client.ClientContext($sharepointURL)
    $Context.Credentials = $credentials
    $Context.add_ExecutingWebRequest({
        param($Source, $EventArgs)
        $request = $EventArgs.WebRequestExecutor.WebRequest
        $request.UserAgent = $UserAgentString
    })

    csomExecuteWithRetry $Context
    
    $restUrl = $sharepointURL + '/_api/SP_TenantSettings_Current'
    $AuthenticationCookie = $Context.Credentials.GetAuthenticationCookie($restUrl, $true)

    $WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
    $WebSession.Credentials = $Context.Credentials
    $WebSession.Cookies.SetCookies($restUrl, $AuthenticationCookie)
    $WebSession.Headers.Add("Accept", "application/json;odata=verbose")
    #$Result = Invoke-RestMethod -Method Get -WebSession $WebSession -Uri $RequestUrl


    $result = Invoke-RestMethod -Method Get -Uri $restUrl -WebSession $WebSession -TimeoutSec 30

    $Context.Dispose()
    
    return $result

}#>

function IsValidUrl([string] $url) #Used to determine if an URL is valid
{
    # Declare default return value
    $isValid = $false
   
    try
    {
        # Create a request object to "ping" the URL
        $request = [System.Net.WebRequest]::Create($url)
        $request.Method = "HEAD"
        $request.UseDefaultCredentials = $true
        $request.Timeout = 1000

        # Capture the response from the "ping"
        $response = $request.GetResponse()
        $httpStatus = $response.StatusCode
   
        # Check the status code to see if the URL is valid
        $isValid = ($httpStatus -eq "OK")
    }
    catch
    {
        # Write error log
        Write-Host $Error[0].Exception
    }
   
    return $isValid
}

function New-WizdomADApp () #Creates a new Azure AD App and returns the object representation, including added Status and Client Secret info.
{
[CmdletBinding(SupportsShouldProcess=$True)]
Param(
    [Parameter(Mandatory=$true)]
    [string]$applicationName,

    [Parameter(Mandatory=$true)]
    [string]$wizdomWebsiteUrl,

    [Parameter(Mandatory=$true)]
    [string]$siteCollectionUrl
)

    try {
        $appName = $applicationName 
        $appURI = $wizdomWebsiteUrl 
        $appHomePageUrl = $siteCollectionUrl 

        $appReplyURLs = @($appHomePageURL)
        $appReplyURLs += ($siteCollectionUrl -Split("sites/"))[0]
    
        if(!($myApp = Get-AzureADApplication -Filter "DisplayName eq '$($appName)'"  -ErrorAction SilentlyContinue))
        {
            $Guid = New-Guid
	        $startDate = Get-Date
	
	        $PasswordCredential = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordCredential
	        $PasswordCredential.StartDate = $startDate
	        #$PasswordCredential.EndDate = $startDate.AddYears(100)
	        $PasswordCredential.EndDate =  "12/30/2299 00:00:00"
            $PasswordCredential.KeyId = $Guid
	        $PasswordCredential.Value = ([System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($Guid))))+"="

            #Windows Azure Active Directory Permissions
	        $svcprincipalAD = Get-AzureADServicePrincipal -All $true | ? { $_.DisplayName -match "Windows Azure Active Directory" }

	        #Windows Azure Active Directory
	        $reqAzuread = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
	        $reqAzuread.ResourceAppId = $svcprincipalAD.AppId

	        ##Application Permissions
	        $appPermissionAD1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "5778995a-e1bf-45b8-affa-663a9f3f4d04","Role" #Read directory data

	        ##Delegated Permissions
	        $delPermissionAD1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "a42657d6-7f20-40e3-b6f0-cee03008a62a","Scope" #Read directory data
	        $delPermissionAD2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "6234d376-f627-4f0f-90e0-dff25c5211a3","Scope" #Read all groups
            $delPermissionAD3 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "311a71cc-e848-46a1-bdf8-97ff7156d8e6","Scope" #Sing you in and read your profile

	        $reqAzuread.ResourceAccess = $appPermissionAD1, $delPermissionAD1, $delPermissionAD2, $delPermissionAD3

            #Microsoft Graph Permissions
	        $svcprincipalGraph = Get-AzureADServicePrincipal -All $true | ? { $_.DisplayName -eq "Microsoft Graph" }

	        #Windows Azure Active Directory
	        $reqAzureGraph = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
	        $reqAzureGraph.ResourceAppId = $svcprincipalGraph.AppId

	        ##Application Permissions
	        $appPermissionGraph1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "19dbc75e-c2e2-444c-a770-ec69d8559fc7","Role" #Read and write directory data
   	        $appPermissionGraph2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "62a82d76-70ea-41e2-9197-370581804d09","Role" #Read and write all groups
            $appPermissionGraph3 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "332a536c-c7ef-4017-ab91-336970924f0d","Role" #Read items in all site collections (preview)
        
            #2Do People.Read  #Read all users' relevant people lists 


	        ##Delegated Permissions
	        $delPermissionGraph1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "205e70e5-aba6-4c52-a976-6d2d46c48043","Scope" #Read items in all site collections
            $delPermissionGraph2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "4e46008b-f24c-477d-8fff-7bb4ec7aafe0","Scope" #Read and write all groups
	        $reqAzureGraph.ResourceAccess = $appPermissionGraph1, $appPermissionGraph2, $appPermissionGraph3, $delPermissionGraph1, $delPermissionGraph2
    

	        $myApp = New-AzureADApplication -DisplayName $appName -IdentifierUris $appURI -Homepage $appHomePageUrl -ReplyUrls $appReplyURLs -PasswordCredentials $PasswordCredential -RequiredResourceAccess @($reqAzuread, $reqAzureGraph)

            $myapp | Add-Member -MemberType NoteProperty -Name AzureAdKey -Value  $($PasswordCredential.Value)
            $myapp | Add-Member -MemberType NoteProperty -Name CreationStatus -Value  $("Created")
        } else
        {
            $myapp | Add-Member -MemberType NoteProperty -Name AzureAdKey -Value ""
            $myapp | Add-Member -MemberType NoteProperty -Name CreationStatus -Value  $("NotCreated")	    
        }
    } catch {
        $myapp | Add-Member -MemberType NoteProperty -Name AzureAdKey -Value ""
        $myapp | Add-Member -MemberType NoteProperty -Name CreationStatus -Value  $("Error")
        write-host "Error in New-WizdomADApp: $($_.Exception.Message)" -foregroundcolor Red
        Write-Host $_.Exception.Message -ForegroundColor white
    } 
    return $myapp
} 
Function Grant-OAuth2PermissionsToApp () #Mimics "Grant Permissions" button when setting permissions on the AAD App
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    Param(
        [Parameter(Mandatory=$true)][string]$azureAppId, #application ID of the azure application you wish to admin-consent to
        [Parameter(Mandatory=$true)][string]$SharePointTenantAdmin,
        [Parameter(Mandatory=$true)][string]$apiToken
    )
    
    $header = @{
    'Authorization' = 'Bearer ' + $apiToken
    'X-Requested-With'= 'XMLHttpRequest'
    'x-ms-client-request-id'= [guid]::NewGuid()
    'x-ms-correlation-id' = [guid]::NewGuid()}
    $url = "https://main.iam.ad.ext.azure.com/api/RegisteredApplications/$azureAppId/Consent?onBehalfOfAll=true"
    do {
        try {Invoke-RestMethod –Uri $url –Headers $header –Method POST -ErrorAction Stop
            $completed = $true} catch {
            $completed = $false
            Start-Sleep -Seconds 10}
    } until ($completed)
}

function New-WizdomAppPackage  # Generates SharePoint App for Wizdom
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    Param(
      [Parameter(Mandatory=$true)]
       [string]$clientid,
	
       [Parameter(Mandatory=$true)]
       [string]$appurl,

       [AllowNull()]
       [string]$outfile = "Wizdom365.app",

       [AllowNull()]
       [string]$title = "Wizdom 365",

       [AllowNull()]
       [string]$name = "Wizdom365",

       [AllowNull()]
       [string]$productid = "6adc8642-831b-48dc-92cd-d3b4f40c56bb"
    )

    # Ensure no / after appurl
    $appurl = $appurl.TrimEnd('/')
    $packagename = "GUI.SP.App.app"

    #UNZIP
    $apppackagepath = $PSScriptRoot + "\util\" + $packagename
    #$apppackagepath = (Resolve-Path ("SharePointOnlineInstallationSupportFiles\util\" + $packagename)).Path
    Add-Type -assembly "system.io.compression.filesystem"
    $folder = $PSScriptRoot + "\appunzipped"
    #$folder = ((Resolve-Path ".").Path + "/appunzipped") 
    Remove-Item $folder -force -Recurse -ErrorAction SilentlyContinue
    #Remove-Item ((Resolve-Path ".").Path + "/appunzipped") -force -Recurse -ErrorAction SilentlyContinue
    [io.compression.zipfile]::ExtractToDirectory($apppackagepath, $folder)

    #Do replaces
    $s = Get-Content ($folder + "\AppManifest.xml")
    $s = $s -replace 'ClientId=".*?"', ('ClientId="' +  $clientid + '"')
    $s = $s -replace '<StartPage>https://wizdom365v2.azurewebsites.net', ('<StartPage>' + $appurl)
    if ($title -ne "") {$s = $s -replace '<Title>.*</Title>', ('<Title>' +  $title + '</Title>')}
    if ($name -ne "") {$s = $s -replace ' Name=".*?"', (' Name="' +  $name + '"')}
    if ($productid -ne "") {$s = $s -replace ' ProductID=".*?"', (' ProductID="' +  $productid + '"')}
    $s | Set-Content ($folder + "\AppManifest.xml")

    #ZIP
    $zipfiledest = $PSScriptRoot +  "\..\" + $outfile
    #$zipfiledest = (Resolve-Path ".").Path +  "/apppackagenew.app"
    If(Test-path $zipfiledest) {Remove-item $zipfiledest}

    # zip file created using "[io.compression.zipfile" won't work. zip.exe from info-zip seems to work (6+ hours used! )
    $currentFolder = (Resolve-Path ".").Path
    cd $folder
    $zip = $PSScriptRoot + "\util\zip.exe"
    &$zip -r $zipfiledest *.*
    #..\SharePointOnlineInstallationSupportFiles\util\zip.exe -r ("..\" + $outfile) *.*
    cd $currentFolder
    Remove-Item $folder -force -Recurse -ErrorAction SilentlyContinue
    #Remove-Item ((Resolve-Path ".").Path + "/appunzipped") -force -Recurse -ErrorAction SilentlyContinue

}

function Install-WizdomOnSitecollection #Emulates the 'Install' function in Wizdom Admin / Site Collections
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$sharePointUrl,
        [Parameter(Mandatory=$true)][String]$accessToken														
    )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken
        $restUrl = $WizdomUrl + "/api/wizdom/365/SitecollectionTasks/InstallWizdomOnSitecollection?sitecollectionUrl=" + [System.Web.HttpUtility]::UrlEncode($sharePointUrl) + "&scriptLoaderOnly=false"
        $InstallStatus = Invoke-RestMethod -Uri $restUrl -Method POST -Headers $httpHeader -TimeoutSec 600
        return $InstallStatus
    } catch {
        write-host "Error in Install-WizdomOnSitecollection: $($_.Exception.Message)" -foregroundcolor Red
        Write-Host $_.Exception.Message -ForegroundColor white
    } finally {
    }
}

function Get-AzureRmCachedAccessToken() # Gets the AzureRM login token used to generate the Wizdom REST Header
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param ()
    try {
        $ErrorActionPreference = 'Stop'
  
        if(-not (Get-Module AzureRm.Profile)) {
            Import-Module AzureRm.Profile
        }
        $azureRmProfileModuleVersion = (Get-Module AzureRm.Profile).Version
        # refactoring performed in AzureRm.Profile v3.0 or later
        if($azureRmProfileModuleVersion.Major -ge 3) {
            $azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
        if(-not $azureRmProfile.Accounts.Count) {
            Write-Error "Ensure you have logged in before calling this function."    
        }
        } else {
        # AzureRm.Profile < v3.0
            $azureRmProfile = [Microsoft.WindowsAzure.Commands.Common.AzureRmProfileProvider]::Instance.Profile
            if(-not $azureRmProfile.Context.Account.Count) {
                Write-Error "Ensure you have logged in before calling this function."    
            }
        }
  
        $currentAzureContext = Get-AzureRmContext
        $profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureRmProfile)
        Write-Debug ("Getting access token for tenant" + $currentAzureContext.Tenant.TenantId)
        $token = $profileClient.AcquireAccessToken($currentAzureContext.Tenant.TenantId)
        return "Bearer " + $token.AccessToken
    } catch {
        write-host "Error in Get-AzureRmCachedAccessToken: $($_.Exception.Message)" -foregroundcolor Red -Verbose:$VerbosePreference
    }
}

Function Get-WizdomHttpRESTHeader () #Creates the Bearer token and header used for calls to Wizdom APIs
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$accessToken,														 
        [Parameter(Mandatory=$false)][String]$UserName,
        [Parameter(Mandatory=$false)][String]$Password
    )
    try {
        #$token = Get-AzureRmCachedAccessToken -Verbose:$VerbosePreference
        $token = $accessToken

        $httpHeader = @{Authorization =($token)}
        $httpHeader.add("x-wizdom-rest", "true")

        if ($UserName -ne "") {
            $httpHeader.add("x-wizdom-rest-username", $UserName)
            $httpHeader.add("x-wizdom-rest-password", $Password)
        }

        return $httpHeader
    } catch {
        write-host "Error in Get-WizdomHttpRESTHeader: $($_.Exception.Message)" -foregroundcolor Red -Verbose:$VerbosePreference
    }
}

Function Get-WizdomAccessToken () #Creates the AccessToken required to access the Wizdom system
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$adTenant, # = "wtwiz.onmicrosoft.com"
        [Parameter(Mandatory=$true)][String]$sharepointTenant, # = "https://testspcool.sharepoint.com/";
        [Parameter(Mandatory=$true)][String]$adClientId, # = "<guid>"
        [Parameter(Mandatory=$true)][String]$adClientSecret, # = "secret"
        [Parameter(Mandatory=$true)][String]$username, # = "username@wtwiz.onmicrosoft.com"
        [Parameter(Mandatory=$true)][String]$userpassword #= "password"
    )
    try {
        $url = "https://login.microsoftonline.com/" + $adTenant + "/oauth2/token?api-version=1.0"
        $body = @{
            resource = $sharepointTenant
            grant_type = "password"
            username = $username
            password = $userpassword
            client_id = $adClientId # azure ad client id
            client_secret = $adClientSecret # azure ad client secret
        }
        #Write-Host "AD:" + $adTenant + " - SP:" + $sharepointTenant + " - UN:" + $username + " - UP:" + $userpassword + " - CI:" + $adClientId + " - CS:" + $adClientSecret    
        $response = Invoke-RestMethod –Uri $url -Method Post -Body $body -ContentType 'application/x-www-form-urlencoded'
        if ($response.access_token -eq "" -or $response.access_token -eq $null) {
            Write-Host "Error in Get-WizdomAccessToken: Cannot get accesstoken from AAD. API Response:" -ForegroundColor Red -Verbose:$VerbosePreference
            Write-Host $response
            return $null
            Throw
        } else {
            return ('Bearer ' + $response.access_token)
        }
    } catch {
        #write-host "Error in Get-WizdomAccessToken: $($_.Exception.Message)" -foregroundcolor Red -Verbose:$VerbosePreference
        return $null
        Throw
    }
}

function Set-WizdomPIN # Emulates the "Pair" button in Wizdom config center / Licenses
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$pin,
        [Parameter(Mandatory=$true)][String]$accessToken
    )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken


        $restUrl = $WizdomUrl + "/api/wizdom/365/license/pair"
        $PINStatus = Invoke-RestMethod -Uri $restUrl -ContentType "application/json; charset=utf-8" -Method POST -Headers $httpHeader -Body (convertto-json($pin)) -ErrorAction SilentlyContinue
        return $PINStatus
    } catch {
        return "PIN not accepted by license server"
    } finally {
    }

}

function Create-WizdomLinkCollectionCategory
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$LinkCollectionGuid,
        [Parameter(Mandatory=$true)][String]$accessToken,
        [Parameter(Mandatory=$true)][String]$Name
    )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken


        $restUrl = $WizdomUrl + "/api/wizdom/personalLink/categories/usercategory/add/" + $LinkCollectionGuid
        $body = '{"id":0,"name":"' + $Name + '","links":[]}'

        $CreateStatus = Invoke-RestMethod -Uri $restUrl -ContentType "application/json; charset=utf-8" -Method POST -Headers $httpHeader -Body $body -ErrorAction SilentlyContinue
        return $CreateStatus
    } catch {
        Write-Error $_
        return "Creation of category $($Name) failed."
    } finally {
    }

}

function Get-WizdomCorporateLinks
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$accessToken
    )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken

        $restUrl = $WizdomUrl + "/api/wizdom/personalLink/categories/list/corporate"

        $CorporateLinks = Invoke-RestMethod -Uri $restUrl -ContentType "application/json; charset=utf-8" -Method GET -Headers $httpHeader -ErrorAction SilentlyContinue
        return $CorporateLinks
    } catch {
        Write-Error $_
        return "Getting Corporate Links failed."
    } finally {
    }

}

function Add-WizdomLinkCorporateLinkToLinkCollection
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$LinkCollectionGuid,
        [Parameter(Mandatory=$true)][String]$accessToken,
        [Parameter(Mandatory=$true)][String]$JsonObject,
        [Parameter(Mandatory=$true)][String]$categoryId
    )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken


        $restUrl = $WizdomUrl + "/api/wizdom/personalLink/links/assign/" + $categoryId
        $body = '{"key":"'+ $LinkCollectionGuid + '","value":[' + $JsonObject + ']}'

        $CreateStatus = Invoke-RestMethod -Uri $restUrl -ContentType "application/json; charset=utf-8" -Method POST -Headers $httpHeader -Body $body -ErrorAction SilentlyContinue
        return $CreateStatus
    } catch {
        Write-Error $_
        return "Adding $($JsonObject.name) to $($LinkCollectionGuid) failed."
    } finally {
    }

}
 
function Get-WizdomLinkCollection
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$LinkCollectionGuid,
        [Parameter(Mandatory=$true)][String]$accessToken
    )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken

        $restUrl = $WizdomUrl + "/api/wizdom/personalLink/views/getoradd/$($LinkCollectionGuid)/true"

        $LinkCollection = Invoke-RestMethod -Uri $restUrl -ContentType "application/json; charset=utf-8" -Method GET -Headers $httpHeader -ErrorAction SilentlyContinue
        return $LinkCollection
    } catch {
        Write-Error $_
        return "Getting Link Collection $($LinkCollectionGuid) failed."
    } finally {
    }

}

function Order-WizdomLinkCollection
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$LinkCollectionGuid,
        [Parameter(Mandatory=$true)][String]$accessToken,
        [Parameter(Mandatory=$true)][String]$JsonObject
    )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken

        $restUrl = $WizdomUrl + "/api/wizdom/personalLink/categories/order/set/$($LinkCollectionGuid)/true"
    
        $OrderStatus = Invoke-RestMethod -Uri $restUrl -ContentType "application/json; charset=utf-8" -Method POST -Headers $httpHeader -Body $JsonObject -ErrorAction SilentlyContinue
        return $OrderStatus
    } catch {
        Write-Error $_
        return "Ordering $($LinkCollectionGuid) failed."
    } finally {
    }

}

Function Get-WizdomConfig () #Gets and parses current Wizdom configuration
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$accessToken
        )

    try {
        Write-Verbose "Downloading WizdomConfig."
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference

        $restUrl = $WizdomUrl + "/Base/Bundles/configuration.aspx?IncludeAttributes=true"

        $configItem = Invoke-RestMethod -Method Post -Uri $restUrl -ContentType "application/json; charset=UTF-8" -Headers $httpHeader -Verbose:$VerbosePreference -ErrorAction SilentlyContinue
        return $configItem.Substring(($configItem.IndexOf("var Wizdom365Config = ")+22),($configItem.IndexOf("};",$configItem.IndexOf("var Wizdom365Config = "))-22)) + "}"|ConvertFrom-Json

    } catch {
        write-host "Error in Get-WizdomConfig: $($_.Exception.Message)" -foregroundcolor Red -Verbose:$VerbosePreference
		Throw	 
    }
}

Function Publish-WizdomConfig () #Sends new configuration settings to the Wizdom server
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][PSObject]$configObject,
        [Parameter(Mandatory=$true)][String]$accessToken
        )

    try {
        Write-Verbose "Posting WizdomConfig."
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $httpHeader.Add("Accept-Encoding","gzip, deflate, br")

        $restUrl = $WizdomUrl + "/api/wizdom/365/configuration"
        $body = ConvertTo-Json($configObject) -Depth 10 -Compress
        $configSaved = Invoke-RestMethod -Method Post -Uri $restUrl  -ContentType "application/json; charset=UTF-8" -Headers $httpHeader -body $body -Verbose:$VerbosePreference -ErrorAction SilentlyContinue

    } catch {
        write-host "Error in Publish-WizdomConfig: $($_.Exception.Message)" -foregroundcolor Red -Verbose:$VerbosePreference
        Throw
    }
}

Function Set-WizdomdataStore () #Sets the Datastore URL and Owner in Wizdom config center / site collections
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][string]$dataStoreUrl,
        [Parameter(Mandatory=$true)][string]$dataStoreOwner,
        [Parameter(Mandatory=$true)][String]$accessToken
        )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference

        $restUrl = $WizdomUrl + "/api/wizdom/365/datastore/create?url=" + [System.Web.HttpUtility]::UrlEncode($dataStoreUrl) + "&ownerLogin=" + $dataStoreOwner.Replace("@","%40")
        $dataStoreUpdated = Invoke-RestMethod -Method Post -Uri $restUrl -ContentType "application/json; charset=UTF-8" -Headers $httpHeader -Verbose:$VerbosePreference
 
    } catch {
        write-host "Error in Set-WizdomDataStore: $($_.Exception.Message)" -foregroundcolor Red -Verbose:$VerbosePreference
		Throw	 
    }
}

function Get-WizdomInstallStatus #Gets the current status of an ongoing wizdom installation
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$siteCollectionId,
        [Parameter(Mandatory=$true)][String]$accessToken
    )

    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken
        $restUrl = $WizdomUrl + "/api/wizdom/365/SitecollectionTasks/AllTaskStatusPaging?skip=0&take=10"
        return (Invoke-RestMethod -Uri $restUrl -Method GET -Headers $httpHeader).sitecollections.where({$_.sitecollectionid -eq $siteCollectionId}).upgradestatus
    } catch {
        write-host "Error in Get-WizdomInstallStatus: $($_.Exception.Message)" -foregroundcolor Red
        write-host "Retry"
    } finally {
    }
}

function Get-PublishingProfileCredentials() #Function to get Publishing credentials for the WebApp
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)]
        [String]$resourceGroupName,
        [Parameter(Mandatory=$true)]
        [String]$webAppName
    )
    $resourceType = "Microsoft.Web/sites/config"
    $resourceName = "$webAppName/publishingcredentials"
    if ($PSCmdlet.ShouldProcess($resourceName, "Get")) {
        $publishingCredentials = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType $resourceType -ResourceName $resourceName -Action list -ApiVersion "2015-08-01" -Force
    }
    return $publishingCredentials
}

function Get-KuduApiAuthorisationHeaderValue() #Pulling authorization access token
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)]
        [String]$resourceGroupName,
        [Parameter(Mandatory=$true)]
        [String]$webAppName
    )
    $publishingCredentials = Get-PublishingProfileCredentials $resourceGroupName $webAppName -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
    return ("Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f 
    $publishingCredentials.Properties.PublishingUserName, $publishingCredentials.Properties.PublishingPassword))))
}

Function Ping-Wizdom () #queries the Wizdom config endpoint to check if Wizdom responds
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$accessToken
    )
    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $restUrl = $WizdomUrl + "/api/wizdom/365/license/ping"
        
        $WizdomLicense = Invoke-RestMethod -Uri $restUrl -Method GET -Headers $httpHeader -Verbose:$VerbosePreference -ErrorAction SilentlyContinue -TimeoutSec 5
        return $true
    } catch {
        return $false
    }
}


Function Import-WizdomZipPackage {
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [parameter(Mandatory=$true)][String]$fileName,
        [Parameter(Mandatory=$true)][String]$accessToken
    )
    try {
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $httpHeader.Add("Accept-Encoding","gzip, deflate, br")

        $fileBin = [IO.File]::ReadAllBytes($fileName)
        $enc = [System.Text.Encoding]::GetEncoding("ISO-8859-1")
        $fileEnc = $enc.GetString($fileBin)
        $boundary = [System.Guid]::NewGuid().ToString()
        $LF = "`r`n"

        $restUrl = $WizdomUrl + "/api/wizdom/exportimport/1/exportimport/ImportZip?"

        $bodyLines = (
            "--$boundary",
	        "Content-Disposition: form-data; name=`"file`"; filename=`"$fileName`"$LF",$fileEnc,
            "Content-Type: application/x-zip-compressed",
            "--$boundary--$LF") -join $LF

        $result = Invoke-RestMethod -Uri $restUrl -Method POST -Headers $httpHeader -ContentType "multipart/form-data; boundary=`"$boundary`""  -Body $bodyLines -Verbose:$VerbosePreference

        Write-Verbose "Clearing Wizdom Cache."
        $restUrl = $WizdomUrl + "/api/wizdom/365/cache/clear?"
        $result = Invoke-RestMethod -Uri $restUrl -Method GET -Headers $httpHeader -Verbose:$VerbosePreference 
    } catch {
        write-host "Error in Import-WizdomZipPackage: $($_.Exception.Message)" -foregroundcolor Red -Verbose:$VerbosePreference
    }

}

Function New-WizdomLightningPage () 
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$SharePointSiteMobile,
        [Parameter(Mandatory=$true)][String]$lightningPageContent,
        [Parameter(Mandatory=$true)][String]$accessToken
    )
    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $restUrl = $WizdomUrl + "/api/wizdom/LightningPages"
        $content = $lightningPageContent.Replace("`r`n","\n")
        $body ='{"url":"' + $SharePointSiteMobile + '/index.html","culture":"en-us","html":"' + $content.Replace("""","\""") + '","template":"custom","channelsetId":"","corpNewsUrl":"","peopleSearchResultSource":"b09a7990-05ea-4af9-81ef-edfab16c4e31"}'

        $WizdomConfig = Invoke-RestMethod -Uri $restUrl -Method POST -body $body -Headers $httpHeader -Verbose:$VerbosePreference -ContentType "application/json; charset=utf-8"
    } catch {
        Write-Host "Error in New-WizdomLightningpage: $($_.Exception.Message)" -ForegroundColor Red -Verbose:$VerbosePreference
        return $_
    }
}

Function New-WizdomCustomModule () 
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$mobileModuleName,
        [Parameter(Mandatory=$true)][String]$accessToken
    )
    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $restUrl = $WizdomUrl + "/api/wizdom/365/modules/partner" #?SPHostUrl=https%3A%2F%2Fwizdomtrial.sharepoint.com%2Fsites%2Fwizdommobileapp&SPLocale=en-us&WizdomVersion=6.31.2.0&cacheTimestamp=2018-09-28T09:06:07.9752773Z&SPCacheKey=&SPLanguage=en-US&SPClientTag=0&userLoginName=info@wizdomtrial.onmicrosoft.com&SPLocale=
        $body =('{"Enabled":false,"Icon":",inherit,inherit","Title":"' + $mobileModuleName + '","Version":"1","ModuleUrl":"' + $WizdomUrl + '/Pages/Administration.html","JsLink":"' + $WizdomUrl + '/Dist/app.js","CssLink":"' + $WizdomUrl + '/Dist/style.css"}')

        $WizdomConfig = Invoke-RestMethod -Uri $restUrl -Method POST -body $body -Headers $httpHeader -Verbose:$VerbosePreference -ContentType "application/json; charset=utf-8"
    } catch {
        Write-Host "Error in New-WizdomCustomModule: $($_.Exception.Message)" -ForegroundColor Red -Verbose:$VerbosePreference
            return $_
    }

}

Function Get-WizdomLanguages () {
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$accessToken
    )
    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $restUrl = $WizdomUrl + "/api/wizdom/365/languages"
        $WizdomLanguages = Invoke-RestMethod -Uri $restUrl -Method GET -Headers $httpHeader -Verbose:$VerbosePreference 
        return $WizdomLanguages
    } catch {
        Write-Host "Error in Get-WizdomLanguages: $($_.Exception.Message)" -ForegroundColor Red -Verbose:$VerbosePreference
        return $_
    }
}

function Set-WizdomLanguage () {
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$culture,
        [Parameter(Mandatory=$true)][String]$accessToken
    )
    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $restUrl = $WizdomUrl + "/api/wizdom/365/languages/" + $culture + "/activate" 
        $WizdomLanguages = Invoke-RestMethod -Uri $restUrl -Method PUT -Headers $httpHeader -Verbose:$VerbosePreference 
        return $WizdomLanguages
    } catch {
        Write-Host "Error in Set-WizdomLanguage: $($_.Exception.Message)" -ForegroundColor Red -Verbose:$VerbosePreference
        return $_
    }
}

function Set-WizdomModernPackageAssociation () {
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$accessToken
    )
    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $restUrl = $WizdomUrl + "/api/wizdom/365/ClassicModernDeploy/AssociateModernToWizdom" 
        $response = Invoke-RestMethod -Uri $restUrl -Method POST -Headers $httpHeader -Verbose:$VerbosePreference 
    } catch {
        Write-Host "Error in Set-WizdomModernPackageAssociation: $($_.Exception.Message)" -ForegroundColor Red -Verbose:$VerbosePreference
        Throw
    }
}

function Install-WizdomModernPackages () {
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$WizdomUrl,
        [Parameter(Mandatory=$true)][String]$accessToken
    )
    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
        $httpHeader = Get-WizdomHttpRESTHeader -accessToken $accessToken -Verbose:$VerbosePreference
        $restUrl = $WizdomUrl + "/api/wizdom/365/ClassicModernDeploy/DeployModernPackages"
        $response = Invoke-RestMethod -Uri $restUrl -Method POST -Headers $httpHeader -Verbose:$VerbosePreference 
    } catch {
        Write-Host "Error in Set-WizdomModernPackageAssociation: $($_.Exception.Message)" -ForegroundColor Red -Verbose:$VerbosePreference
        return $_
    }
}

<#function WizdomGlobalTermsets ()  {
[CmdletBinding(SupportsShouldProcess=$True)]
param (
        [Parameter(Mandatory=$false)][String]$siteUrl,
        [Parameter(Mandatory=$false)][String]$Username,
        [Parameter(Mandatory=$false)][String]$Password,
        [Parameter(Mandatory=$false)][Switch]$checkAdminRights
    )

$WizdomGlobalGroupName = "Wizdom Global"
$WizdomGlobalGroupId = "10000001-1001-1001-1001-100000000001"
$WizdomTermSetNames = @("Wizdom_Languages", "Wizdom_RelatedTopic", "Wizdom_ManualType", "Wizdom_ManualArea")

Try {
    $Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, ($Password | ConvertTo-SecureString -AsPlainText -Force))
    $Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
    $Ctx.Credentials = $Credentials
    $ctx.add_ExecutingWebRequest({
        param($Source, $EventArgs)
        $request = $EventArgs.WebRequestExecutor.WebRequest
        $request.UserAgent = $UserAgentString
    })

    csomExecuteWithRetry $Ctx
    Write-Verbose "Successfully got client context"


    $TaxonomySession = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($Ctx) 
    $TermStore = $TaxonomySession.GetDefaultSiteCollectionTermStore()
    $Ctx.Load($TaxonomySession)
    $Ctx.Load($TermStore)
    csomExecuteWithRetry $Ctx
    $WizdomGlobalGroup = $TermStore.GetGroup($WizdomGlobalGroupId)
    $Ctx.Load($WizdomGlobalGroup)
    csomExecuteWithRetry $Ctx
    
        if($WizdomGlobalGroup -eq $null -or $WizdomGlobalGroup.ServerObjectIsNull -eq $true){
            $WizdomGlobalGroup = $TermStore.CreateGroup($WizdomGlobalGroupName, $WizdomGlobalGroupId)
            if ($PSCmdlet.ShouldProcess($WizdomGlobalGroupName,"Create")){
                $Ctx.Load($WizdomGlobalGroup)
                csomExecuteWithRetry $Ctx
            }
            Write-Verbose "Term Group '$($WizdomGlobalGroupName)' has been created successfully"
        }
        else{
         Write-Verbose "Term Group '$($WizdomGlobalGroup.Name)' already exists"
         }

    if (-not $checkAdminRights.IsPresent) {
            $TermSets = $WizdomGlobalGroup.TermSets
            $Ctx.Load($TermSets)
            csomExecuteWithRetry $Ctx

            Foreach($TermSetName in $WizdomTermSetNames){
                $TermSet = $TermSets | Where-Object {$_.Name -eq $TermSetName}
                if($TermSet -eq $null){
                    $NewTermSet = $WizdomGlobalGroup.CreateTermSet($TermSetName,[System.Guid]::NewGuid().toString(),$TermStore.DefaultLanguage)
                    if ($PSCmdlet.ShouldProcess($TermSetName,"Create")){
                        $Ctx.Load($NewTermSet)
                        csomExecuteWithRetry $Ctx
                    }
                    Write-Verbose "TermSet '$($TermSetName)' has been created successfully"
                }
                else{
                    Write-Verbose "TermSet '$TermSetName' already exists"
                }
            }
        }
    return $true

}
Catch {
    if ($checkAdminRights.IsPresent) {
        if ($_.FullyQualifiedErrorId -eq "MethodArgumentConversionInvalidCastArgument") {
            Throw
        } else {
            return $false
       }
    } else {
        write-host -f Red "Operation failed. Error: " $_.Exception.Message
    }

}
}#>


Function Install-WizdomMobile () { 
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true)][String]$mobileModuleName,
        [Parameter(Mandatory=$true)][String]$wizdomMobileSiteSPO,
        [Parameter(Mandatory=$true)][String]$wizdomWebsiteUrl,
        [Parameter(Mandatory=$true)][String]$sharePointAdminUsr,
        [Parameter(Mandatory=$false)][System.Management.Automation.PSCredential]$sharePointAdminCredentials,
        [Parameter(Mandatory=$true)][String]$mobileSiteCollectionOwner,
        [Parameter(Mandatory=$true)][String]$mobileSiteCollectionTitle,
        [Parameter(Mandatory=$true)][String]$mobileSiteCollectionLocaleId,
        [Parameter(Mandatory=$false)][String]$wizdomSharePointAppId, #not required for skipInstall - ParameterSets?
        [Parameter(Mandatory=$true)][String]$azureResourceGroupName,
        [Parameter(Mandatory=$false)][String]$azureMobileWebAppUrl,
        [Parameter(Mandatory=$true)][String]$mobileModuleZip, 
        [parameter(Mandatory=$true)][String]$lightningPageTemplate,
        [Parameter(Mandatory=$false)][String]$outputMaxLength = 150,
        [Parameter(Mandatory=$false)][String]$removeMode, #AzureServices, SharePointSites
        [Parameter(Mandatory=$false)][String]$installMode, #MobileSolution, NoneTestConfig 
        [Parameter(Mandatory=$false)][String]$wizdomSharePointAppName,
        [Parameter(Mandatory=$false)][Switch]$enableNotifications = $false,
        [Parameter(Mandatory=$false)][String]$notificationHubNamespace,
        [Parameter(Mandatory=$false)][String]$notificationHubName,
        [Parameter(Mandatory=$false)][String]$notificationHubTemplate,
        [Parameter(Mandatory=$false)][Switch]$ConfirmRemove = $True
    )
    #region checkSettings
    
    $websiteNameMobile = $azureMobileWebAppUrl.Split(".")[0].Split("/")[-1]
    $wizdomWebsiteName = $wizdomWebsiteUrl.Split(".")[0].Split("/")[-1]
    #endregion
    if ($installMode -ne "NoneTestConfig") {
        Write-Host "--- Wizdom Mobile App Installation Begin ---" -ForegroundColor White
        Write-Host ("Mobile Installation starttime: " + (get-date)) -ForegroundColor White
    }
    
    $AzureWebApp = Get-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $wizdomWebsiteName -ErrorAction SilentlyContinue
    if ($AzureWebApp -ne $null) {
        $AppSettingsList = @{}
        ForEach ($kvp in $AzureWebApp.SiteConfig.AppSettings) {
            $AppSettingsList[$kvp.Name] = $kvp.Value
        }
        if($AppSettingsList.ClientSecret -like "AZURE_KEY_VAULT*") {
            $clientSecret = (Get-AzureKeyVaultSecret -VaultName ($AppSettingsList.KeyvaultUrl).split('/')[2].split('.')[0] -Name $AppSettingsList.clientSecret.split(':')[1]).SecretValueText
        } else {
            $clientSecret = $AppSettingsList.clientSecret
        }
        if($AppSettingsList.AzureADKey -like "AZURE_KEY_VAULT*") {
            $AzureADKey = (Get-AzureKeyVaultSecret -VaultName $AppSettingsList.KeyvaultUrl.split('/')[2].split('.')[0] -Name $AppSettingsList.AzureADKey.split(':')[1]).SecretValueText
        } else {
            $AzureADKey = $AppSettingsList.AzureADKey 
        }
        if($AppSettingsList.SearchPassword -like "AZURE_KEY_VAULT*") {
            $SearchPassword = (Get-AzureKeyVaultSecret -VaultName $AppSettingsList.KeyvaultUrl.split('/')[2].split('.')[0] -Name $AppSettingsList.SearchPassword.split(':')[1]).SecretValueText
        } else {
            $SearchPassword = $AppSettingsList.SearchPassword
        }
        $wizdomWebsiteName = $AppSettingsList.AppUrl.Split(".")[0].Split("/")[-1]
    }

    try {
        #region 2.1	CREATE NEW SITE COLLECTION
            #get group
            if ($removeMode -match "SharePointSites") {
                if ((Get-SPOSite -Limit ALL| Where Url -eq $wizdomMobileSiteSPO) -ne $null ) {
                    $output = Write-WizdomHost -messageType PROCESS -message ("Deleting SharePoint Site " + $mobileSiteCollectionTitle) -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    try {
                        if ($PSCmdlet.ShouldProcess($wizdomMobileSiteSPO, "Remove")) {
                            if ($ConfirmRemove) {
                                Remove-SPOSite -Identity $wizdomMobileSiteSPO -ErrorAction SilentlyContinue |write-verbose
                            } else {
                                Remove-SPOSite -Identity $wizdomMobileSiteSPO -ErrorAction SilentlyContinue -Confirm:$false |write-verbose
                            }
                            $siteDeleted = $false
                            do {
                                Start-Sleep -Seconds $waitLong
                                try {
                                    $site = Get-SPODeletedSite -Identity $wizdomMobileSiteSPO -ErrorAction Stop
                                    $siteDeleted = $true}
                                catch {$siteDeleted = $false}
                            } until ($siteDeleted)
                            if ($ConfirmRemove) {
                                Remove-SPODeletedSite -Identity $wizdomMobileSiteSPO |write-verbose
                            } else {
                                Remove-SPODeletedSite -Identity $wizdomMobileSiteSPO -Confirm:$false | Write-Verbose
                            }
                        }
                        Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    } catch {
                        Write-WizdomHost -messageType WARNING -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    }
                }
            }

            # Create a web app.
            if ($removeMode -match "AzureServices") {
                if ((Get-AzureRMWebApp -ResourceGroupName $azureResourceGroupName -Name $websiteNameMobile -ErrorAction SilentlyContinue) -ne $null) {
                    $output = Write-WizdomHost -messageType PROCESS -message ("Deleting Azure Mobile Web App " + $websiteNameMobile) -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                        if ($PSCmdlet.ShouldProcess($websiteNameMobile, "Remove")) {
                            if ($ConfirmRemove) {
                                Remove-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $websiteNameMobile -Force -Confirm
                            } else {
                                Remove-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $websiteNameMobile -Force -Confirm:$false
                            }
                        }
                    Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                }
                
            }

            if ($installMode -eq "NoneTestConfig") {
                Return 
            }
            

            if ($PSCmdlet.ShouldProcess("MobileZip", "Extract")) {
                #Expand-Archive -Path $mobileModuleZip -DestinationPath ($env:TEMP + "\" + $mobileModuleZip.split("\")[-1].Replace(".zip","")) -Force
                $mobileZipDir = ($env:TEMP + "\WizMobInst")
                Expand-Archive -Path $mobileModuleZip -DestinationPath $mobileZipDir -Force
            }
            $mobileModuleDir = (Get-ChildItem $mobileZipDir -Recurse | Where-Object { $_.PSIsContainer -and $_.Name.EndsWith('WizdomBlob')}).Parent.FullName

            $output = Write-WizdomHost -messageType PROCESS -message ("Creating Wizdom site '" + $wizdomMobileSiteSPO.split('/')[-1] + "'") -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            if ((get-sposite -Limit ALL| Where Url -eq $wizdomMobileSiteSPO) -eq $null ) {
                $retryCount = 0
                do {
                    try {
                        try {
                            $deletedSite = Get-SPODeletedSite -Identity $wizdomMobileSiteSPO -ErrorAction Stop
                            if ($deletedSite -ne $null) {Remove-SPODeletedSite -Identity $wizdomMobileSiteSPO -Confirm:$false}
                        } catch {}
                
                        if ($PSCmdlet.ShouldProcess($wizdomMobileSiteSPO, "New Site")) {
                            New-SPOSite -Url $wizdomMobileSiteSPO -Owner $sharePointAdminUsr -StorageQuota 1024 -Title $mobileSiteCollectionTitle -CompatibilityLevel 15 -LocaleId $mobileSiteCollectionLocaleId -Template "STS#0"
                        }
                        $siteCreated = $true
                    } catch {
                        $siteCreated = $false
                        if ($retryCount -eq 0) {
                            Write-host $_
                            $output = Write-WizdomHost -messageType PROCESS -message "SharePoint has put deletion of previous site in queue. It might take 10-15 mins for it to become available again" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                        } else {
                            if (($output + $dotCount) -le ($outputMaxLength - 2)) {
                                Write-Host -NoNewline "." -ForegroundColor White
                                $dotCount++
                            }
                        }
                        $retryCount++
                        Start-Sleep -Seconds $waitVeryLong
                    }
                } until ($siteCreated)
                $connectionMobileSiteSharePointAdmin = Connect-PnPOnline -ReturnConnection -Url $wizdomMobileSiteSPO -AppId $AppSettingsList.clientId -AppSecret $clientSecret
                <#if ($sharePointAdminCredentials -ne $null) {
                    $connectionMobileSiteSharePointAdmin = Connect-PnPOnline -ReturnConnection -Url $wizdomMobileSiteSPO -Credentials $sharePointAdminCredentials
                } else {
                    Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    $output = Write-WizdomHost -messageType PROCESSATTENTION -message "PnPOnline-Module: Sign in to the mobile site with your MFA enabled user" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    $connectionMobileSiteSharePointAdmin = Connect-PnPOnline -ReturnConnection -Url $wizdomMobileSiteSPO -UseWebLogin
                    Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    $output = Write-WizdomHost -messageType PROCESS -message "Setting user rights on site" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                }#>

                if ($PSCmdlet.ShouldProcess($AppSettingsList.SearchUsername, "Add user to Visitors Group")) {
                    do {
                        Start-Sleep -Seconds $waitShort
                        $visitorsGroup = Get-PnPGroup -Connection ($connectionMobileSiteSharePointAdmin) -AssociatedVisitorGroup
                    } until ($visitorsGroup -ne $null)
                    do {
                        try {
                            Add-PnPUserToGroup -LoginName $AppSettingsList.SearchUsername -Identity $visitorsGroup.id -Connection ($connectionMobileSiteSharePointAdmin) | Write-Verbose
                            do {    
                                Start-Sleep -Seconds $waitShort
                                try {
                                    $sharepointSiteVisitor = Get-SPOUser -site $wizdomMobileSiteSPO -LoginName $AppSettingsList.SearchUsername -ErrorAction SilentlyContinue
                                } catch {
                                    $sharepointSiteVisitor = $null
                                }
                            } while ($null -eq $sharepointSiteVisitor)
                        } catch {
                            Start-Sleep -Seconds $waitShort
                        }
                    } until ($sharepointSiteVisitor -ne $null)
                }

                if ($PSCmdlet.ShouldProcess($mobileSiteCollectionOwner, "Add user as Site Collection Owner")) {
                    do {
                        Start-Sleep -Seconds $waitShort
                        $ownerGroup = Get-PnPGroup -Connection ($connectionMobileSiteSharePointAdmin) -AssociatedOwnerGroup
                    } until ($ownerGroup -ne $null)

                    do {
                        try {
                            Add-PnPUserToGroup -LoginName $mobileSiteCollectionOwner -Identity $ownerGroup.id -Connection ($connectionMobileSiteSharePointAdmin) | Write-Verbose
                            do {    
                                Start-Sleep -Seconds $waitShort
                                try {
                                    $sharepointSiteOwner = Get-SPOUser -site $wizdomMobileSiteSPO -LoginName $mobileSiteCollectionOwner -ErrorAction SilentlyContinue
                                } catch {
                                    $sharepointSiteOwner = $null
                                }
                            } while ($null -eq $sharepointSiteOwner)
                        } catch {
                            Start-Sleep -Seconds $waitShort
                        }
                    } until ($sharepointSiteOwner -ne $null)

                    Set-SPOUser -site $wizdomMobileSiteSPO -LoginName $mobileSiteCollectionOwner -IsSiteCollectionAdmin $true |write-verbose
                    do {
                        Start-Sleep -Seconds $waitShort
                    } until ((get-spouser -Site $wizdomMobileSiteSPO -LoginName $mobileSiteCollectionOwner).IsSiteAdmin)

                }
                Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            } else {
                Write-WizdomHost -messageType WARNING -outputMaxLength $outputMaxLength -initialStringLength $output -message " - Wizdom site already exists" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                $connectionMobileSiteSharePointAdmin = Connect-PnPOnline -ReturnConnection -Url $wizdomMobileSiteSPO -AppId $AppSettingsList.clientId -AppSecret $clientSecret
                <#if ($sharePointAdminCredentials -ne $null) {
                    $connectionMobileSiteSharePointAdmin = Connect-PnPOnline -ReturnConnection -Url $wizdomMobileSiteSPO -Credentials $sharePointAdminCredentials
                } else {
                    $output = Write-WizdomHost -messageType PROCESSATTENTION -message "PnPOnline-Module: Sign in to the mobile site with your MFA enabled user" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    $connectionMobileSiteSharePointAdmin = Connect-PnPOnline -ReturnConnection -Url $wizdomMobileSiteSPO -UseWebLogin
                    Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                }#>

                if ($PSCmdlet.ShouldProcess($AppSettingsList.SearchUsername, "Add user to Visitors Group")) {
                    do {
                        Start-Sleep -Seconds $waitShort
                        $visitorsGroup = Get-PnPGroup -Connection ($connectionMobileSiteSharePointAdmin) -AssociatedVisitorGroup
                    } until ($visitorsGroup -ne $null)
                    if (@(Get-PnPGroupMembers -Identity $visitorsGroup -Connection ($connectionMobileSiteSharePointAdmin)).where({$_.LoginName -eq ("i:0#.f|membership|" + $AppSettingsList.SearchUsername)})[0].id -eq $null) {
                        do {
                            try {
                                Add-PnPUserToGroup -LoginName $AppSettingsList.SearchUsername -Identity $visitorsGroup.id -Connection ($connectionMobileSiteSharePointAdmin) | Write-Verbose
                                do {    
                                    Start-Sleep -Seconds $waitShort
                                    try {
                                        $sharepointSiteVisitor = Get-SPOUser -site $wizdomMobileSiteSPO -LoginName $AppSettingsList.SearchUsername -ErrorAction SilentlyContinue
                                    } catch {
                                        $sharepointSiteVisitor = $null
                                    }
                                } while ($null -eq $sharepointSiteVisitor)
                            } catch {
                                Start-Sleep -Seconds $waitShort
                            }
                        } until ($sharepointSiteVisitor -ne $null)
                    }
                }

                if ($PSCmdlet.ShouldProcess($mobileSiteCollectionOwner, "Add user as Site Collection Owner")) {
                    do {
                        Start-Sleep -Seconds $waitShort
                        $ownerGroup = Get-PnPGroup -Connection ($connectionMobileSiteSharePointAdmin) -AssociatedOwnerGroup
                    } until ($ownerGroup -ne $null)

                    if (@(Get-PnPGroupMembers -Identity $ownerGroup -Connection ($connectionMobileSiteSharePointAdmin)).where({$_.LoginName -eq ("i:0#.f|membership|" + $mobileSiteCollectionOwner)})[0].id -eq $null) {
                        do {
                            try {
                                Add-PnPUserToGroup -LoginName $mobileSiteCollectionOwner -Identity $ownerGroup.id -Connection ($connectionMobileSiteSharePointAdmin) | Write-Verbose
                                do {    
                                    Start-Sleep -Seconds $waitShort
                                    try {
                                        $sharepointSiteOwner = Get-SPOUser -site $wizdomMobileSiteSPO -LoginName $mobileSiteCollectionOwner -ErrorAction SilentlyContinue
                                    } catch {
                                        $sharepointSiteOwner = $null
                                    }
                                } while ($null -eq $sharepointSiteOwner)
                            } catch {
                                Start-Sleep -Seconds $waitShort
                            }
                        } until ($sharepointSiteOwner -ne $null)

                        Set-SPOUser -site $wizdomMobileSiteSPO -LoginName $mobileSiteCollectionOwner -IsSiteCollectionAdmin $true |write-verbose
                        do {
                            Start-Sleep -Seconds $waitShort
                        } until ((get-spouser -Site $wizdomMobileSiteSPO -LoginName $mobileSiteCollectionOwner).IsSiteAdmin)
                    }
                }
            }
        #endregion

        #region 3.1.2	ENABLE FEATURES
            $output = Write-WizdomHost -messageType PROCESS -message ("Activating Publishing Features on '" + $wizdomMobileSiteSPO + "'") -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                if ($PSCmdlet.ShouldProcess($wizdomMobileSiteSPO, "Activate Publishing Features")) {
                    Enable-PnPFeature -Identity "f6924d36-2fa8-4f0b-b16d-06b7250180fa" -Scope Site -Connection $connectionMobileSiteSharePointAdmin
                    Enable-PnPFeature -Identity "94c94ca6-b32f-4da9-a9e3-1f3d343d7ecb" -Scope Web -Connection $connectionMobileSiteSharePointAdmin

                }
            Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
        #endregion
<#
        #region 3.1.3	ADD WIZDOM APP
            $output = Write-WizdomHost -messageType PROCESS -message "Adding Wizdom App" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            $dotCount = 0
            if ($removeMode -notmatch "SharePointSites") { #($removeMode -match "AzureResourceGroup" -or $removeMode -match "AzureServices") -and 
                if ((get-sposite -Identity $wizdomMobileSiteSPO -ErrorAction SilentlyContinue) -ne $null ) {
                    if ($PSCmdlet.ShouldProcess("Wizdom App", "Remove from Site Collection")) {
                        try {
                            $wizdomApps = (Get-PnPAppInstance -Connection $connectionMobileSiteSharePointAdmin -WarningAction SilentlyContinue).where({$_.Title -eq $wizdomSharePointAppName})
                            foreach ($wizdomApp in $wizdomApps) {
                                Uninstall-PnPAppInstance -Identity $wizdomApp.Id.ToString() -Connection $connectionMobileSiteSharePointAdmin -Force -WarningAction SilentlyContinue -ErrorAction SilentlyContinue|Write-Verbose
                            }
                            do {
                                $wizdomApps = (Get-PnPAppInstance -Connection $connectionMobileSiteSharePointAdmin -WarningAction SilentlyContinue).where({$_.Title -eq $wizdomSharePointAppName})
                                Start-Sleep -Seconds $waitShort
                            } until ($wizdomApps -eq $null -or $wizdomApps.Count -eq 0)
                        } catch {}
                    } 
                }
            }
        
            $appInstalled = $false
            if ($PSCmdlet.ShouldProcess("Wizdom App", "Add to Site Collection")) {
                do {
                    Install-PnPApp -Identity $wizdomSharePointAppId -Scope Tenant -Wait -Connection ($connectionMobileSiteSharePointAdmin) -ErrorAction SilentlyContinue -ErrorVariable installPnPAppError
                    if ($installPnPAppError -eq $null) {
                        $appInstalled = $true
                    } else {
                        start-sleep -Seconds $waitShort
                        $appInstalled = $false
                        if (($output.Length + $dotCount) -le ($outputMaxLength - 2)) {
                            Write-Host -NoNewline "." -ForegroundColor White
                            $dotCount++
                        }
                    }
                } until ($appInstalled)
            }
<#            do {
                try {
                    if ($PSCmdlet.ShouldProcess("Wizdom App", "Add to Site Collection")) {
                        Install-PnPApp -Identity $wizdomSharePointAppId -Scope Tenant -Wait -Connection ($connectionMobileSiteSharePointAdmin)
                        $appInstalled = $true
                    } else {$appInstalled = $true}
                } catch {
                    start-sleep -Seconds $waitShort
                    $appInstalled = $false
                    if (($output.Length + $dotCount) -le ($outputMaxLength - 2)) {
                        Write-Host -NoNewline "." -ForegroundColor White
                        $dotCount++
                    }
                }
            } until ($appInstalled)
  #>          
#            Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength ($output+$dotCount) -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference

            Set-SPOUser -Site $wizdomMobileSiteSPO -LoginName $AppSettingsList.SearchUsername -IsSiteCollectionAdmin $false | Write-Verbose
        #endregion
            $accessTokenParameters = @{
                adTenant = $AppSettingsList.AzureTenantname
                sharepointTenant = $AppSettingsList.TenantSiteUrl
                adClientId = $AppSettingsList.AzureADClientID
                adClientSecret = $AzureADKey
                username = $AppSettingsList.SearchUsername
                userpassword = $SearchPassword
            }
            #Write-Host $AppSettingsList.AzureTenantname
            #Write-Host $AppSettingsList.TenantSiteUrl
            #Write-Host $AppSettingsList.AzureADClientID
            #Write-Host $AzureADKey
            #Write-Host $AppSettingsList.SearchUsername
            #Write-Host $SearchPassword
            $accessToken = Get-WizdomAccessToken @accessTokenParameters

        #region 3.1.4	INSTALL WIZDOM
            $output = Write-WizdomHost -messageType PROCESS -message ("Installing Wizdom on site collection " + $wizdomMobileSiteSPO + " - (long running process)") -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            $dotCount = 0
            if ($PSCmdlet.ShouldProcess("Wizdom", "Install")) {
                $InstallStatus = Install-WizdomOnSitecollection -WizdomUrl $wizdomWebsiteUrl -sharePointUrl $wizdomMobileSiteSPO -accessToken $accessToken
                do {
                    Start-Sleep -Seconds $waitLong
                    if (($output + $dotCount) -le ($outputMaxLength - 2)) {
                        Write-Host -NoNewline "." -ForegroundColor White
                        $dotCount++
                    }
                } until ((Get-WizdomInstallStatus -WizdomUrl $wizdomWebsiteUrl -siteCollectionId $InstallStatus.sitecollectionId -accessToken $accessToken) -eq "Done")
            }
            Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength ($output+$dotCount) -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
        #endregion

        #region 3.2.5.1 CONFIGURE NOTIFICATION HUB 
            if($enableNotifications) {
                $output = Write-WizdomHost -messageType PROCESS -message "Adding the notification hub" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "NewsTrending")) {
                        New-AzureRmResourceGroupDeployment -ResourceGroupName $azureResourceGroupName -TemplateFile $notificationHubTemplate -notificationHubNS $notificationHubNamespace -notificationHubName $notificationHubName|Write-Verbose
                        $notificationHubConnectionString = (Get-AzureRmNotificationHubListKeys -ResourceGroup $azureResourceGroupName -Namespace $notificationHubNamespace -NotificationHub $notificationHubName -AuthorizationRule "DefaultFullSharedAccessSignature").PrimaryConnectionString
                    }
                Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            }
        <#

Select Pricing tier depending on customer size 

#>

        #endregion

        #region 3.1.5	CREATE NEW WEB APP

            #Login-AzureRmAccount -Subscription $azureSubscriptionId -AccessToken $azureToken -AccountId $azureAdmin -WhatIf:$false|Write-Verbose
            # Create a web app.



            $output = Write-WizdomHost -messageType PROCESS -message ("Creating Azure Webapplication " + $websiteNameMobile) -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                try {
                    $AzureWebAppMobile = Get-AzureRMWebApp -ResourceGroupName $azureResourceGroupName -Name $websiteNameMobile -ErrorAction SilentlyContinue
                    if ($AzureWebAppMobile -eq $null) {
                        if ($PSCmdlet.ShouldProcess($websiteNameMobile, "New WebApp")) {
                            $AzureWebAppMobile = New-AzureRmWebApp -Name $websiteNameMobile -Location $AzureWebApp.location -ResourceGroupName $azureResourceGroupName -AppServicePlan $AzureWebApp.Id.split('/')[-1] 
                            Write-Host -NoNewline "." -ForegroundColor White
                            $dotCount++
                            $WebAppPropertiesObject = @{"siteConfig" = @{"AlwaysOn" = $true}}
                            $WebAppResourceType = 'microsoft.web/sites'
                            $webAppResource = Get-AzureRmResource -ResourceType $WebAppResourceType -ResourceGroupName $azureResourceGroupName -ResourceName $websiteNameMobile
                            $webAppResource | Set-AzureRmResource -PropertyObject $WebAppPropertiesObject -Force |write-verbose
                            Write-Host -NoNewline "." -ForegroundColor White
                            $dotCount++
                            if ($removeMode -match "Azure") {
                                ipconfig /flushdns |write-verbose
                            }
                            Write-Host -NoNewline "." -ForegroundColor White
                            $dotCount++
                            do {
                                Start-Sleep -Seconds $waitShort
                                $webApp =  Get-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $websiteNameMobile -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
                                if (($output + $dotCount) -le ($outputMaxLength - 2)) {
                                    Write-Host -NoNewline "." -ForegroundColor White
                                    $dotCount++
                                }
                            } until ($webApp.State -eq "Running")
                        }
                        Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength ($output+$dotCount) -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference    
                    } else {
                        Write-WizdomHost -messageType WARNING -outputMaxLength $outputMaxLength -initialStringLength $output -message " - Webapplication already exists" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    }
                } catch {
                    Write-WizdomHost -messageType ERROR -outputMaxLength $outputMaxLength -initialStringLength $output -afterOutputMessage $_ -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    Exit
                }
        

            $output = Write-WizdomHost -messageType PROCESS -message "Updating Azure Webapplication Application Settings" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference        

            $AppSettingsListMobile = @{}
            ForEach ($kvp in $AzureWebAppMobile.SiteConfig.AppSettings) {
                $AppSettingsListMobile[$kvp.Name] = $kvp.Value
            }

            $AppSettingsListMobile['AdminSiteUrl'] = $AppSettingsList.AdminSiteUrl
            $AppSettingsListMobile['AppUrl'] = $AppSettingsList.AppUrl
            $AppSettingsListMobile['AzureADClientID'] = $AppSettingsList.AzureADClientID

            if($AppSettingsList.AzureADKey -like "AZURE_KEY_VAULT*") {
                $AppSettingsListMobile['AzureADKey'] = (Get-AzureKeyVaultSecret -VaultName ($AppSettingsList.KeyvaultUrl).split('/')[2].split('.')[0] -Name $AppSettingsList.AzureADKey.split(':')[1]).SecretValueText
            } else {
                $AppSettingsListMobile['AzureADKey'] = $AppSettingsList.AzureADKey
            }

            $AppSettingsListMobile['AzureTenantname'] = $AppSettingsList.AzureTenantname
            $AppSettingsListMobile['ClientId'] = $AppSettingsList.ClientId

            if($AppSettingsList.ClientSecret -like "AZURE_KEY_VAULT*") {
                $AppSettingsListMobile['ClientSecret'] = (Get-AzureKeyVaultSecret -VaultName ($AppSettingsList.KeyvaultUrl).split('/')[2].split('.')[0] -Name $AppSettingsList.ClientSecret.split(':')[1]).SecretValueText
            } else {
                $AppSettingsListMobile['ClientSecret'] = $AppSettingsList.ClientSecret
            }

            $AppSettingsListMobile['TenantSiteUrl'] = $AppSettingsList.TenantSiteUrl

            if ($PSCmdlet.ShouldProcess($websiteNameMobile, "Update WebApp AppSettings")) {
                Set-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $websiteNameMobile -AppSettings $AppSettingsListMobile |write-verbose
            }
        
            if ($AppSettingsList.'module:LightningPages' -eq "") {
                $AppSettingsList['module:LightningPages'] = "true"
            } else {
                $AppSettingsList.'module:LightningPages' = "true"
            }

            if($enableNotifications) {
                $AppSettingsList['PushSenderNotificationHubConnectionString'] = $notificationHubConnectionString
                $AppSettingsList['PushSenderNotificationHubPath'] = $notificationHubName
            }

            if ($PSCmdlet.ShouldProcess($wizdomWebsiteName, "Update WebApp AppSettings")) {
                Set-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $wizdomWebsiteName -AppSettings $AppSettingsList |write-verbose
            }

            Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
        #endregion

        #region 3.2	DEPLOYMENT
            $output = Write-WizdomHost -messageType PROCESS -message "Uploading mobile app code" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            # Get publishing profile for the web app
            $xml = [xml](Get-AzureRmWebAppPublishingProfile -Name $websiteNameMobile -ResourceGroupName $azureResourceGroupName)

            # Extract connection information from publishing profile
            $username = $xml.SelectNodes("//publishProfile[@publishMethod=`"MSDeploy`"]/@userName").value
            $password = $xml.SelectNodes("//publishProfile[@publishMethod=`"MSDeploy`"]/@userPWD").value
            #$url = $xml.SelectNodes("//publishProfile[@publishMethod=`"MSDeploy`"]/@publishUrl").value
            $mobileModuleUploadZip = $mobileModuleDir + "\mobileModuleUpload.zip"
            if ($PSCmdlet.ShouldProcess($websiteNameMobile, "Deploy Mobile App Code")) {
                Compress-Archive -Path ($mobileModuleDir + "\*") -DestinationPath $mobileModuleUploadZip -Force|write-verbose
                $apiUrl = "https://" + $websiteNameMobile + ".scm.azurewebsites.net/api/zipdeploy"
                $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
                $userAgent = "powershell/1.0"
                Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -UserAgent $userAgent -Method POST -InFile $mobileModuleUploadZip -ContentType "multipart/form-data" |write-verbose
            }
        #endregion 
        
        #region 3.2.1	IMPORT CUSTOM MODULE
            if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "Import Custom Code")) {
                Import-WizdomZipPackage -WizdomUrl $wizdomWebsiteUrl -fileName ($mobileModuleDir + "\Dist\WizdomMobileModule.zip") -accessToken $accessToken |write-verbose
            }
        #endregion
                
        #region 3.2.2.1	CHANGE LIGHTNING PAGE TEMPLATE
            $lightningPageContent = (Get-Content -Path $lightningPageTemplate -raw -Force ) -replace '##WEBAPP_NAME##',$websiteNameMobile
        #endregion

        Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
        #region 3.2.2.2	CREATE LIGHTNING PAGE FOR WIZDOM MOBILE SITE
            #30 sek
            $output = Write-WizdomHost -messageType PROCESS -message "Restarting Azure Web App Services" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            if ($PSCmdlet.ShouldProcess($wizdomWebsiteName + ", " + $websiteNameMobile, "Restart")) {
                Stop-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $wizdomWebsiteName|write-verbose
                Stop-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $websiteNameMobile|write-verbose
                Start-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $wizdomWebsiteName|write-verbose
                Start-AzureRmWebApp -ResourceGroupName $azureResourceGroupName -Name $websiteNameMobile|write-verbose
            }
            Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference

            $output = Write-WizdomHost -messageType PROCESS -message "Waiting for Wizdom to come online" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            $dotCount = 0
            if ($PSCmdlet.ShouldProcess("Wizdom", "Ping")) {
                do {
                Start-Sleep -Seconds $waitLong
                if (($output + $dotCount) -le ($outputMaxLength - 2)) {
                    Write-Host -NoNewline "." -ForegroundColor White
                    $dotCount++
                }
                } until (ping-wizdom -wizdomUrl $wizdomWebsiteUrl -accessToken $accessToken)
            }
            Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength ($output+$dotCount) -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference

            $wizdomLanguage = (Get-WizdomLanguages -WizdomUrl $wizdomWebsiteUrl -accessToken $accessToken).where({$_.lcid -eq $mobileSiteCollectionLocaleId})
            if ($wizdomLanguage.active -eq $false) {
                if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "Set Language")) {
                    Set-WizdomLanguage -WizdomUrl $wizdomWebsiteUrl -culture $wizdomLanguage.tag -accessToken $accessToken |Write-Verbose
                }
            }
            $output = Write-WizdomHost -messageType PROCESS -message "Adding Lightningpage for the Mobile App" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            if ($sharePointAdminCredentials -ne $null) {
                if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "New Lightningpage")) {
                    Set-SPOUser -site $wizdomMobileSiteSPO -LoginName $AppSettingsList.SearchUsername -IsSiteCollectionAdmin $true |write-verbose
                    do {
                        Start-Sleep -Seconds $waitShort
                    } until ((get-spouser -Site $wizdomMobileSiteSPO -LoginName $AppSettingsList.SearchUsername).IsSiteAdmin)
                    New-WizdomLightningPage -WizdomUrl $wizdomWebsiteUrl -SharePointSiteMobile $wizdomMobileSiteSPO -lightningPageContent $lightningPageContent -accessToken $accessToken
                    Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    Set-SPOUser -site $wizdomMobileSiteSPO -LoginName $AppSettingsList.SearchUsername -IsSiteCollectionAdmin $false |write-verbose
                }
            } else {
                $lightningPageContent | Out-File -FilePath "index.html" -Force
                Write-Host
                Write-Host "Please perform the following manual steps:" -ForegroundColor Yellow
                Write-Host "  Create a New Lightning Page in Wizdom Config Center / Modules  / Lightning pages:"
                Write-Host "  (URL: $($wizdomWebsiteUrl)/Base/Pages/Configuration.aspx?SPHostUrl=$($wizdomMobileSiteSPO))"
                Write-host "  Click Add new lightning page and update the URL file name to index.html"
                Write-Host "  Select the Html tab and replace all content with the content of this file: $(Split-Path($PSScriptRoot))\index.html"
                Write-Host "  Click Save"
                pause ("Press any key to continue...")
                Write-Host
                Remove-Item -Path "index.html" -Force
            }
            
        #endregion

        #region 3.2.3 ADD AND CONFIGURE CUSTOM MODULE
            $output = Write-WizdomHost -messageType PROCESS -message "Adding and Configuring the Wizdom Mobile Custom Module" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
            if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "New Custom Module")) {
                New-WizdomCustomModule -WizdomUrl $wizdomWebsiteUrl -mobileModuleName $mobileModuleName -accessToken $accessToken
            }
        #endregion

        #region 3.2.4 CONFIGURE INITIAL MOBILE APP SETTINGS
        #Latest update 05-12-2019
            try {
                $header = Get-WizdomHttpRESTHeader -accessToken $accessToken
                $restBaseUrl = "https://" + $websiteNameMobile + ".azurewebsites.net/api/settings/"

                #Enable Latest News and Highlights

                $restUrl = $restBaseUrl + "NewsLatest"
                $restBody = '{"rowLimit":10,"homeRowLimit":5,"title":"Latest News","frontpageTitle":"Highlights","enabledComponent":true,"path":""}'
                if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "Update NewsLatest")) {
                    $result = Invoke-RestMethod -Method Post -Uri $restUrl -Body $restBody -Headers $header -ContentType "application/json; charset=UTF-8" -ErrorAction Stop
                }

                #Enable Links
                $restUrl = $restBaseUrl + "Links"
                $restBody = '{"link":[{"appLinkHeader":"asdsaads","appLinkUrl":"https://developer.microsoft.com/en-us/fabric#/styles/icons"}],"linkCollection":[{"title":"Intranet Home","url":"https://www.wizdom-intranet.com"}],"enabledComponent":true,"title":"Links"}'
                if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "Links")) {
                    $result = Invoke-RestMethod -Method Post -Uri $restUrl -Body $restBody -Headers $header -ContentType "application/json; charset=UTF-8" -ErrorAction Stop
                }

                #Enable Tranding News
                $restUrl = $restBaseUrl + "NewsTrending"
                $restBody = '{"rowLimit":10,"path":"","title":"Trending News"}'
                if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "NewsTrending")) {
                    $result = Invoke-RestMethod -Method Post -Uri $restUrl -Body $restBody -Headers $header -ContentType "application/json; charset=UTF-8" -ErrorAction Stop
                }

                #Enable Noticeboard
                $restUrl = $restBaseUrl + "NewsNoticeboard"
                $restBody = '{"channelSetId":1,"itemsPerPage":10,"title":"My Other News"}'
                if ($PSCmdlet.ShouldProcess($wizdomWebsiteUrl, "NewsNoticeboard")) {
                    $result = Invoke-RestMethod -Method Post -Uri $restUrl -Body $restBody -Headers $header -ContentType "application/json; charset=UTF-8" -ErrorAction Stop
                }

            } catch {
                Write-Host $_.Exception.Message -ForegroundColor Red
                Write-Host
                Write-Host "Manual Configuration Needed of the Wizdom Mobile app:"
                Write-Host "Open the URL $($wizdomMobileSiteSPO)"
                    Write-Host "Click on  to open Wizdom Admin Center"
                    Write-Host "In the Wizdom Admin Center, go to Custom modules and click on $($mobileModuleName)"
                    write-host "See further explanation of the needed config steps here:"
                    Write-Host "https://success.wizdom-intranet.com/a-z-guides-to-set-up-and-use-wizdoms-modules/wizdom-mobile-app/wizdom-mobile-app-module-settings/"
            }
            Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
        #endregion

        #region email Support
        Write-Host ("Mobile Installation endtime: " + (get-date)) -ForegroundColor White
            $inputString = "Confirm`r`n" + "Do you want to send an email to Wizdom with a request for an activation of the mobile app?`r`n" + "Information included:`r`n" + "- CompanyID: $($wizdomMobileSiteSPO.split('/')[2].split('.')[0])`r`n" + "- Link to index.html: $($wizdomMobileSiteSPO + '/index.html')`r`n[Y] Yes  [N] No (default is 'N')"
            $input = Read-Host -prompt $inputString
            $toAddress = "support@wizdom-intranet.com"
            if ($input.ToString().ToLower() -eq "y") { 
                $replyTo = Read-Host -Prompt "Please input email adress to which answers should be communicated. Default is $($sharePointAdminUsr)"
                $adfs = Read-Host -Prompt "If you use another ADFS server solution than OOTB Office 365, then all URLs to the ADFS servers needs to be included. If irrelevant, leave blank"
                if ($replyTo -eq "") {$replyTo = $sharePointAdminUsr}

                $mailParam = @{
                    To = $toAddress
                    Subject = "Automated request for Mobile App Activation"
                    Body = "Request for mobile App activation:`r`n" + "- CompanyID: $($wizdomMobileSiteSPO.split('/')[2].split('.')[0])`r`n" + "- Link to index.html: $($wizdomMobileSiteSPO + '/index.html')`r`n" + "- ADFS address: $($adfs)`r`n" + "`r`n" + "Replies should be sent to: $($replyTo)"
                }
                
                $output = Write-WizdomHost -messageType PROCESS -message "Sending email to Wizdom" -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                try {
                    Send-PnPMail @mailParam
                    Write-WizdomHost -messageType OK -outputMaxLength $outputMaxLength -initialStringLength $output -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                } catch {
                    Write-WizdomHost -messageType ERROR -outputMaxLength $outputMaxLength -initialStringLength $output -afterOutputMessage $_ -WhatIf:$WhatIfPreference -Verbose:$VerbosePreference
                    Write-host "Please send the mail manually:"
                    Write-host $mailParam
                }
            }

        #endregion

        #region post-installation setup - 3.2.6
        
        write-host "The following steps are not performed automatically, but need to be done manually:"
        write-host "1) Create a Corporate News portal e.g. https://$($wizdomMobileSiteSPO.split('/')[2].split('.')[0]).sharepoint.com/sites/news (unless one already exists)" 
        write-host "2) Click Settings menu and select Site Settings"
        Write-Host "3) In Look and feel select Image Renditions"
        Write-Host "4) Add the following renditions:"
        Write-Host "   - WizdomMobileModule16x9: 670px 376px"
        Write-Host "   - WizdomMobileModuleNewsRollup: 375px 325px"
        Write-Host "   - WizdomMobileModuleNewsRollupX2: 750px 650px"
        Write-Host
        if ($input.ToString().ToLower() -ne "y") {
            Write-host "5) Send an email to Wizdom to activate your Wizdom in the Mobile App:"
            Write-Host "   - To: $($toAddress)"
            Write-Host "   - Subject: Request for Mobile App Activation"
            Write-Host "   - Body:"
            Write-Host "     Request for mobile App activation:"
            Write-Host "     - CompanyID: $($wizdomMobileSiteSPO.split('/')[2].split('.')[0])"
            Write-Host "     - Link to index.html: $($wizdomMobileSiteSPO + '/index.html')"
            Write-Host "     - <If you use another ADFS server solution than OOTB Office 365, then all URLs to the ADFS servers needs to be included. If irrelevant, leave blank>"
        }
        #endregion
    } catch {
        Write-Host "Script failed: $($_.exception.Message)" -ForegroundColor Red
    } finally {
        if ($installMode -ne "NoneTestConfig") {
            if ($PSCmdlet.ShouldProcess($mobileModuleDir, "Remove")) {
                Remove-Item -Path $mobileModuleDir -Recurse -Force -ErrorAction Ignore
            }
            Write-Host "--- Wizdom Mobile App Installation End ---" -ForegroundColor White
        }
    }

}