Scripts/CustomImageTemplateScripts/installLanguagePacks.ps1 (239 lines of code) (raw):
<#Author : Akash Chawla
# Usage : Install Language packs
#>
#######################################
# Install language packs #
#######################################
[CmdletBinding()]
Param (
[Parameter(
Mandatory
)]
[ValidateSet("Arabic (Saudi Arabia)","Bulgarian (Bulgaria)","Chinese (Simplified, China)","Chinese (Traditional, Taiwan)","Croatian (Croatia)","Czech (Czech Republic)","Danish (Denmark)","Dutch (Netherlands)", "English (United Kingdom)", "Estonian (Estonia)", "Finnish (Finland)", "French (Canada)", "French (France)", "German (Germany)", "Greek (Greece)", "Hebrew (Israel)", "Hungarian (Hungary)", "Italian (Italy)", "Japanese (Japan)", "Korean (Korea)", "Latvian (Latvia)", "Lithuanian (Lithuania)", "Norwegian, Bokmål (Norway)", "Polish (Poland)", "Portuguese (Brazil)", "Portuguese (Portugal)", "Romanian (Romania)", "Russian (Russia)", "Serbian (Latin, Serbia)", "Slovak (Slovakia)", "Slovenian (Slovenia)", "Spanish (Mexico)", "Spanish (Spain)", "Swedish (Sweden)", "Thai (Thailand)", "Turkish (Turkey)", "Ukrainian (Ukraine)")]
[System.String[]]$LanguageList,
[Parameter(
Mandatory
)]
[ValidateSet("Windows 11","Windows 10 - 1903","Windows 10 - 1909","Windows 10 - 20H1","Windows 10 - 20H2","Windows 10 - 21H1","Windows 10 - 21H2")]
[string]$WindowsVersion
)
function Set-Assets($WindowsVersion, [ref] $langDrive, [ref] $fodPath, [ref] $inboxAppDrive, [ref] $LangPackPath, $tempFolder) {
Begin {
# Set paths
$langIsoUrlIso = 'LanguagePack.iso'
$fodIsoUrlIso = 'FOD.iso'
$inboxAppsIsoUrlIso = 'InboxApps.iso'
$langOutputPath = (Join-Path -Path $tempFolder -ChildPath $langIsoUrlIso)
$fodOutputPath = (Join-Path -Path $tempFolder -ChildPath $fodIsoUrlIso)
$inboxAppsOutputPath = (Join-Path -Path $tempFolder -ChildPath $inboxAppsIsoUrlIso)
}
Process {
# Windows 11
if($WindowsVersion -eq "Windows 11") {
$langIsoUrl = 'https://software-download.microsoft.com/download/sg/22000.1.210604-1628.co_release_amd64fre_CLIENT_LOF_PACKAGES_OEM.iso'
$inboxAppsIsoUrl = 'https://software-download.microsoft.com/download/pr/22000.194.210911-1543.co_release_svc_prod1_amd64fre_InboxApps.iso'
# Starting ISO downloads
Invoke-WebRequest -Uri $langIsoUrl -OutFile $langOutputPath
Write-host "AVD AIB Customization: Finished Download for Language ISO for $WindowsVersion : $((Get-Date).ToUniversalTime()) "
# Mount ISOs
$langMount = Mount-DiskImage -ImagePath $langOutputPath
$langDrive.Value = ($langMount | Get-Volume).DriveLetter+":"
$LangPackPath.Value = $langDrive.Value+"\LanguagesAndOptionalFeatures"
$fodPath.Value = $langDrive.Value+"\LanguagesAndOptionalFeatures"
}
# Windows 10 - supported versions: 1903, 1909, 2004 (20H1), 20H2, 21H1, 21H2
else {
if($WindowsVersion -eq "Windows 10 - 1903" -or $WindowsVersion -eq "Windows 10 - 1909") {
$langIsoUrl = 'https://software-download.microsoft.com/download/pr/18362.1.190318-1202.19h1_release_CLIENTLANGPACKDVD_OEM_MULTI.iso'
$fodIsoUrl = 'https://software-download.microsoft.com/download/pr/18362.1.190318-1202.19h1_release_amd64fre_FOD-PACKAGES_OEM_PT1_amd64fre_MULTI.iso'
$inboxAppsIsoUrl = 'https://software-download.microsoft.com/download/pr/18362.1.190318-1202.19h1_release_amd64fre_InboxApps.iso'
}
else {
$langIsoUrl = 'https://software-download.microsoft.com/download/pr/19041.1.191206-1406.vb_release_CLIENTLANGPACKDVD_OEM_MULTI.iso'
$fodIsoUrl = 'https://software-download.microsoft.com/download/pr/19041.1.191206-1406.vb_release_amd64fre_FOD-PACKAGES_OEM_PT1_amd64fre_MULTI.iso'
if($WindowsVersion -eq "Windows 10 - 20H1") {
$inboxAppsIsoUrl = 'https://software-download.microsoft.com/download/pr/19041.1.191206-1406.vb_release_amd64fre_InboxApps.iso'
} elseif ($WindowsVersion -eq "Windows 10 - 20H2") {
$inboxAppsIsoUrl = 'https://software-download.microsoft.com/download/pr/19041.508.200905-1327.vb_release_svc_prod1_amd64fre_InboxApps.iso'
} elseif ($WindowsVersion -eq "Windows 10 - 21H1" -or $WindowsVersion -eq "Windows 10 - 21H2") {
$inboxAppsIsoUrl = 'https://software-download.microsoft.com/download/sg/19041.928.210407-2138.vb_release_svc_prod1_amd64fre_InboxApps.iso'
}
}
# Starting ISO downloads
Invoke-WebRequest -Uri $langIsoUrl -OutFile $langOutputPath
Write-host "AVD AIB Customization: Finished Download for Language ISO for $WindowsVersion : $((Get-Date).ToUniversalTime()) "
Invoke-WebRequest -Uri $fodIsoUrl -OutFile $fodOutputPath
Write-host "AIB Customization: Finished Download for Feature on Demand (FOD) Disk 1 for $WindowsVersion : $((Get-Date).ToUniversalTime()) "
$langMount = Mount-DiskImage -ImagePath $langOutputPath
$fodMount = Mount-DiskImage -ImagePath $fodOutputPath
$langDrive.Value = ($langMount | Get-Volume).DriveLetter+":"
$fodPath.Value = ($fodMount | Get-Volume).DriveLetter+":"
$LangPackPath.Value = Join-Path $langdrive.Value -ChildPath "\x64\langpacks"
}
Invoke-WebRequest -Uri $inboxAppsIsoUrl -OutFile $inboxAppsOutputPath
Write-host "AIB Customization: Finished Download for Inbox Apps for $WindowsVersion : $((Get-Date).ToUniversalTime()) "
$inboxAppsMount = Mount-DiskImage -ImagePath $inboxAppsOutputPath
$inboxAppDrive.Value = ($inboxAppsMount | Get-Volume).DriveLetter+":"
}
End {
}
}
function Install-LanguagePack {
<#
Function to install language packs along with features on demand and inbox apps
Based on the language parameter, this function installs language packs along with the necessary features on demand (FOD) and inbox apps. Not all FODs are available for each language - this function
will install the FODs based on the mapping here: https://download.microsoft.com/download/7/6/0/7600F9DC-C296-4CF8-B92A-2D85BAFBD5D2/Windows-10-1809-FOD-to-LP-Mapping-Table.xlsx
#>
BEGIN {
$templateFilePathFolder = "C:\AVDImage"
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
Write-host "Starting AVD AIB Customization: Install Language packs: $((Get-Date).ToUniversalTime()) "
# Disable Language Pack Cleanup
Disable-ScheduledTask -TaskPath "\Microsoft\Windows\AppxDeploymentClient\" -TaskName "Pre-staged app cleanup" | Out-Null
$fodPath = ""
$langDrive = ""
$LangPackPath = ""
$inboxAppDrive = ""
$guid = [guid]::NewGuid().Guid
$tempFolder = (Join-Path -Path "C:\temp\" -ChildPath $guid)
if (!(Test-Path -Path $tempFolder)) {
New-Item -Path $tempFolder -ItemType Directory
}
Set-Location $tempFolder
Set-Assets -WindowsVersion ($WindowsVersion) -langDrive ([ref] $langDrive) -fodPath ([ref] $fodPath) -langPackPath ([ref] $LangPackPath) -inboxAppDrive ([ref] $inboxAppDrive) -tempFolder $tempFolder
#$langPackPath = "H:\x64\langpacks"
#$fodPath = "F:"
#$inboxAppDrive = "G:"
Invoke-WebRequest https://raw.githubusercontent.com/achawla5/PSScripts/main/Windows-10-1809-FOD-to-LP-Mapping-Table.csv -OutFile .\LPtoFODFile.csv
$LPtoFODFile = ".\LPtoFODFile.csv"
#Check for Language mapping file
if (-not (Test-Path $LPtoFODFile )) {
Write-Error "Could not validate that $LPtoFODFile file exists in this location"
exit
}
$LPtoFODMapping = Import-Csv $LPtoFODFile
# populate dictionary
$LanguagesDictionary = @{}
$LanguagesDictionary.Add("Arabic (Saudi Arabia)", "ar-SA")
$LanguagesDictionary.Add("Bulgarian (Bulgaria)", "bg-BG")
$LanguagesDictionary.Add("Chinese (Simplified, China)", "zh-CN")
$LanguagesDictionary.Add("Chinese (Traditional, Taiwan)", "zh-TW")
$LanguagesDictionary.Add("Croatian (Croatia)", "hr-HR")
$LanguagesDictionary.Add("Czech (Czech Republic)", "cs-CZ")
$LanguagesDictionary.Add("Danish (Denmark)", "da-DK")
$LanguagesDictionary.Add("Dutch (Netherlands)", "nl-NL")
$LanguagesDictionary.Add("English (United States)", "en-US")
$LanguagesDictionary.Add("English (United Kingdom)", "en-GB")
$LanguagesDictionary.Add("Estonian (Estonia)", "et-EE")
$LanguagesDictionary.Add("Finnish (Finland)", "fi-FI")
$LanguagesDictionary.Add("French (Canada)", "fr-CA")
$LanguagesDictionary.Add("French (France)", "fr-FR")
$LanguagesDictionary.Add("German (Germany)", "de-DE")
$LanguagesDictionary.Add("Greek (Greece)", "el-GR")
$LanguagesDictionary.Add("Hebrew (Israel)", "he-IL")
$LanguagesDictionary.Add("Hungarian (Hungary)", "hu-HU")
$LanguagesDictionary.Add("Indonesian (Indonesia)", "id-ID")
$LanguagesDictionary.Add("Italian (Italy)", "it-IT")
$LanguagesDictionary.Add("Japanese (Japan)", "ja-JP")
$LanguagesDictionary.Add("Korean (Korea)", "ko-KR")
$LanguagesDictionary.Add("Latvian (Latvia)", "lv-LV")
$LanguagesDictionary.Add("Lithuanian (Lithuania)", "lt-LT")
$LanguagesDictionary.Add("Norwegian, Bokmål (Norway)", "nb-NO")
$LanguagesDictionary.Add("Polish (Poland)", "pl-PL")
$LanguagesDictionary.Add("Portuguese (Brazil)", "pt-BR")
$LanguagesDictionary.Add("Portuguese (Portugal)", "pt-PT")
$LanguagesDictionary.Add("Romanian (Romania)", "ro-RO")
$LanguagesDictionary.Add("Russian (Russia)", "ru-RU")
$LanguagesDictionary.Add("Serbian (Latin, Serbia)", "sr-Latn-RS")
$LanguagesDictionary.Add("Slovak (Slovakia)", "sk-SK")
$LanguagesDictionary.Add("Slovenian (Slovenia)", "sl-SI")
$LanguagesDictionary.Add("Spanish (Mexico)", "es-MX")
$LanguagesDictionary.Add("Spanish (Spain)", "es-ES")
$LanguagesDictionary.Add("Swedish (Sweden)", "sv-SE")
$LanguagesDictionary.Add("Thai (Thailand)", "th-TH")
$LanguagesDictionary.Add("Turkish (Turkey)", "tr-TR")
$LanguagesDictionary.Add("Ukrainian (Ukraine)", "uk-UA")
} # Begin
PROCESS {
foreach ($Language in $LanguageList) {
$LanguageCode = $LanguagesDictionary.$Language
$LanguagePackPath = "$LangPackPath\Microsoft-Windows-Client-Language-Pack_x64_$LanguageCode.cab"
try {
Add-WindowsPackage -Online -PackagePath $LanguagePackPath -NoRestart -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null
}
catch {
Write-Host "AVD AIB Customization : Exception occured with language pack: $LanguagePackPath - [$($_.Exception.Message)]"
continue
}
$FODList = $LPtoFODMapping | Where-Object { $_.'Target Lang' -eq $LanguageCode }
if (($FODList | Measure-Object).Count -ne 0){
foreach ($file in $FODList.'Cab Name') {
$FODFilePath = Get-ChildItem (Join-Path $fodPath $file.replace('.cab', '*.cab'))
if ($null -eq $FODFilePath) {
Write-Host "AVD AIB Customization : Could not find $FODFilePath"
break
}
try {
$PackageName = $FODFilePath.FullName
Add-WindowsPackage -Online -PackagePath $PackageName -NoRestart -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null
}
catch {
Write-Host "AVD AIB Customization : Exception occured while adding package $PackageName : [$($_.Exception.Message)]"
continue
}
}
}
# Update Inbox Apps
# reference https://docs.microsoft.com/en-us/azure/virtual-desktop/language-packs
$inboxAppPath = $inboxAppDrive + "\arm64fre\"
foreach ($App in (Get-AppxProvisionedPackage -Online)) {
$AppPath = $inboxAppPath + $App.DisplayName + '_' + $App.PublisherId
$licFile = Get-Item $AppPath*.xml
try {
if ($licFile.Count) {
$lic = $true
$licFilePath = $licFile.FullName
} else {
$lic = $false
}
$appxFile = Get-Item $AppPath*.appx*
if ($appxFile.Count) {
$appxFilePath = $appxFile.FullName
if ($lic) {
Add-AppxProvisionedPackage -Online -PackagePath $appxFilePath -LicensePath $licFilePath -ErrorAction Stop
} else {
Add-AppxProvisionedPackage -Online -PackagePath $appxFilePath -skiplicense -ErrorAction Stop
}
}
}
catch {
Write-Host "AVD AIB Customization : Exception occured with inbox app package: $AppPath - [$($_.Exception.Message)]"
continue;
}
}
try {
Write-Host "AVD AIB CUSTOMIZER PHASE : Install language packs : Adding $LanguageCode to WinUserLanguageList"
$WinUserLanguageList = Get-WinUserLanguageList -ErrorAction Stop
$WinUserLanguageList.Add("$LanguageCode")
Set-WinUserLanguageList -LanguageList $WinUserLanguageList -Force -ErrorAction Stop
}
catch {
Write-Host "AVD AIB Customization : Failed to add $LanguageCode to WinUserLanguageList - [$($_.Exception.Message)]"
}
}
} #Process
END {
#Cleanup
if ((Test-Path -Path $tempFolder -ErrorAction SilentlyContinue)) {
Remove-Item -Path $tempFolder -Force -Recurse -ErrorAction Continue
}
if ((Test-Path -Path $templateFilePathFolder -ErrorAction SilentlyContinue)) {
Remove-Item -Path $templateFilePathFolder -Force -Recurse -ErrorAction Continue
}
$stopwatch.Stop()
$elapsedTime = $stopwatch.Elapsed
Write-Host "*** AVD AIB CUSTOMIZER PHASE : Install language packs - Exit Code: $LASTEXITCODE ***"
Write-Host "Ending AVD AIB Customization : Install language packs - Time taken: $elapsedTime"
}
}
Install-LanguagePack -LanguageList $LanguageList -WindowsVersion $WindowsVersion