Scripts/New-MsOfficeDeploymentToolShare.ps1

#Requires -Version 5.0

<#
 .Synopsis
   Assists in ODT placement on the server
 
 .Description
   The task schedule automatically deletes the old version.
 
 .Parameter ConfigPath
   Set ODT config path
   Create from 'Microsoft 365 Apps admin center'
 
   https://config.office.com/
 
 .Parameter LocalOfficeDeploymentToolPath
   Set to officedeploymenttool_*.exe path
   Available from 'Official Microsoft Download Center'
 
   https://go.microsoft.com/fwlink/p/?LinkID=626065
 
 .Parameter DestinationDirectory
   Root folder to place shared folders
 
 .Parameter ShareIsHidden
   Add '$' to the end of the created shared folder name flag
 
 .Parameter DirectoryName
   Deployment directory name and shared folder name
 
 .Parameter NoRegisterTask
   Not register task schedule flag
 
 .Parameter TaskName
   Task name
 
 .Parameter TaskTrigger
   Task trigger
 
 .Parameter StartTask
   Start registered task
 
 .Parameter AcceptMsOdtEula
   Agree to EULA (MICROSOFT SOFTWARE LICENSE TERMS, MICROSOFT OFFICE DEPLOYMENT TOOL) and do not display prompt
   If you want to check the contents of EULA, please execute ODT directly.
 
 .Parameter Force
   Ignore errors that can be continued
 
 .Example
   # Simply command sample
   New-MsOfficeDeploymentToolShare -ConfigPath $env:UserProfile\Downloads\Configuration.xml -LocalOfficeDeploymentToolPath $env:UserProfile\Downloads\officedeploymenttool_15128-20224.exe
 
 .Example
   # Multiple configuration command sample
   New-MsOfficeDeploymentToolShare -ConfigPath @("$env:UserProfile\Downloads\configuration-Office365-x64.xml","$env:UserProfile\Downloads\configuration-Office2021Enterprise.xml") -LocalOfficeDeploymentToolPath $env:UserProfile\Downloads\officedeploymenttool_15128-20224.exe
 
 .Example
   # Select additional option
   New-MsOfficeDeploymentToolShare -ConfigPath $env:UserProfile\Downloads\Configuration.xml -LocalOfficeDeploymentToolPath $env:UserProfile\Downloads\officedeploymenttool_15128-20224.exe -DestinationDirectory D:\Shares -DirectoryName PerpetualVL2021 -Force
 
 .Example
   # Install to running command sample by command prompt
   PowerShell -ExecutionPolicy ByPass -Command "Import-Module ManagementMsOfficeDeploymentToolShare; New-MsOfficeDeploymentToolShare -ConfigPath \""$env:UserProfile\Downloads\Configuration.xml\"" -LocalOfficeDeploymentToolPath \""$env:UserProfile\Downloads\officedeploymenttool_15128-20224.exe\"" -Force"
 
 .Example
   # Install to running command sample by command prompt
   PowerShell -ExecutionPolicy ByPass -Command "Import-Module ManagementMsOfficeDeploymentToolShare; New-MsOfficeDeploymentToolShare -ConfigPath \""$env:UserProfile\Downloads\configuration-Office365-x64.xml\"",\""$env:UserProfile\Downloads\configuration-Office2021Enterprise.xml\"" -LocalOfficeDeploymentToolPath \""$env:UserProfile\Downloads\officedeploymenttool_15128-20224.exe\"" -Force"
 
#>

