diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 59176f6..2e7edbe 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,22 +1,43 @@ -# Changelog -*** -## 1.0 Initial release - 23.10.2022 -No additional information - see Readme +# Changelog + +## 1.2 - 23.11.2023 + +* Changed to Evergreen Url for setup.exe to avoid any issues with "scraping" the ODT download site and simplification. (Requested by [@aaronparker](https://github.com/aaronparker)) +* Added cleanup action to remove temporary setup files after installation +* Added Languagepacks as an separated option. Install with parameters same way as Proofing tools. The XML files in the folder is only templates used by script to configure given language. + +Example + +```PowerShell +powershell.exe -executionpolicy bypass -file InstallLanguagePacks.ps1 -LanguageID nb-no -Action Install +powershell.exe -executionpolicy bypass -file InstallLanguagePacks.ps1 -LanguageID nb-no -Action Uninstall +``` *** + ## 1.1 - 28.10.2023 -* Added support for external XML configuration.xml for M365 Apps main package, Visio and Project as an option + +* Added support for external XML configuration.xml for M365 Apps main package, Visio and Project as an option * No change for Proofing Tools - + Example -Without external XML (Requires configuration.xml in the package) - Same as Version 1.0 -``` +Without external XML (Requires configuration.xml in the package) - Same as Version 1.0 + +```PowerShell powershell.exe -executionpolicy bypass -file .ps1 ``` -With external XML (Requires XML to be provided by URL) - New option in the scripts -``` +With external XML (Requires XML to be provided by URL) - New option in the scripts + +```PowerShell powershell.exe -executionpolicy bypass -file .ps1 -XMLURL "https://mydomain.com/xmlfile.xml" ``` -*** \ No newline at end of file + +*** + +## 1.0 Initial release - 23.10.2022 + +No additional information - see Readme + +*** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bb06a4a..3639ffa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ -# Welcome to our contribution guide! +# Welcome to our contribution guide Thank you for investing your time in contributing to our community project! Any contribution you make will be reflected on in here. Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable. -If you are having issues with this solution, please remember that this is a community solution free of charge. We are always looking for good proposals and ideas on how to bring this to the next level. +If you are having issues with this solution, please remember that this is a community solution free of charge. We are always looking for good proposals and ideas on how to bring this to the next level. diff --git a/LanguagePacks/InstallLanguagePacks.ps1 b/LanguagePacks/InstallLanguagePacks.ps1 new file mode 100644 index 0000000..3b1d4b1 --- /dev/null +++ b/LanguagePacks/InstallLanguagePacks.ps1 @@ -0,0 +1,211 @@ +<# +.SYNOPSIS + Script to install additional languagepacks as a Win32 App + +.DESCRIPTION + Script to install additional languagepacks as a Win32 App by downloading the latest office setup.exe from evergreen url + Running Setup.exe from downloaded files with provided config.xml file. + +.PARAMETER LanguageID + Set the language ID in the correct formatting (like nb-no or en-us) +.PARAMETER Action + Supported actions are Install or Uninstall + +.EXAMPLE + InstallLanguagePacks.ps1 -LanguageID "nb-no" -Action Install + InstallLanguagePacks.ps1 -LanguageID "nb-no" -Action Uninstall + +.NOTES + Version: 1.2 + Author: Jan Ketil Skanke + Creation Date: 23.11.2022 + Purpose/Change: Initial script development + Author: Jan Ketil Skanke + Contributor Sandy Zeng + Contact: @JankeSkanke @sandytsang + Updated: 2022-23-11 + Version history: + 1.2 - (2022-23-11) Script created - Matching M365 Apps solution version +#> + +#region parameters +[CmdletBinding()] +Param ( + [Parameter(Mandatory=$true)] + [string]$LanguageID, + + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [ValidateSet("Install", "Uninstall")] + [string]$Action +) +#endregion parameters + +#Region Functions +function Write-LogEntry { + param ( + [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] + [ValidateNotNullOrEmpty()] + [string]$Value, + [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] + [ValidateNotNullOrEmpty()] + [ValidateSet("1", "2", "3")] + [string]$Severity, + [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] + [ValidateNotNullOrEmpty()] + [string]$FileName = $LogFileName + ) + # Determine log file location + $LogFilePath = Join-Path -Path $env:SystemRoot -ChildPath $("Temp\$FileName") + + # Construct time stamp for log entry + $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), " ", (Get-WmiObject -Class Win32_TimeZone | Select-Object -ExpandProperty Bias)) + + # Construct date for log entry + $Date = (Get-Date -Format "MM-dd-yyyy") + + # Construct context for log entry + $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) + + # Construct final log entry + $LogText = "" + + # Add value to log file + try { + Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop + if ($Severity -eq 1) { + Write-Verbose -Message $Value + } elseif ($Severity -eq 3) { + Write-Warning -Message $Value + } + } catch [System.Exception] { + Write-Warning -Message "Unable to append log entry to $LogFileName.log file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)" + } +} +function Start-DownloadFile { + param( + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string]$URL, + + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string]$Path, + + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string]$Name + ) + Begin { + # Construct WebClient object + $WebClient = New-Object -TypeName System.Net.WebClient + } + Process { + # Create path if it doesn't exist + if (-not(Test-Path -Path $Path)) { + New-Item -Path $Path -ItemType Directory -Force | Out-Null + } + + # Start download of file + $WebClient.DownloadFile($URL, (Join-Path -Path $Path -ChildPath $Name)) + } + End { + # Dispose of the WebClient object + $WebClient.Dispose() + } +} +function Invoke-XMLUpdate { + param( + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string]$LanguageID, + + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string]$Filename, + + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [ValidateSet("Install", "Uninstall")] + [string]$Action + ) + if ($Action -eq "Install"){ + $xmlDoc = [System.Xml.XmlDocument](Get-Content $FileName) + $xmlDoc.Configuration.Add.Product.Language.ID = $LanguageID + $xmlDoc.Save($FileName); + } + else { + $xmlDoc = [System.Xml.XmlDocument](Get-Content $FileName) + $xmlDoc.Configuration.Remove.Product.Language.ID = $LanguageID + $xmlDoc.Save($FileName); + } +} +#Endregion Functions + +#Region Initialisations +$LogFileName = "M365AppsSetup.log" +#Endregion Initialisations +switch -Wildcard ($Action) { + {($PSItem -match "Install")}{ + $FileName = "install.xml" + } + {($PSItem -match "Uninstall")}{ + $FileName = "uninstall.xml" + } +} + +#Initate Install +Write-LogEntry -Value "Initiating LanguagePack $($LanguageID) $($Action) process" -Severity 1 +#Attempt Cleanup of SetupFolder +if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup"){ + Remove-Item -Path "$($env:SystemRoot)\Temp\OfficeSetup" -Recurse -Force -ErrorAction SilentlyContinue +} + +$SetupFolder = (New-Item -ItemType "directory" -Path "$($env:SystemRoot)\Temp" -Name OfficeSetup -Force).FullName + +try{ + #Download latest Office Deployment Toolkit + $SetupEverGreenURL = "https://officecdn.microsoft.com/pr/wsus/setup.exe" + Write-LogEntry -Value "Attempting to download latest Office setup executable" -Severity 1 + Start-DownloadFile -URL $SetupEverGreenURL -Path $SetupFolder -Name "setup.exe" + + try{ + #Start install preparations + $SetupFilePath = Join-Path -Path $SetupFolder -ChildPath "setup.exe" + if (-Not (Test-Path $SetupFilePath)) { + Throw "Error: Setup file not found" + } + Write-LogEntry -Value "Setup file ready at $($SetupFilePath)" -Severity 1 + try{ + #Prepare language pack installation or removal + $OfficeCR2Version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($SetupFilePath).FileVersion + Write-LogEntry -Value "Office C2R Setup is running version $OfficeCR2Version" -Severity 1 + Invoke-XMLUpdate -LanguageID $LanguageID -Filename "$($PSScriptRoot)\$($Filename)" -Action $Action + Copy-Item "$($PSScriptRoot)\$($Filename)" $SetupFolder -Force -ErrorAction Stop + Write-LogEntry -Value "LanguagePack $($LanguageID) configuration file copied" -Severity 1 + Try{ + #Running office installer + Write-LogEntry -Value "Starting LanguagePack $($LanguageID) $($Action) with Win32App method" -Severity 1 + $OfficeInstall = Start-Process $SetupFilePath -ArgumentList "/configure $($SetupFolder)\$($Filename)" -NoNewWindow -Wait -PassThru -ErrorAction Stop + } + catch [System.Exception]{ + Write-LogEntry -Value "Error running the LanguagePack $($LanguageID) $($Action). Errormessage: $($_.Exception.Message)" -Severity 3 + } + } + catch [System.Exception]{ + Write-LogEntry -Value "Error preparing LanguagePack $($LanguageID) $($Action). Errormessage: $($_.Exception.Message)" -Severity 3 + } + } + catch [System.Exception]{ + Write-LogEntry -Value "Error finding setup.exe Possible download error. Errormessage: $($_.Exception.Message)" -Severity 3 + } + +} +catch [System.Exception]{ + Write-LogEntry -Value "Error downloading setup.exe from evergreen url. Errormessage: $($_.Exception.Message)" -Severity 3 +} +#Cleanup +if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup"){ + Remove-Item -Path "$($env:SystemRoot)\Temp\OfficeSetup" -Recurse -Force -ErrorAction SilentlyContinue +} +Write-LogEntry -Value "LanguagePack $($LanguageID) $($Action) completed" -Severity 1 diff --git a/LanguagePacks/install.xml b/LanguagePacks/install.xml new file mode 100644 index 0000000..c627206 --- /dev/null +++ b/LanguagePacks/install.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/LanguagePacks/uninstall.xml b/LanguagePacks/uninstall.xml new file mode 100644 index 0000000..b2bfe63 --- /dev/null +++ b/LanguagePacks/uninstall.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/M365AppsWin32App/InstallM365Apps.ps1 b/M365AppsWin32App/InstallM365Apps.ps1 index 5c7b2c3..cb37f3f 100644 --- a/M365AppsWin32App/InstallM365Apps.ps1 +++ b/M365AppsWin32App/InstallM365Apps.ps1 @@ -3,7 +3,7 @@ Script to install M365 Apps as a Win32 App .DESCRIPTION - Script to install Office as a Win32 App during Autopilot by downloading the latest Office Deployment Toolkit + Script to install Office as a Win32 App during Autopilot by downloading the latest Office setup exe from evergreen url Running Setup.exe from downloaded files with provided config.xml file. .EXAMPLE @@ -13,14 +13,15 @@ powershell.exe -executionpolicy bypass -file InstallM365Apps.ps1 -XMLURL "https://mydomain.com/xmlfile.xml" .NOTES - Version: 1.1 + Version: 1.2 Author: Jan Ketil Skanke - Contact: @JankeSkanke + Contact: @JankeSkanke Creation Date: 01.07.2021 - Updated: (2022-25-10) + Updated: (2022-23-11) Version history: - 1.0.0 - (2022-23-10) Script released - 1.1.0 - (2022-25-10) Added support for External URL as parameter + 1.0.0 - (2022-23-10) Script released + 1.1.0 - (2022-25-10) Added support for External URL as parameter + 1.2.0 - (2022-23-11) Moved from ODT download to Evergreen url for setup.exe #> #region parameters [CmdletBinding()] @@ -120,26 +121,20 @@ if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup") { $SetupFolder = (New-Item -ItemType "directory" -Path "$($env:SystemRoot)\Temp" -Name OfficeSetup -Force).FullName try { - #Download latest Office Deployment Toolkit - $ODTDownloadURL = "https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117" - $WebResponseURL = ((Invoke-WebRequest -Uri $ODTDownloadURL -UseBasicParsing -ErrorAction Stop -Verbose:$false).links | Where-Object { $_.outerHTML -like "*click here to download manually*" }).href - $ODTFileName = Split-Path -Path $WebResponseURL -Leaf - $ODTFilePath = $SetupFolder - Write-LogEntry -Value "Attempting to download latest Office Deployment Toolkit executable" -Severity 1 - Start-DownloadFile -URL $WebResponseURL -Path $ODTFilePath -Name $ODTFileName + #Download latest Office setup.exe + $SetupEverGreenURL = "https://officecdn.microsoft.com/pr/wsus/setup.exe" + Write-LogEntry -Value "Attempting to download latest Office setup executable" -Severity 1 + Start-DownloadFile -URL $SetupEverGreenURL -Path $SetupFolder -Name "setup.exe" try { - #Extract setup.exe from ODT Package - $ODTExecutable = (Join-Path -Path $ODTFilePath -ChildPath $ODTFileName) - $ODTExtractionPath = (Join-Path -Path $ODTFilePath -ChildPath (Get-ChildItem -Path $ODTExecutable).VersionInfo.ProductVersion) - $ODTExtractionArguments = "/quiet /extract:$($ODTExtractionPath)" - Write-LogEntry -Value "Attempting to extract the setup.exe executable from Office Deployment Toolkit" -Severity 1 - Start-Process -FilePath $ODTExecutable -ArgumentList $ODTExtractionArguments -NoNewWindow -Wait -ErrorAction Stop - $SetupFilePath = ($ODTExtractionPath | Get-ChildItem | Where-Object { $_.Name -eq "setup.exe" }).FullName + #Start install preparations + $SetupFilePath = Join-Path -Path $SetupFolder -ChildPath "setup.exe" + if (-Not (Test-Path $SetupFilePath)) { + Throw "Error: Setup file not found" + } Write-LogEntry -Value "Setup file ready at $($SetupFilePath)" -Severity 1 try { #Prepare Office Installation - Copy-Item -Path $SetupFilePath -Destination $SetupFolder -Force -ErrorAction Stop $OfficeCR2Version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$($SetupFolder)\setup.exe").FileVersion Write-LogEntry -Value "Office C2R Setup is running version $OfficeCR2Version" -Severity 1 @@ -167,7 +162,7 @@ try { Try { #Running office installer Write-LogEntry -Value "Starting M365 Apps Install with Win32App method" -Severity 1 - $OfficeInstall = Start-Process "$($SetupFolder)\setup.exe" -ArgumentList "/configure $($SetupFolder)\configuration.xml" -Wait -PassThru -ErrorAction Stop + $OfficeInstall = Start-Process $SetupFilePath -ArgumentList "/configure $($SetupFolder)\configuration.xml" -Wait -PassThru -ErrorAction Stop } catch [System.Exception] { Write-LogEntry -Value "Error running the M365 Apps install. Errormessage: $($_.Exception.Message)" -Severity 3 @@ -185,4 +180,8 @@ try { catch [System.Exception] { Write-LogEntry -Value "Error downloading Office Deployment Toolkit. Errormessage: $($_.Exception.Message)" -Severity 3 } +#Cleanup +if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup"){ + Remove-Item -Path "$($env:SystemRoot)\Temp\OfficeSetup" -Recurse -Force -ErrorAction SilentlyContinue +} Write-LogEntry -Value "M365 Apps setup completed" -Severity 1 diff --git a/ProjectWin32App/InstallProject.ps1 b/ProjectWin32App/InstallProject.ps1 index a95b775..1ea6140 100644 --- a/ProjectWin32App/InstallProject.ps1 +++ b/ProjectWin32App/InstallProject.ps1 @@ -21,6 +21,7 @@ Version history: 1.0.0 - (2022-23-10) Script released 1.1.0 - (2022-25-10) Added support for External URL as parameter + 1.2.0 - (2022-23-11) Moved from ODT download to Evergreen url for setup.exe #> #region parameters [CmdletBinding()] @@ -120,26 +121,20 @@ if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup") { $SetupFolder = (New-Item -ItemType "directory" -Path "$($env:SystemRoot)\Temp" -Name OfficeSetup -Force).FullName try { - #Download latest Office Deployment Toolkit - $ODTDownloadURL = "https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117" - $WebResponseURL = ((Invoke-WebRequest -Uri $ODTDownloadURL -UseBasicParsing -ErrorAction Stop -Verbose:$false).links | Where-Object { $_.outerHTML -like "*click here to download manually*" }).href - $ODTFileName = Split-Path -Path $WebResponseURL -Leaf - $ODTFilePath = $SetupFolder - Write-LogEntry -Value "Attempting to download latest Office Deployment Toolkit executable" -Severity 1 - Start-DownloadFile -URL $WebResponseURL -Path $ODTFilePath -Name $ODTFileName + #Download latest Office setup.exe + $SetupEverGreenURL = "https://officecdn.microsoft.com/pr/wsus/setup.exe" + Write-LogEntry -Value "Attempting to download latest Office setup executable" -Severity 1 + Start-DownloadFile -URL $SetupEverGreenURL -Path $SetupFolder -Name "setup.exe" try { - #Extract setup.exe from ODT Package - $ODTExecutable = (Join-Path -Path $ODTFilePath -ChildPath $ODTFileName) - $ODTExtractionPath = (Join-Path -Path $ODTFilePath -ChildPath (Get-ChildItem -Path $ODTExecutable).VersionInfo.ProductVersion) - $ODTExtractionArguments = "/quiet /extract:$($ODTExtractionPath)" - Write-LogEntry -Value "Attempting to extract the setup.exe executable from Office Deployment Toolkit" -Severity 1 - Start-Process -FilePath $ODTExecutable -ArgumentList $ODTExtractionArguments -NoNewWindow -Wait -ErrorAction Stop - $SetupFilePath = ($ODTExtractionPath | Get-ChildItem | Where-Object { $_.Name -eq "setup.exe" }).FullName - Write-LogEntry -Value "Setup file ready at $($SetupFilePath)" -Severity 1 + #Start install preparations + $SetupFilePath = Join-Path -Path $SetupFolder -ChildPath "setup.exe" + if (-Not (Test-Path $SetupFilePath)) { + Throw "Error: Setup file not found" + } + Write-LogEntry -Value "Setup file ready at $($SetupFilePath)" -Severity 1 try { #Prepare Office Installation - Copy-Item -Path $SetupFilePath -Destination $SetupFolder -Force -ErrorAction Stop $OfficeCR2Version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$($SetupFolder)\setup.exe").FileVersion Write-LogEntry -Value "Office C2R Setup is running version $OfficeCR2Version" -Severity 1 @@ -167,7 +162,7 @@ try { Try { #Running office installer Write-LogEntry -Value "Starting Project Install with Win32App method" -Severity 1 - $OfficeInstall = Start-Process "$($SetupFolder)\setup.exe" -ArgumentList "/configure $($SetupFolder)\configuration.xml" -Wait -PassThru -ErrorAction Stop + $OfficeInstall = Start-Process $SetupFilePath -ArgumentList "/configure $($SetupFolder)\configuration.xml" -Wait -PassThru -ErrorAction Stop } catch [System.Exception] { Write-LogEntry -Value "Error running the Project install. Errormessage: $($_.Exception.Message)" -Severity 3 @@ -185,4 +180,8 @@ try { catch [System.Exception] { Write-LogEntry -Value "Error downloading Office Deployment Toolkit. Errormessage: $($_.Exception.Message)" -Severity 3 } +#Cleanup +if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup"){ + Remove-Item -Path "$($env:SystemRoot)\Temp\OfficeSetup" -Recurse -Force -ErrorAction SilentlyContinue +} Write-LogEntry -Value "Project setup completed" -Severity 1 diff --git a/ProofingTools/InstallProofingTools.ps1 b/ProofingTools/InstallProofingTools.ps1 index 8be1725..9493d45 100644 --- a/ProofingTools/InstallProofingTools.ps1 +++ b/ProofingTools/InstallProofingTools.ps1 @@ -16,19 +16,20 @@ InstallProofingTools.ps1 -LanguageID "nb-no" -Action Uninstall .NOTES - Version: 3.0 - Author: Jan Ketil Skanke - Creation Date: 01.07.2021 - Purpose/Change: Initial script development - Author: Jan Ketil Skanke - Contributor Sandy Zeng - Contact: @JankeSkanke @sandytsang -Updated: 2022-22-09 + Version: 1.2 + Author: Jan Ketil Skanke + Creation Date: 01.07.2021 + Purpose/Change: Initial script development + Author: Jan Ketil Skanke + Contributor Sandy Zeng + Contact: @JankeSkanke @sandytsang + Updated: 2022-22-09 Version history: - 1.0 - (2020-10-11) Script created - 2.0 - (2022-15-06) MultiLanguageSupport via parameter - 2.1 - (2022-20-06) Dynamically change configuration.xml based on LanguageID Parameter - 2.2 - (2022-22-09) Adding support for uninstall, now equires 2 xml files - uninstall.xml and install.xml + 1.0 - (2020-10-11) Script created + 1.0.1 - (2022-15-06) MultiLanguageSupport via parameter + 1.0.2 - (2022-20-06) Dynamically change configuration.xml based on LanguageID Parameter + 1.1 - (2022-22-09) Adding support for uninstall, now equires 2 xml files - uninstall.xml and install.xml + 1.2.0 - (2022-23-11) Moved from ODT download to Evergreen url for setup.exe #> #region parameters @@ -167,26 +168,20 @@ if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup"){ $SetupFolder = (New-Item -ItemType "directory" -Path "$($env:SystemRoot)\Temp" -Name OfficeSetup -Force).FullName try{ - #Download latest Office Deployment Toolkit - $ODTDownloadURL = "https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117" - $WebResponseURL = ((Invoke-WebRequest -Uri $ODTDownloadURL -UseBasicParsing -ErrorAction Stop -Verbose:$false).links | Where-Object { $_.outerHTML -like "*click here to download manually*" }).href - $ODTFileName = Split-Path -Path $WebResponseURL -Leaf - $ODTFilePath = $SetupFolder - Write-LogEntry -Value "Attempting to download latest Office Deployment Toolkit executable" -Severity 1 - Start-DownloadFile -URL $WebResponseURL -Path $ODTFilePath -Name $ODTFileName + #Download latest Office setup.exe + $SetupEverGreenURL = "https://officecdn.microsoft.com/pr/wsus/setup.exe" + Write-LogEntry -Value "Attempting to download latest Office setup executable" -Severity 1 + Start-DownloadFile -URL $SetupEverGreenURL -Path $SetupFolder -Name "setup.exe" try{ - #Extract setup.exe from ODT Package - $ODTExecutable = (Join-Path -Path $ODTFilePath -ChildPath $ODTFileName) - $ODTExtractionPath = (Join-Path -Path $ODTFilePath -ChildPath (Get-ChildItem -Path $ODTExecutable).VersionInfo.ProductVersion) - $ODTExtractionArguments = "/quiet /extract:$($ODTExtractionPath)" - Write-LogEntry -Value "Attempting to extract the setup.exe executable from Office Deployment Toolkit" -Severity 1 - Start-Process -FilePath $ODTExecutable -ArgumentList $ODTExtractionArguments -NoNewWindow -Wait -ErrorAction Stop - $SetupFilePath = ($ODTExtractionPath | Get-ChildItem | Where-Object {$_.Name -eq "setup.exe"}).FullName - Write-LogEntry -Value "Setup file ready at $($SetupFilePath)" -Severity 1 + #Start install preparations + $SetupFilePath = Join-Path -Path $SetupFolder -ChildPath "setup.exe" + if (-Not (Test-Path $SetupFilePath)) { + Throw "Error: Setup file not found" + } + Write-LogEntry -Value "Setup file ready at $($SetupFilePath)" -Severity 1 try{ #Prepare Proofing tools installation or removal - Copy-Item -Path $SetupFilePath -Destination $SetupFolder -Force -ErrorAction Stop $OfficeCR2Version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$($SetupFolder)\setup.exe").FileVersion Write-LogEntry -Value "Office C2R Setup is running version $OfficeCR2Version" -Severity 1 Invoke-XMLUpdate -LanguageID $LanguageID -Filename "$($PSScriptRoot)\$($Filename)" -Action $Action @@ -195,7 +190,7 @@ try{ Try{ #Running office installer Write-LogEntry -Value "Starting Proofing tools $($LanguageID) $($Action) with Win32App method" -Severity 1 - $OfficeInstall = Start-Process "$($SetupFolder)\setup.exe" -ArgumentList "/configure $($SetupFolder)\$($Filename)" -NoNewWindow -Wait -PassThru -ErrorAction Stop + $OfficeInstall = Start-Process $SetupFilePath -ArgumentList "/configure $($SetupFolder)\$($Filename)" -NoNewWindow -Wait -PassThru -ErrorAction Stop } catch [System.Exception]{ Write-LogEntry -Value "Error running the Proofing tools $($LanguageID) $($Action). Errormessage: $($_.Exception.Message)" -Severity 3 @@ -213,4 +208,8 @@ try{ catch [System.Exception]{ Write-LogEntry -Value "Error downloading Office Deployment Toolkit. Errormessage: $($_.Exception.Message)" -Severity 3 } +#Cleanup +if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup"){ + Remove-Item -Path "$($env:SystemRoot)\Temp\OfficeSetup" -Recurse -Force -ErrorAction SilentlyContinue +} Write-LogEntry -Value "Proofing Tools $($LanguageID) $($Action) completed" -Severity 1 diff --git a/README.md b/README.md index 3e998ee..7febea7 100644 --- a/README.md +++ b/README.md @@ -9,21 +9,25 @@ Description: Deploying M365 with Intune dynamically as a Win32App [![HitCount](https://hits.dwyl.com/msendpointmgr/m365apps.svg?style=flat)](http://hits.dwyl.com/msendpointmgr/m365apps) # M365 Apps Intune scripted dynamic install using Office Deployment Toolkit -## This solution covers installation of the following products + +## This solution covers installation of the following products + * [M365 Apps(Office)](#main-office-package-getting-configuration-from-external-url) * [Project](#project-and-visio) * [Visio](#project-and-visio) * [Proofing tools](#proofing-tools) -Each product is made of the following components +Each product is made of the following components + * Install script (PowerShell) -* Local Configuration.xml or External URL +* Local Configuration.xml or External URL * Detection (script or documented) -*** +*** ## Main Office Package (getting configuration from External URL) 1. Define your config XML (Example below, can be generated at office.com) + ```xml @@ -45,21 +49,23 @@ Each product is made of the following components ``` + 1. Create a .Intunewim using the Win32 Content Prep tool [Prepare Win32 app content for upload](https://learn.microsoft.com/en-us/mem/intune/apps/apps-win32-prepare?WT.mc_id=EM-MVP-5002085) containing the InstallM365Apps.ps1 2. Upload .Intunewim and define the following parameters during install - * Install Command: + * Install Command: * ```powershell.exe -executionpolicy bypass -file InstallM365Apps.ps1 -XMLURL "https://mydomain.com/xmlfile.xml"``` - * Uninstall Command: - * ```powershell.exe -executionpolicy bypass -file InstallM365Apps.ps1 ``` (Not working yet) + * Uninstall Command: + * ```powershell.exe -executionpolicy bypass -file InstallM365Apps.ps1``` (Not working yet) Office Install XML * Install behaviour: System * Requirements (probable 64 bit Windows something) * Detection: Use PowerShell detection Script M365AppsWin32DetectionScript.ps1 - 1. Assign + 1. Assign *** + ## Main Office Package (using configuration.xml inside package) 1. Define your config XML (Example below, can be generated at office.com) @@ -86,14 +92,14 @@ Each product is made of the following components ``` 2. Create a .Intunewim using the Win32 Content Prep tool [Prepare Win32 app content for upload](https://learn.microsoft.com/en-us/mem/intune/apps/apps-win32-prepare?WT.mc_id=EM-MVP-5002085) containing the configuration.xml and the InstallM365Apps.ps1 2. Upload .Intunewim and define the following parameters during install - * Install Command: + * Install Command: * ```powershell.exe -executionpolicy bypass -file InstallM365Apps.ps1``` - * Uninstall Command: - * ```powershell.exe -executionpolicy bypass -file InstallM365Apps.ps1 ``` (Not working yet) - * Install behaviour: System + * Uninstall Command: + * ```powershell.exe -executionpolicy bypass -file InstallM365Apps.ps1``` (Not working yet) + * Install behaviour: System * Requirements (probable 64 bit Windows something) - * Detection: Use PowerShell detection Script M365AppsWin32DetectionScript.ps1 - 1. Assign + * Detection: Use PowerShell detection Script M365AppsWin32DetectionScript.ps1 + 1. Assign *** ## Project and Visio @@ -124,47 +130,62 @@ Each product is made of the following components * Follow others steps from the main office package. Office Install XML - Project Install Command (Local): -``` + +```PowerShell powershell.exe -executionpolicy bypass -file InstallProject.ps1 ``` + Project Install Command (ExternalXML): -``` + +```PowerShell powershell.exe -executionpolicy bypass -file InstallProject.ps1 -XMLURL "https://mydomain.com/xmlfile.xml" ``` Visio Install Command (Local): -``` +```PowerShell powershell.exe -executionpolicy bypass -file InstallVisio.ps1 ``` + Visio Install Command (ExternalXML): -``` + +```PowerShell powershell.exe -executionpolicy bypass -file InstallVisio.ps1 -XMLURL "https://mydomain.com/xmlfile.xml" ``` + *** -## Proofing tools -We recommend installing only 1 language on the computers unless your requirements are very specific. But there might still be need for proofing tools for multiple languages. The main thinking here is to have all possible proofing tools in your environment as available to end user to install by their own choosing. +## Proofing tools or LanguagePacks -For proofing tool the included configuration.xml files are just "templates" as the script it self will rewrite the XML dynamically based on the parameters you send to the script. +We recommend installing only 1 language on the computers unless your requirements are very specific. But there might still be some users that would need a complete language pack or proofing tools for various languages. The main thinking here is to have all possible proofing tools in your environment as available to end user to install by their own choosing. ->There is no need to maintain this XML as long as Microsoft does not change the XML requirements. +For these 2 options the included configuration.xml files are just "templates" as the script it self will rewrite the XML dynamically based on the parameters you send to the script. + +>There is no need to maintain this XML as long as Microsoft does not change the XML requirements. *** -**EXAMPLES for Proofing Tools** +**EXAMPLES for LanguagePacks** + +```PowerShell +powershell.exe -executionpolicy bypass -file InstallLanguagePacks.ps1 -LanguageID nb-no -Action Install +powershell.exe -executionpolicy bypass -file InstallLanguagePacks.ps1 -LanguageID nb-no -Action Uninstall ``` + + +**EXAMPLES for Proofing Tools** + +```PowerShell powershell.exe -executionpolicy bypass -file InstallProofingTools.ps1 -LanguageID nb-no -Action Install powershell.exe -executionpolicy bypass -file InstallProofingTools.ps1 -LanguageID nb-no -Action Uninstall ``` + Office Install XML Office Install XML *** -It is also recommended that you have a requirement to check if Main Office is installed on the device as the install will fail if you try to install the proofing tools without Office installed. -This can be done using a registry key check or using the provided requirement script +It is also recommended that you have a requirement to check if Main Office is installed on the device as the install will fail if you try to install the a language pack or proofing tools without Office installed. This can be done using a registry key check or using the provided requirement script. Office Install XML @@ -172,9 +193,16 @@ This can be done using a registry key check or using the provided requirement sc *** -Detection of the proofing tools can be done either with the provided detection script, customized for each LanguageID or by having a registry key check. +Detection of language packs is best using registry detection. Example Norwegian: + +* Key Path: **HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\O365ProPlusRetail - nb-no** +* Value Name: **DisplayName** +* String Comparison - Equals +* Microsoft 365 Apps for enterprise - nb-no + +Detection of the proofing tools can be done either with the provided detection script, customized for each LanguageID or by using a registry key check(Recommended). -EXAMPLE Detection Rule: +EXAMPLE Detection Rule: Registry Office Install XML diff --git a/VisioWin32App/InstallVisio.ps1 b/VisioWin32App/InstallVisio.ps1 index a143e8d..d723478 100644 --- a/VisioWin32App/InstallVisio.ps1 +++ b/VisioWin32App/InstallVisio.ps1 @@ -3,7 +3,7 @@ Script to install Visio as a Win32 App during Autopilot .DESCRIPTION - Script to install Visio as a Win32 App during Autopilot by downloading the latest Office Deployment Toolkit + Script to install Visio as a Win32 App during Autopilot by downloading the latest Office setup exe from evergreen url Running Setup.exe from downloaded files with provided config.xml file. .EXAMPLE @@ -13,7 +13,7 @@ powershell.exe -executionpolicy bypass -file InstallVisio.ps1 -XMLURL "https://mydomain.com/xmlfile.xml" .NOTES - Version: 1.1 + Version: 1.2 Author: Jan Ketil Skanke Contact: @JankeSkanke Creation Date: 01.07.2021 @@ -21,6 +21,7 @@ Version history: 1.0.0 - (2022-23-10) Script released 1.1.0 - (2022-25-10) Added support for External URL as parameter + 1.2.0 - (2022-23-11) Moved from ODT download to Evergreen url for setup.exe #> #region parameters [CmdletBinding()] @@ -118,26 +119,20 @@ if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup"){ $SetupFolder = (New-Item -ItemType "directory" -Path "$($env:SystemRoot)\Temp" -Name OfficeSetup -Force).FullName try{ - #Download latest Office Deployment Toolkit - $ODTDownloadURL = "https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117" - $WebResponseURL = ((Invoke-WebRequest -Uri $ODTDownloadURL -UseBasicParsing -ErrorAction Stop -Verbose:$false).links | Where-Object { $_.outerHTML -like "*click here to download manually*" }).href - $ODTFileName = Split-Path -Path $WebResponseURL -Leaf - $ODTFilePath = $SetupFolder - Write-LogEntry -Value "Attempting to download latest Office Deployment Toolkit executable" -Severity 1 - Start-DownloadFile -URL $WebResponseURL -Path $ODTFilePath -Name $ODTFileName + #Download latest Office setup.exe + $SetupEverGreenURL = "https://officecdn.microsoft.com/pr/wsus/setup.exe" + Write-LogEntry -Value "Attempting to download latest Office setup executable" -Severity 1 + Start-DownloadFile -URL $SetupEverGreenURL -Path $SetupFolder -Name "setup.exe" try{ - #Extract setup.exe from ODT Package - $ODTExecutable = (Join-Path -Path $ODTFilePath -ChildPath $ODTFileName) - $ODTExtractionPath = (Join-Path -Path $ODTFilePath -ChildPath (Get-ChildItem -Path $ODTExecutable).VersionInfo.ProductVersion) - $ODTExtractionArguments = "/quiet /extract:$($ODTExtractionPath)" - Write-LogEntry -Value "Attempting to extract the setup.exe executable from Office Deployment Toolkit" -Severity 1 - Start-Process -FilePath $ODTExecutable -ArgumentList $ODTExtractionArguments -NoNewWindow -Wait -ErrorAction Stop - $SetupFilePath = ($ODTExtractionPath | Get-ChildItem | Where-Object {$_.Name -eq "setup.exe"}).FullName + #Start install preparations + $SetupFilePath = Join-Path -Path $SetupFolder -ChildPath "setup.exe" + if (-Not (Test-Path $SetupFilePath)) { + Throw "Error: Setup file not found" + } Write-LogEntry -Value "Setup file ready at $($SetupFilePath)" -Severity 1 try{ #Prepare Office Installation - Copy-Item -Path $SetupFilePath -Destination $SetupFolder -Force -ErrorAction Stop $OfficeCR2Version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$($SetupFolder)\setup.exe").FileVersion Write-LogEntry -Value "Office C2R Setup is running version $OfficeCR2Version" -Severity 1 @@ -165,7 +160,7 @@ try{ Try{ #Running office installer Write-LogEntry -Value "Starting Visio Install with Win32App method" -Severity 1 - $OfficeInstall = Start-Process "$($SetupFolder)\setup.exe" -ArgumentList "/configure $($SetupFolder)\configuration.xml" -Wait -PassThru -ErrorAction Stop + $OfficeInstall = Start-Process $SetupFilePath -ArgumentList "/configure $($SetupFolder)\configuration.xml" -Wait -PassThru -ErrorAction Stop } catch [System.Exception]{ Write-LogEntry -Value "Error running the Visio install. Errormessage: $($_.Exception.Message)" -Severity 3 @@ -183,4 +178,8 @@ try{ catch [System.Exception]{ Write-LogEntry -Value "Error downloading Office Deployment Toolkit. Errormessage: $($_.Exception.Message)" -Severity 3 } +#Cleanup +if (Test-Path "$($env:SystemRoot)\Temp\OfficeSetup"){ + Remove-Item -Path "$($env:SystemRoot)\Temp\OfficeSetup" -Recurse -Force -ErrorAction SilentlyContinue +} Write-LogEntry -Value "Visio setup completed" -Severity 1