Managing language
packs across enterprise devices is often a complex and user-dependent process.
This PowerShell-based solution simplifies the entire lifecycle of language
pack deployment, from user selection to installation and status tracking,
making it scalable and enterprise-ready.
This implementation
consists of three coordinated components:
- Dummy Package Script (initialization and registry setup)
- User Prompt Script (region/language selection and user
interaction)
- Installation Script (DISM-based language pack deployment)
Together, these
scripts provide a complete, automated workflow for multilingual environments.
- Overview of the Solution
The solution is
designed to:
- Allow users to select region and
preferred language
- Store selections using SCCM task
sequence variables and registry
- Install language packs dynamically using DISM
- Provide user feedback (success/failure
popups)
- Maintain centralized logging for
auditing and troubleshooting
- 1. Dummy Package Script (Initialization
Layer)
The dummy script
prepares the environment by ensuring the required registry structure exists.
- Key Functionality:
- Creates registry path:
- HKLM:\SOFTWARE\LPs
- Initializes logging at:
- C:\ProgramData\\LogFiles
- Logs whether the registry path was newly
created or already exists
- Purpose:
This acts as a foundation
step to track installation state and user selections consistently across
the deployment lifecycle.
- 2. User Prompt Script (Interactive Layer)
This script provides a
Windows Forms-based UI for users to select their region and
corresponding language.
- Key Features:
- Region-to-Language Mapping
- Regions (Asia, Europe, America)
dynamically populate language options
- Ensures users only select valid
combinations
Each display language
is mapped to its system language code (e.g., de-DE, en-US, ja-JP), which is
used later during installation.
- User Validation
- Prevents users from proceeding without
selecting both region and language
- Displays warning messages if inputs are
incomplete
- Task Sequence Integration
The script stores
selections in SCCM variables:
- Region
- DisplayLanguage
- Registry Updates
Stores:
- Installation status (PromptCompleted,
Success, Failed)
- Selected language code
- User Feedback
Provides:
- Success popup → On completion
- Failure popup → On installation issues
- 3. Language Pack Installation Script
(Execution Layer)
This script performs
the actual installation using DISM (Deployment Image Servicing and
Management).
- Key Functionality:
- Automatic CAB Detection
- Detects all .cab files in the package
directory
- Supports multiple components per language
pack
- Installation Execution
Runs:
PowerShell
dism /Online
/Add-Package /PackagePath:<cab file>
Show more lines
- Processes each CAB sequentially
- Logs both success and failure
- Error Handling
- Tracks installation status using
$LASTEXITCODE
- Sets overall success flag based on results
- SCCM Integration
Sets Task Sequence
variable:
- allSuccess = LPsuccess → if all packages
installed
- allSuccess = LPfail → if any package fails
- Logging Strategy
All scripts use a
consistent logging approach:
Log Location:
C:\ProgramData\LogFiles
Captured Details:
- Script start and end events
- User selections
- Installation status
- Errors and command output
This ensures full traceability
across all deployment stages.
- End-to-End Workflow
- Initialization
- Registry and log folders are created
(Dummy Script)
- User Interaction
- User selects region and language
- Values stored in SCCM and registry
- Installation
- DISM installs language pack CAB files
- Status is evaluated and logged
- Post Execution
- Success or failure popup displayed
- Registry updated with final state
- Key Benefits
- ✅ User-Friendly
Interactive UI ensures
correct language selection and reduces deployment errors.
- ✅ Scalable
Designed for
enterprise rollout using SCCM task sequences.
- ✅ Automated
Eliminates manual
language pack installation processes.
- ✅ Reliable
Error handling and
status tracking ensure consistent outcomes.
- ✅ Transparent
Centralized logging
provides full visibility for administrators.
- Use Cases
This solution is ideal
for:
- Global organizations with multilingual workforce
- Device provisioning workflows requiring regional configurations
- Standardized OS deployments with dynamic localization
- User-driven customization within
controlled boundaries
- Conclusion
This PowerShell-based
language pack deployment solution demonstrates how enterprise automation can
balance user interaction and centralized control. By combining UI-driven
selection, registry tracking, SCCM integration, and DISM execution, it provides
a complete and scalable approach to multilingual device management.
It ensures that
devices are configured correctly based on regional needs while maintaining
compliance, automation, and operational efficiency.
- ✅ Final Combined Search Description
Main Version:
Automate Windows language pack deployment using PowerShell with user-driven
region and language selection, SCCM integration, DISM-based installation,
centralized logging, registry tracking, and enterprise-ready workflow
management.
Dummy script:
# Define variables
$regPath = "HKLM:\SOFTWARE\LPs"
$logFolder = "C:\ProgramData\LogFiles"
$logFile = Join-Path $logFolder "LangPackInstallation_application.log"
# Ensure log directory
exists
if (-not (Test-Path $logFolder)) {
New-Item -Path $logFolder -ItemType Directory -Force | Out-Null
}
# Logging function
function Write-Log {
param ([string]$Message)
$timestamp = Get-Date -Format "yyyy-MM-dd
HH:mm:ss"
"$timestamp - $Message" | Out-File -FilePath $logFile -Append -Encoding UTF8
}
# Check and create registry
path if missing
if (-not (Test-Path $regPath)) {
New-Item -Path $regPath -Force | Out-Null
Write-Host "Registry
path created: $regPath"
Write-Log "Registry
path created: $regPath"
} else {
Write-Host "Registry
path already exists: $regPath"
Write-Log "Registry
path already exists: $regPath"
}
Region selection:
param (
[ValidateSet("Prompt", "SuccessPopup", "FailedPopup")]
[string]$Action = "Prompt"
)
Add-Type -AssemblyName System.Windows.Forms
# Define log path
$LogPath = "C:\ProgramData\LogFiles"
$LogFile = Join-Path $LogPath "LangPackInstallation.log"
if (-not (Test-Path $LogPath)) {
New-Item -Path $LogPath -ItemType Directory -Force | Out-Null
}
function Write-Log {
param ([string]$Message)
$timestamp = Get-Date -Format "yyyy-MM-dd
HH:mm:ss"
"$timestamp - $Message" | Out-File -FilePath $LogFile -Append -Encoding UTF8
}
function Set-RegistryStatus {
param (
[string]$Status,
[string]$LangCode = ""
)
$regPath = "HKLM:\SOFTWARE\LPs"
if (-not (Test-Path $regPath)) {
New-Item -Path $regPath -Force | Out-Null
}
Set-ItemProperty -Path $regPath -Name "Status" -Value $Status -Force
if ($LangCode) {
Set-ItemProperty -Path $regPath -Name "Language" -Value $LangCode -Force
}
Write-Log "Registry
updated: Status=$Status, Language=$LangCode"
}
function Show-RegionLangPrompt {
Write-Log "==========
Starting Region & Language Prompt =========="
$RegionLangMap = @{
"Asia" = @("Chinese (Simplified)", "Chinese
(Traditional)", "Japanese", "Korean")
"Europe" = @("English (UK)", "French", "German", "Italian", "Spanish (Spain)")
"America" = @("English (US)", "Portuguese (Brazil)")
}
$DisplayToLangCode = @{
"Korean"
= "ko-KR"
"Chinese (Simplified)" = "zh-CN"
"Chinese (Traditional)"= "zh-TW"
"Japanese"
= "ja-JP"
"French"
= "fr-FR"
"German"
= "de-DE"
"Spanish (Spain)" = "es-ES"
"English (US)" = "en-US"
"English (UK)" = "en-GB"
"Portuguese (Brazil)" = "pt-BR"
"Italian" = "it-IT"
}
$form = New-Object Windows.Forms.Form
$form.Text = "Select Region and Language"
$form.StartPosition
= "CenterScreen"
$form.FormBorderStyle
= 'FixedDialog'
$form.MaximizeBox
= $false
$form.MinimizeBox
= $false
$form.Size = New-Object Drawing.Size(480, 220)
$regionLabel = New-Object Windows.Forms.Label
$regionLabel.AutoSize
= $true
$regionLabel.Text = "Select Region:"
$regionLabel.Location
= New-Object Drawing.Point(10, 20)
$form.Controls.Add($regionLabel)
$regionBox = New-Object Windows.Forms.ComboBox
$regionBox.Location
= New-Object Drawing.Point(10, 55)
$regionBox.Width = 200
$regionBox.DropDownStyle
= 'DropDownList'
$regionBox.Items.AddRange($RegionLangMap.Keys)
$form.Controls.Add($regionBox)
$langLabel = New-Object Windows.Forms.Label
$langLabel.AutoSize
= $true
$langLabel.Text = "Select Language:"
$langLabel.Location
= New-Object Drawing.Point(10, 80)
$form.Controls.Add($langLabel)
$langBox = New-Object Windows.Forms.ComboBox
$langBox.Location
= New-Object Drawing.Point(10, 115)
$langBox.Width = 200
$langBox.DropDownStyle
= 'DropDownList'
$form.Controls.Add($langBox)
$regionBox.Add_SelectedIndexChanged({
$langBox.Items.Clear()
$selectedRegion = $regionBox.SelectedItem
Write-Log "Region
selected: $selectedRegion"
if ($RegionLangMap.ContainsKey($selectedRegion)) {
$RegionLangMap[$selectedRegion] | ForEach-Object {
[void]$langBox.Items.Add($_)
}
}
})
$okBtn = New-Object Windows.Forms.Button
$okBtn.Text = "OK"
$okBtn.Location
= New-Object Drawing.Point(240, 150)
$okBtn.Width = 100
$okBtn.Add_Click({
if ($regionBox.SelectedItem
-and $langBox.SelectedItem)
{
$selectedRegion = $regionBox.SelectedItem
$displayLang = $langBox.SelectedItem
$langCode = $DisplayToLangCode[$displayLang]
Write-Log "User
selected Language: $displayLang => Code: $langCode"
$form.Tag = @{
Region = $selectedRegion
Language = $langCode
}
$form.Close()
} else {
Write-Log "User
attempted to proceed without selecting Region/Language"
[System.Windows.Forms.MessageBox]::Show("Please
select both Region and Language.", "Selection
Required", "OK", "Warning")
}
})
$form.Controls.Add($okBtn)
$form.ShowDialog()
| Out-Null
if ($form.Tag) {
try {
$tsEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment
$tsEnv.Value("Region") = $form.Tag.Region
$tsEnv.Value("DisplayLanguage") = $form.Tag.Language
Write-Log "TS
Variables Set: Region=$($form.Tag.Region),
Language=$($form.Tag.Language)"
Set-RegistryStatus -Status "PromptCompleted" -LangCode $form.Tag.Language
} catch {
Write-Log "Failed
to set TS variables: $_"
}
} else {
Write-Log "User
canceled or closed the form without selection."
}
Write-Log "==========
End of Script =========="
}
function Show-LPSuccessPopup {
[System.Windows.Forms.MessageBox]::Show(
"Language
Pack Installation Completed Successfully.",
"Language
Pack Success",
[System.Windows.Forms.MessageBoxButtons]::OK,
[System.Windows.Forms.MessageBoxIcon]::Information
)
Write-Log "==========
Start of Script =========="
Write-Log "Language
Pack Installation Completed Successfully."
Set-RegistryStatus -Status "Success"
Write-Log "==========
End of Script =========="
}
function Show-LPFailedPopup {
[System.Windows.Forms.MessageBox]::Show(
"Language
Pack installation failed. Please contact IT support.",
"Language
Pack Failure",
[System.Windows.Forms.MessageBoxButtons]::OK,
[System.Windows.Forms.MessageBoxIcon]::Error
)
Write-Log "==========
Start of Script =========="
Write-Log "Language
Pack installation failed. Please contact IT support."
Set-RegistryStatus -Status "Failed"
Write-Log "==========
End of Script =========="
}
# Execute based on action
switch ($Action) {
"Prompt"
{ Show-RegionLangPrompt }
"SuccessPopup" { Show-LPSuccessPopup }
"FailedPopup" { Show-LPFailedPopup }
}
LP installation
script:
$language = Split-Path -Leaf (Split-Path -Parent $MyInvocation.MyCommand.Definition)
$LogFolder = "C:\ProgramData\LogFiles"
$LogFile = Join-Path $LogFolder "LangPackInstallation.log"
if (-not (Test-Path $LogFolder)) {
New-Item -Path $LogFolder -ItemType Directory -Force | Out-Null
}
function Write-Log {
param([string]$Message)
$timestamp = Get-Date -Format "yyyy-MM-dd
HH:mm:ss"
"$timestamp - $Message" | Out-File -FilePath $LogFile -Append -Encoding utf8
}
Write-Log "=====
Starting LP install for $language ====="
$cabFiles = Get-ChildItem -Path $PSScriptRoot -Filter *.cab
$allSuccess = $true
foreach ($cab in $cabFiles) {
Write-Host "Installing:
$($cab.Name)"
Write-Log "Installing:
$($cab.Name)"
$output = dism /Online /Add-Package /PackagePath:$($cab.FullName)
2>&1
if ($LASTEXITCODE -ne 0) {
Write-Log "Failed:
$($cab.Name)"
Write-Log $output
$allSuccess = $false
} else {
Write-Log "Installed:
$($cab.Name)"
}
}
# Set TS variable after
completion
try {
$tsEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment
if ($allSuccess) {
$tsEnv.Value("allSuccess") = "LPsuccess"
Write-Log "All
CABs installed successfully. TS variable 'allSuccess' set to LPsuccess"
} else {
$tsEnv.Value("allSuccess") = "LPfail"
Write-Log "One
or more CABs failed. TS variable 'allSuccess' set to LPfail"
}
} catch {
Write-Log "Failed
to set TS variable: $_"
}
Write-Log "==========
End of Script =========="
No comments:
Post a Comment
Leave your valuable words here for improve better.