Automating Language Pack Installation with PowerShell and SCCM

 

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
  • Language Code Mapping

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
  1. Initialization
    • Registry and log folders are created (Dummy Script)
  2. User Interaction
    • User selects region and language
    • Values stored in SCCM and registry
  3. Installation
    • DISM installs language pack CAB files
    • Status is evaluated and logged
  4. 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.