Function New-MsOfficeDeploymentToolShare{
    Param(
        [Parameter(Mandatory)][String[]]$ConfigPath=@(),
        [Parameter(Mandatory)][String]$LocalOfficeDeploymentToolPath,
        [String]$DestinationDirectory = "C:\Shares",
        [Bool]$ShareIsHidden = $True,
        [String]$DirectoryName = "Office",
        [Switch]$NoRegisterTask = $False,
        [String]$TaskName = "Invoke-MsOfficeDeploymentToolAndCompress",
        $TaskTrigger,
        [Switch]$StartTask = $False,
        [Switch]$AcceptMsOdtEula = $False,
        [Switch]$AcceptEula = $False,
        [Switch]$Force
    )

    Function Invoke-Application($Path, $Argument){
        Try{
            $Process = Start-Process -FilePath $Path -ArgumentList $Argument -PassThru -Wait
            If ($Process.ExitCode -ne 0){
                Write-Warning "$($NewMsOfficeDeploymentToolShareMessageTable.WarnExitCodeByInvokeApplication) [$Path $Argument] : $($Process.ExitCode)" -Verbose
            }
        }
        Catch{
            Write-Warning "$($NewMsOfficeDeploymentToolShareMessageTable.WarnByInvokeApplication) [$Path $Argument] : $($_.Exception.Message)"
        }
    }
    Function Invoke-DownloadToTemporaryDirectory($Url){
        Try{
            # support Windows Server 2016
            [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12

            $Path = $((New-TemporaryFile).FullName)
            Invoke-WebRequest $Url -OutFile $Path
            Return $Path
        }
        Catch{
            Write-Warning "$($NewMsOfficeDeploymentToolShareMessageTable.WarnByInvokeDownloadToTemporaryDirectory) [$Url] : $($_.Exception.Message)"
        }
    }
    Function Invoke-WriteError($Exception, $Force){
        If ($Force){
            Write-Warning $Exception
        }
        Else{
            Write-Error $Exception -ErrorAction Stop
        }
    }
    Try{
        # MS-EULA
        If (-not $AcceptMsOdtEula){
            $ChoiceDescription = [System.Management.Automation.Host.ChoiceDescription]
            $MessageOptions = @(
                New-Object $ChoiceDescription ($NewMsOfficeDeploymentToolShareMessageTable.AgreeLable,"")
                New-Object $ChoiceDescription ($NewMsOfficeDeploymentToolShareMessageTable.ExitLable, "")
            )
            $MessageResult = $Host.Ui.PromptForChoice($NewMsOfficeDeploymentToolShareMessageTable.MsOdtEulaLabel, $NewMsOfficeDeploymentToolShareMessageTable.MsOdtEulaMessage, $MessageOptions, 0)
            Switch ($MessageResult){
                1{
                    Return
                }
            }
        }

        # check param
        @($ConfigPath) | ForEach-Object {
            If (-Not (Test-Path $_ -PathType Leaf)){
                Write-Error ([System.IO.FileNotFoundException]::new("$($NewMsOfficeDeploymentToolShareMessageTable.NotFoundConfigPath): [$ConfigPath]")) -ErrorAction Stop
            }
        }
        If (-Not (Test-Path $DestinationDirectory -PathType Container)){
            Invoke-WriteError -Exception ([System.IO.DirectoryNotFoundException]::new("$($NewMsOfficeDeploymentToolShareMessageTable.NotFoundDestinationDirectory) [$DestinationDirectory]")) -Force $Force
            If ($Force){
                New-Item -Path $DestinationDirectory -ItemType Directory -Force | Out-Null
            }
        }
        If (-not [String]::IsNullOrEmpty($LocalOfficeDeploymentToolPath) -and -Not (Test-Path $LocalOfficeDeploymentToolPath -PathType Leaf)){
            Write-Error ([System.IO.FileNotFoundException]::new("$($NewMsOfficeDeploymentToolShareMessageTable.NotFoundLocalOfficeDeploymentToolPath) [$LocalOfficeDeploymentToolPath]")) -ErrorAction Stop
        }
        If ([String]::IsNullOrEmpty($DirectoryName)){
            $Configuration = ([Xml](Get-Content $ConfigPath -Encoding UTF8)).Configuration
            $DirectoryName = "$($Configuration.Add.Channel).$($Configuration.Add.OfficeClientEdition)"
        }

        If ($ShareIsHidden){
            $DirectoryName += "$"
        }

        If ((Get-SmbShare | Where-Object Name -eq $DirectoryName).Count -ne 0){
            Invoke-WriteError -Exception "$($NewMsOfficeDeploymentToolShareMessageTable.ExistsFromShares): [$DirectoryName]" -Force $Force
        }
        $DestinationDirectory = (Join-Path $DestinationDirectory $DirectoryName)

        If (-not $NoRegisterTask){
            $ScheduleService = New-Object -ComObject Schedule.Service
            $ScheduleService.Connect()
            $ScheduleTask = $ScheduleService.GetFolder("\").GetTasks(0) | Where-Object Name -eq $TaskName
            If ($ScheduleTask -ne $Null){
                Invoke-WriteError -Exception "$($NewMsOfficeDeploymentToolShareMessageTable.ExistsFromTaskSchedule): [$TaskName]" -Force $Force
                If ($Force){
                    Unregister-ScheduledTask -TaskName $TaskName -Confirm:$False
                }
            }
        }

        # download ODT installer
        If ([String]::IsNullOrEmpty($LocalOfficeDeploymentToolPath)){
            $Path = Invoke-DownloadToTemporaryDirectory -Url "https://download.microsoft.com/download/2/7/A/27AF1BE6-DD20-4CB4-B154-EBAB8A7D4A7E/officedeploymenttool_15128-20224.exe"
            If (-not (Test-Path $Path -PathType Leaf)){
                Write-Error ([System.IO.FileNotFoundException]::new("$($NewMsOfficeDeploymentToolShareMessageTable.NotFoundLocalOfficeDeploymentToolPath): [$LocalOfficeDeploymentToolPath]")) -ErrorAction Stop
            }
            $LocalOfficeDeploymentToolPath = "$Path.exe"
            Move-Item $Path -Destination $LocalOfficeDeploymentToolPath
        }

        # test ODT's digital signature (If it is digitally signed, it is judged that the file is not damaged.)
        If ((Get-AuthenticodeSignature $LocalOfficeDeploymentToolPath).Status -ne "Valid"){
            Invoke-WriteError -Exception "$($NewMsOfficeDeploymentToolShareMessageTable.InvalidDigitalSignature): [$LocalOfficeDeploymentToolPath]" -Force $Force
        }

        # extract ODT installer
        $TemporaryDirectoryPath = (New-TemporaryFile).FullName
        Remove-Item $TemporaryDirectoryPath -Force

        Invoke-Application -Path $LocalOfficeDeploymentToolPath -Argument "/quiet /extract:$TemporaryDirectoryPath"
        $TemporaryMsOdtPath = (Join-Path $TemporaryDirectoryPath "setup.exe")

        If (-not (Test-Path $TemporaryMsOdtPath)){
            Write-Error ([System.IO.FileNotFoundException]::new("$($NewMsOfficeDeploymentToolShareMessageTable.NotFoundTemporaryMsOdtPath): [$TemporaryMsOdtPath]")) -ErrorAction Stop
        }

        # Copy to Directory
        New-Item $DestinationDirectory -ItemType Container -Force | Out-Null

        @($ConfigPath) | ForEach-Object {
            $DestinationConfigPath = (Join-Path $DestinationDirectory (Split-Path $_ -Leaf))
            Copy-Item $ConfigPath $DestinationConfigPath
        }
        $DestinationOdtPath = (Join-Path $DestinationDirectory "setup.exe")
        Copy-Item $TemporaryMsOdtPath (Join-Path $DestinationDirectory "setup.exe")

        # Set share
        Get-SmbShare | Where-Object Name -eq $DirectoryName | Remove-SmbShare -Force
        New-SmbShare -Name $DirectoryName -Path $DestinationDirectory -ReadAccess "Everyone" -LeasingMode Full -Description $NewMsOfficeDeploymentToolShareMessageTable.SharedFolderDescription | Out-Null

        # Register task
        If (-not $NoRegisterTask){
            If ($ConfigPath.Count -gt 1){
                $Actions = (New-ScheduledTaskAction -Execute "%WinDir%\system32\WindowsPowerShell\v1.0\powershell.exe" -Argument ("-ExecutionPolicy ByPass -Command ""Import-Module ManagementMsOfficeDeploymentToolShare; Invoke-MsOfficeDeploymentToolAndCompress -WorkingDirectory " + "'" + "$DestinationDirectory" + "'" + " -ConfigFileName " + "'" + "$((Split-Path $ConfigPath -Leaf) -Join "','")' -UsingOfficeReleases"""))
            }
            Else{
                $Actions = (New-ScheduledTaskAction -Execute "%WinDir%\system32\WindowsPowerShell\v1.0\powershell.exe" -Argument ("-ExecutionPolicy ByPass -Command ""Import-Module ManagementMsOfficeDeploymentToolShare; Invoke-MsOfficeDeploymentToolAndCompress -WorkingDirectory " + "'" + "$DestinationDirectory" + "'" + " -ConfigFileName " + "'" + "$(Split-Path $ConfigPath -Leaf)'"""))
            }
            If ($TaskTrigger -eq $Null){
                $TaskTrigger = New-ScheduledTaskTrigger -Daily -At ([DateTime]"2:00").AddMinutes((Get-Random -Maximum (60 * 5))).ToString("H:mm") # 2:00 AM ~ 5:00 AM, Everyday
            }
            $Principal = New-ScheduledTaskPrincipal -UserId "System" -RunLevel Highest
            $Settings = New-ScheduledTaskSettingsSet -RunOnlyIfNetworkAvailable -WakeToRun
            $Task = New-ScheduledTask -Action $Actions -Principal $Principal -Trigger $TaskTrigger -Settings $Settings -Description $NewMsOfficeDeploymentToolShareMessageTable.TaskDescription
            $Task.Author = "ManagementMsOfficeDeploymentToolShare"
            Register-ScheduledTask $TaskName -InputObject $Task | Out-Null
            If ($StartTask){
                Start-ScheduledTask -TaskName $TaskName
            }
        }
    }
    Catch{
        Write-Error "$($_.Exception.Message)"
    }
    Try{
        Remove-Item $TemporaryDirectoryPath -Recurse -Force -ErrorAction SilentlyContinue
    }
    Catch{}
}
Export-ModuleMember -Function New-MsOfficeDeploymentToolShare