PowerShell GUI for Downloading Language Packs - W10_11LangPack.ps1

Strange thing with these language files, Ntlite shows that everything has integrated and after uploading the system can not change the language as if these files did not integrate
 
Language Packs must always be integrated first, before applying updates or removals. The best way is to do two runs:
1. Load clean image, add LPs. Make new image.
2. Load image, continue with other changes.
 
I get an error by running W10_11LangPack.ps1 after the selection 22H2 Win11 NL,FR,DE etc..
My location i am running is on C:\Temp. Other versions it works.

Can someone help me?

Test-Path : Cannot bind argument to parameter 'Path' because it is null.
 
Last edited:
Test-Path is null could be UUP dump acting up (due to recent stability problems). I tried W10 21H2 (same as 22H2) NL, and it was working.
If you have a specific repeat case, let me know.
 
I've written a PowerShell GUI to download Language Packs for most versions of Windows 10 & 11.
This replaces searching UUP dump or rg-adguard for the correct version, downloading the links and renaming files.

We're still using UUP dump to generate the expiring download links. The script will skip files with identical names in the current folder.

View attachment 6951

Code:
Downloading "Microsoft-Windows-Client-LanguagePack-Package_cs-cz-amd64-cs-cz.esd"
Downloading "Microsoft-Windows-LanguageFeatures-Basic-cs-cz-Package-amd64.cab"
Downloading "Microsoft-Windows-LanguageFeatures-Handwriting-cs-cz-Package-amd64.cab"
Downloading "Microsoft-Windows-LanguageFeatures-OCR-cs-cz-Package-amd64.cab"
Downloading "Microsoft-Windows-LanguageFeatures-TextToSpeech-cs-cz-Package-amd64.cab"

SHA-1 Hash:
e7b2986577196a4dd08693327a7209dae02545e5  Microsoft-Windows-Client-LanguagePack-Package_cs-cz-amd64-cs-cz.esd
4e6b61b4e3654d03d765bbf59ab6fc45eb5b4c2f  Microsoft-Windows-LanguageFeatures-Basic-cs-cz-Package-amd64.cab
4ef0b346760bb818b830b218296c5bfd7b11d38d  Microsoft-Windows-LanguageFeatures-Handwriting-cs-cz-Package-amd64.cab
702a8eddbc454768efabb4c04ea540b464a6b7de  Microsoft-Windows-LanguageFeatures-OCR-cs-cz-Package-amd64.cab
f980392aca2b3d424c8ca73446beb7e8026bb14f  Microsoft-Windows-LanguageFeatures-TextToSpeech-cs-cz-Package-amd64.cab

What versions are supported?
  • Win 11 22H2
  • Win 11 22H1
  • Win 10 2004, 20H2, 21H1 & 21H2 are the same family
  • Win 10 1903 & 1909 are the same family
  • Win 10 1809
Win 10 below 1809 isn't supported (why are you still using it?). Server 2022 isn't here, because the language selection is severely limited.

Do I need ESD2CAB?
Yes, click on the GUI's download link to open abbodi's GitHub.

Why do I get a PowerShell execution policy error?
Your default execution policy prevents unsigned scripts from running. Run the W10_11LP.bat instead.

How do I check if the downloaded packages are the correct version?
When files are downloaded, the script will report the SHA-1 values.

You can compare the SHA-1 against UUPdump (select a Windows build, under Browse Files / Search enter "language").
ie. https://uupdump.net/findfiles.php?id=a84eaaea-f57c-4271-a642-4abf996a7101&q=language

Why do you use a different UUP than abbodi's W10MUI?
Language Packs are some of the first packages built, and they're shared across later versions in the same family. While my reference builds are different, all packages have identical SHA-1 values to abbodi's UUP's. There's no functional difference btw them.

If you're bored, my versions are listed in the script.

What about Win 7 & 8 versions?
There's a different script for you (included in the ZIP), because the languages list isn't the same as W10/11.
While you could just copy the URL from pastebin or other sources, I already wrote a GUI.

View attachment 6952

How hard was it writing the GUI?
When you find a good WinForms code example, it's easy to modify and make your own layout. I moved and sized the visual elements by hand.
If you noticed, the OK button isn't active until the user selects from all menu boxes. And W11 doesn't have a x86 version, checking that option always gets unselected.

I used this program to download and use the english language pack with Windows 10 Pro 20H2. I converted the downloaded ESD language to cab with ESD2CAB tool. Then tried to install the converted language in Windows via "lpksetup" but failed. Any solution ?
 

Attachments

  • Capture0.JPG
    Capture0.JPG
    18.3 KB
  • Capture1.JPG
    Capture1.JPG
    102.3 KB
I don’t know what the problem was with the previous version of ESD2CAB, but, I tried this and worked successfully. Thanks a lot. Maybe garlin update his script, to link the new updated version ? ;)
 
Last edited:
garlin another thing I've noticed and might make someone a little confused (as shown below in pictures). Maybe it's nothing but posting anyway!! ;):p
 

Attachments

  • First Post.PNG
    First Post.PNG
    7.2 KB
  • Script.PNG
    Script.PNG
    16.1 KB
Hi!
EDIT4: The full working solution is now at: https://github.com/Harze2k/PowerShell/blob/main/Intune/Install-LanguageCabs
Got limited here with the size of the code haha :) Also bonus, the script is actually working, running parallel jobs to finish as quick as possible. \o/
Watch out for when uudump change their site though, might mess things up though..

Just wanted to share a modification i did based on OP:s excellent script :)
Its a script i use today in production to set language on windows 11 machines based on the computername prefix.
Code:
Function Install-LanguageCabs {
    param (
    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Language,
    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({ 
        if ($_ -notin 'arm', 'amd64') {
            throw "The Arch parameter must be either 'amd64' or 'arm'. amd64 is for standard x64. x86 doesnt work at all from what iv seen."
        }
        return $true
    })]
    [String]$Arch,
    [Switch]$Install,
    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({
        if ($_ -ne ".\") {
            New-Item -Path $_ -ItemType Directory -Force -ErrorAction SilentlyContinue
            Set-Location $_
        }   return $true
    })]
    [String]$Path,
    [Parameter(Mandatory=$false)]
    [ValidateScript({
        if (-not ($_)) {
            throw "The Build parameter cannot be empty or null."
        }
        if (-not ($_ -match '\d{5}\.\d+$')) {
            throw "Build string must be 5 digits.anynumberofdigits so i.e 25300.457"
        }return $true
    })]
    [String]$Build,
    [Parameter(Mandatory=$true)]
    [ValidateScript({ 
        if ($_ -notin '10','11') {
            throw "The Os parameter must be either '10' or '11'."
        }
        return $true
    })]
    [String]$Os,
    [Switch]$LocalRepository,
    [Parameter(Mandatory=$false)]
    [ValidateScript({
        if (-not ($_)) {
            throw "The LocalRepositoryPath parameter cannot be empty or null."
        }
        if (-not (Test-Path "$_\$Os\$Build\$language\*.cab" -PathType Any)) {
            throw "The path specified ""$_\$Os\$Build\$language"" in the LocalRepositoryPath parameter does not exist. Or the path doesnt contain any cab files to install."
        }   return $true
    })]
    [String]$LocalRepositoryPath,
    [Parameter(Mandatory=$true)]
    [ValidateScript({
        if (-not ($_)) {
            throw "The ToastImage parameter cannot be empty or null."
        }
        if (-not (Test-Path $_ -PathType Any)) {
            throw "The path specified ""$_"" in the ToastImage parameter does not exist. It needs to point directly to the full path or a image file."
        }   return $true
    })]
    [String]$ToastImage,
    [string]$ProgressFile)
    Start-Transcript -Path "C:\Temp\Intune\Scripts\TransLogOOBEInstallCAB.log" -Force -Verbose -ErrorAction SilentlyContinue
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13
    $WebResponse = (Invoke-WebRequest -Uri "https://uupdump.net/known.php?q=windows+$($Os)+$($Build -replace '10.0.','')" -UseBasicParsing -MaximumRedirection 1 -Method GET).Links
    #if ($null -ne $WebResponse) {
    $href= ($WebResponse | Where-Object { $_.href -match "./selectlang.php\?id"} -ErrorAction SilentlyContinue)
    $UpdateID = (($href | Where-Object {$_.outerHTML -match $Arch}).href).split("=")[1]
    try {
        $Links = (Invoke-WebRequest -UseBasicParsing -Uri "https://uupdump.net/get.php?id=$UpdateID&pack=$Language&edition=core" -Method GET -MaximumRedirection 1).Links
    }
    catch {
        $_.Exception.Message
        $Install = $null
        $Links=$null
    }
    if($Links) {
        $Lang = $Language.Split('-')[0]
        foreach ($link in ($Links.outerHTML -match ".*(Language|LanguageFeatures).*$Lang-.*")) {
            $URL = $link.Split('"')[1]
            $Filename = $link.Split('>')[1].Split('<')[0] -replace '\s',''
            $PackageName = ($Filename -split ('[_-]' + $Lang))[0]
            $Filename = $Filename.Replace($PackageName,[cultureinfo]::GetCultureInfo('en-US').TextInfo.ToTitleCase($PackageName))
            $Filename = $Filename.TrimStart('Cabs_')
            $Filename = $Filename.Replace('Ocr','OCR')
            foreach ($word in ('Pack','Feat','ToSpeech')) {
                $Filename = $Filename.Replace($word.ToLower(),$word)
            }
            Write-Host $filename
            if (-not (Test-Path -LiteralPath $Filename -PathType Leaf)) {
                try {
                    if ($LocalRepository){
                        Copy-Item -LiteralPath "$LocalRepositoryPath\$Os\$Build\$language\*.cab" -Destination .\ -Force
                    }
                    else {
                        Invoke-WebRequest -UseBasicParsing -Uri $URL -Headers $Headers -OutFile $Filename -ErrorAction SilentlyContinue
                        Write-Host "Downloading: $Filename to path: $Path" -ForegroundColor Blue
                    }
                }
                catch {
                    $_.Exception.Message
                }
            }
            else {
                Write-Host "No download needed, File: $Filename exist in path: $Path" -ForegroundColor Green     
            }
        }
    }
    else {
        Write-Host "Was a problem downloading from: " -NoNewline -ForegroundColor Red
        Write-Host "https://uupdump.net/get.php?id=$UpdateID&pack=$Language&edition=core"
        if (Test-Path -Path $path -Filter "\(Microsoft-Windows-LanguageFeatures*.cab)|(\Microsoft-Windows-Client*.esd)|(\Microsoft-Windows-Client*.cab)") {
            Write-Host "But! The files in the current directory match what we are after so no need for downloading anything!" -ForegroundColor Green
            $Install = $True 
        }
        elseif($LocalRepository) {   
            if(Test-Path -Path $LocalRepositoryPath\$Os\$Build\$language -Filter "\(Microsoft-Windows-LanguageFeatures*.cab)|(\Microsoft-Windows-Client*.esd)|(\Microsoft-Windows-Client*.cab)") {
                Write-Host "But! Since you specified a local repository to download from and we can access them there, everything is good!" -ForegroundColor Green 
                Copy-Item -LiteralPath "$LocalRepositoryPath\$Os\$Build\$language\*.cab" -Destination .\ -Force -Verbose
                $Install = $True 
            }
        }
        else{
            Write-Host "And no local files was found in $path and no LocalRepository was specified" -ForegroundColor Red    
            Write-Host "Will have to abort Language CAB Install and retry on next attempt" -ForegroundColor Red
            $Install = $null
            Exit 2
        }
    }
    if ($Install) {
        if(-Not $LocalRepository) {
            try{
                if(Test-Path -Path $path -Filter "\Microsoft-Windows-Client-LanguagePack-Package*.cab") { 
                }
                elseif(!(Test-Path -Path $path -Filter "\Microsoft-Windows-Client-LanguagePack-Package*.cab") -and (Test-Path -Path $path -Filter "\Microsoft-Windows-Client-LanguagePack-Package*.esd")) {
                    Invoke-WebRequest -UseBasicParsing -Uri 'https://github.com/abbodi1406/WHD/raw/master/scripts/ESD2CAB-CAB2ESD-2.zip' -Headers $Headers -OutFile "$path\ESD2CAB.zip" -ErrorAction SilentlyContinue
                    Start-Sleep 1
                    Expand-Archive -Path "$path\ESD2CAB.zip" -DestinationPath "$path\" -Force -ErrorAction Stop
                    Start-Sleep 1
                    $file = Get-Content -Path ".\esd2cab_CLI.cmd"
                    $file = $file | Where-Object { $_ -notmatch "echo Press any key to exit\.\.\." } | Where-Object { $_ -notmatch "pause >nul" } #Removes the need to interact with the ESD to CAB conversion
                    Set-Content -Path ".\esd2cab_CLI.cmd" -Value $file
                    Start-Sleep 1
                    .\esd2cab_CLI.cmd
                }
                else {
                    Write-Host "Should be .cab files in this current directory.." -ForegroundColor Red
                }
            }   
            catch {
                $_.Exception.Message    
            }
        }
        Remove-PSDrive -Name HKCR -ErrorAction SilentlyContinue
        $command = @(
            "dism /online /add-package /packagepath:$path\Microsoft-Windows-Client-LanguagePack-Package_$Language-$arch-$Language.cab /norestart /LogPath:$path\$Language-CAB.log /LogLevel:3",
            "dism /online /add-package /packagepath:$path\Microsoft-Windows-LanguageFeatures-Basic-$Language-Package-$arch.cab /norestart /LogPath:$path\$Language-CAB.log /LogLevel:3",
            "dism /online /add-package /packagepath:$path\Microsoft-Windows-LanguageFeatures-Handwriting-$Language-Package-$arch.cab /norestart /LogPath:$path\$Language-CAB.log /LogLevel:3",
            "dism /online /add-package /packagepath:$path\Microsoft-Windows-LanguageFeatures-OCR-$Language-Package-$arch.cab /norestart /LogPath:$path\$Language-CAB.log /LogLevel:3",
            "dism /online /add-package /packagepath:$path\Microsoft-Windows-LanguageFeatures-TextToSpeech-$Language-Package-$arch.cab /norestart /LogPath:$path\$Language-CAB.log /LogLevel:3"
        )
        if($Language -eq "ja-jp" -or $Language -eq "en-us" -or $Language -eq "en-uk") {
            $command += "dism /online /add-package /packagepath:$path\Microsoft-Windows-LanguageFeatures-Speech-$Language-Package-$arch.cab /norestart /LogPath:$path\$Language-CAB.log /LogLevel:3"
        }
        Get-Job | Remove-Job -Force -Confirm:$false
        Remove-item "$path\ErrorObject.log" -Force -Recurse -Confirm:$false -ErrorAction SilentlyContinue 
        Remove-item "$path\$Language-CAB.log" -Force -Recurse -Confirm:$false -ErrorAction SilentlyContinue
        $elapsedTime = Measure-Command {
            $jobList = @()
            for ($i = 0; $i -lt ($command.Length); $i++) {
                $JobName = switch ($i) {
                    0 { "($language)-Client-LanguagePack" }
                    1 { "LanguageFeatures-Basic" }
                    2 { "LanguageFeatures-Handwriting" }
                    3 { "LanguageFeatures-OCR" }
                    4 { "LanguageFeatures-TextToSpeech" }
                    5 { "LanguageFeatures-Speech" }
                }
                $job = Start-Job -Name $jobName -ScriptBlock { 
                    param($command,$JobName,$Path)
                        try {
                            $logData = @{
                                StartTimestamp = Get-Date
                                Command = $Command
                                EndTimestamp = ""
                                ElapsedTime = ""
                                InstallStatus = ""
                            }
                            $DISM = & cmd /c "$command" 
                            $logData.EndTimestamp = Get-Date
                            $logData.ElapsedTime = [datetime]::ParseExact($logData.EndTimestamp.ToString("yyyy-MM-dd hh:mm:ss.ffff"), "yyyy-MM-dd hh:mm:ss.ffff", $null) - [datetime]::ParseExact($logData.StartTimestamp.ToString("yyyy-MM-dd hh:mm:ss.ffff"), "yyyy-MM-dd hh:mm:ss.ffff", $null)
                            $logData.StartTimestamp = $logData.StartTimestamp.ToString("yyyy-MM-dd hh:mm:ss.ffff", [System.Globalization.CultureInfo]::InvariantCulture)
                            $logData.EndTimestamp = $logData.EndTimestamp.ToString("yyyy-MM-dd hh:mm:ss.ffff", [System.Globalization.CultureInfo]::InvariantCulture)
                        } 
                        catch {
                            $_ | Select-Object * | Out-File "$path\ErrorObject.log" -Append -Force
                            $logData.InstallStatus = "Error.."
                        }
                        $logData.InstallStatus = "OK"
                        Return $logData
                } -ArgumentList $command[$i].ToString(), $JobName,$path
                $jobList += $job
            }
            $timeout = [DateTime]::Now.AddMinutes(45)
            while ($jobList) {
                if ([DateTime]::Now -gt $timeout) {
                    Write-Error "The job has exceeded the 45 minutes timeout limit."
                    break
                }
                foreach ($job in $jobList) {
                    if ($job.State -eq "Completed") {
                        # Get the job output
                        $output = Receive-Job $job | Out-String -Stream
                        Write-Output "Job $($job.Name) output:"
                        $output | ForEach-Object {
                            if ($_ -match '^(\S+)\s+(\S.*)$') {
                                Write-Host $Matches[1] -ForegroundColor Green -NoNewline
                                Write-Host ' ' $Matches[2]
                            }    
                            else {
                                Write-Host $_
                            }
                        } 
                        $jobList = $jobList | Where-Object { $_.InstanceId -ne $job.InstanceId }
                        $job.Dispose()
                    }
                }
                Start-Sleep -Milliseconds 100
            }
        }
        if ($elapsedTime.Minutes -ge 45) {
            Write-Error "Will have to abort since Install CAB job never finished, will try again.."
            Exit 3
        }
        else {
            if ($elapsedTime.Minutes -le 9) {
                Write-Host "Elapsed total time for complete language ($Language) CAB installation: 0$($elapsedTime.Hours):0$($elapsedTime.Minutes):$($elapsedTime.Seconds).$($elapsedTime.Milliseconds)" -ForegroundColor Green
            }
            else {
                Write-Host "Elapsed total time for complete language ($Language) CAB installation: 0$($elapsedTime.Hours):$($elapsedTime.Minutes):$($elapsedTime.Seconds).$($elapsedTime.Milliseconds)" -ForegroundColor Green
            }
            if(Get-Content -Path "$path\ErrorObject.log" -ErrorAction SilentlyContinue) {
                Write-Warning "The Install CAB jobs finished in time but left errors.."
                Write-Warning "Printing first 50 rows here:"
                Get-Content -Path "$path\ErrorObject.log" -TotalCount 50 | Out-Host
            }
            else{
                Write-Host "Looks like Install CAB files worked! Good job!" -ForegroundColor Green
                Update-ExitCode -Path $progressFile -Part "Install-LanguageCabs" -ExitCode "Job says OK!"
            }
        }
        New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT -erroraction silentlycontinue | Out-Null
        New-item 'HKCR:\ToastReboot' -force -ErrorAction SilentlyContinue | Out-Null
        set-itemproperty 'HKCR:\ToastReboot' -name '(DEFAULT)' -value 'url:ToastReboot' -force -ErrorAction SilentlyContinue | Out-Null
        set-itemproperty 'HKCR:\ToastReboot' -name 'URL Protocol' -value '' -force -ErrorAction SilentlyContinue | Out-Null
        new-itemproperty -path 'HKCR:\ToastReboot' -propertytype dword -name 'EditFlags' -value 2162688 -ErrorAction SilentlyContinue | Out-Null
        New-item 'HKCR:\ToastReboot\Shell\Open\command' -force -ErrorAction SilentlyContinue | Out-Null
        set-itemproperty 'HKCR:\ToastReboot\Shell\Open\command' -name '(DEFAULT)' -value 'C:\Windows\System32\shutdown.exe -r -t 00' -force -ErrorAction SilentlyContinue #Pressing restart now on the toast will do just that :)
        if (-not (Get-Command "Invoke-AsCurrentUser_WithArgs" -ErrorAction SilentlyContinue)) {
            $url = "https://raw.githubusercontent.com/ztrhgf/RunAsUser/master/Public/Invoke-AsCurrentUser.ps1"
            $localFile = "$env:Temp\Invoke-AsCurrentUser_WithArgs.ps1"
            $status = Invoke-WebRequest $url -PassThru -OutFile $localFile
            if ($status.StatusCode -eq "200" -or ($status.StatusDescription -eq "OK") -or (Test-Path "$env:Temp\Invoke-AsCurrentUser_WithArgs.ps1")) {
                (Get-Content $localFile -Raw) -replace "Invoke-AsCurrentUser", "Invoke-AsCurrentUser_WithArgs" | Set-Content $localFile
                $newFunc = Get-Content $localFile -Raw
                Invoke-Command -ScriptBlock ([Scriptblock]::Create($newFunc))
                Invoke-Expression $newFunc -Verbose
            }
        }
        [hashtable]$Argument = @{
            Os = $Os
            ToastImage = $ToastImage
        }
        Invoke-AsCurrentUser_WithArgs -UseWindowsPowerShell -Argument $argument -ScriptBlock {
            Param ([string]$Os,[string]$ToastImage)
            Import-Module -Name BurntToast -ErrorAction SilentlyContinue -Force -Verbose
            $burn = Get-Command "Submit-BTNotification" -ErrorAction SilentlyContinue
            if (!($burn)) {
                Import-Module $((Get-ChildItem -Path "C:\WINDOWS\system32\config\systemprofile\Documents\PowerShell\Modules\BurntToast\0.*.5\BurntToast.psd1").FullName) -Force # SYSTEM user has installed the module here.
            }
            Remove-BTNotification -UniqueIdentifier "LXP" -Confirm:$false -ErrorAction SilentlyContinue
            Remove-BTNotification -Group "LXP" -ErrorAction SilentlyContinue
            Remove-BTNotification -UniqueIdentifier "LXP" -ErrorAction SilentlyContinue
            $heroimage = New-BTImage -Source $ToastImage -HeroImage
            $Text1 = New-BTText -Content "Good news! Windows $Os language installation has finished in the backgroud, a restart is needed."
            $Button = New-BTButton -Content "Restart Later" -snooze -id "SnoozeTime"
            $Button2 = New-BTButton -Content "Restart Now" -Arguments "ToastReboot:" -ActivationType Protocol
            $audio = New-BTAudio -Silent
            $action = New-BTAction -Buttons $Button, $Button2
            $Binding = New-BTBinding -Children $text1 -HeroImage $heroimage
            $Visual = New-BTVisual -BindingGeneric $Binding
            $Content = New-BTContent -Visual $Visual -Actions $action -Audio $audio -Duration Long
            Submit-BTNotification -Content $Content -UniqueIdentifier "LXP"
        }  
    }
    else {
        try{
            if(Get-ChildItem -Path .\ -Filter "*.cab") {
                Invoke-WebRequest -UseBasicParsing -Uri 'https://github.com/abbodi1406/WHD/raw/master/scripts/ESD2CAB-CAB2ESD-2.zip' -OutFile .\ESD2CAB.zip
                Start-Sleep 1
                Expand-Archive -Path .\ESD2CAB.zip -DestinationPath .\ -Force -ErrorAction Stop
                Start-Sleep 1
                $file = Get-Content -Path ".\esd2cab_CLI.cmd"
                $file = $file | Where-Object { $_ -notmatch "echo Press any key to exit\.\.\." } | Where-Object { $_ -notmatch "pause >nul" } #Removes the need to interact with the ESD to CAB conversion
                Set-Content -Path ".\esd2cab_CLI.cmd" -Value $file
                Start-Sleep 1
                Write-Host "Running: .\esd2cab_CLI.cmd" -ForegroundColor Green
                .\esd2cab_CLI.cmd
            }
            else {
                Write-Host "Should be .cab files in this current directory but none was found, its a mystery!" -ForegroundColor Red
            }
        }
        catch {
            $_.Exception.Message
        }
    }
    Stop-Transcript -ErrorAction SilentlyContinue 
}
 
Last edited:
Sounds like you've invested a lot of time working on your deployment environment. Most of our NTLite users are installing a few home PC's, but I agree that local file caching is a huge performance win.

Thumbs up on the toast notification! I used to work with the MSN Messenger team, which introduced toasts on Windows.
 
thanx man, and yeeha I've been deep in automation for a few years now and love anything you can simplify for our end user :) It's ironic because i have zero things automated for my home environment. But for our servicedesk i have a script that asks for one input; language on the pc. And then language is set as above but also automatic Intune and hybrid join with autopilot and all that jazz :) But in the end it's all about freeing up time for myself, since no one knows what i do at IT i see a future where i can automate basically everything and then not have to do anything except what choose :)
yeah, cheers for the toast, was something i thought about a while back, and users really love it. Damn it's pretty cool that you were part of that initially. MSN messenger was really the Facebook messenger of the day haha. Oh, and feel free to steal anything you like for your application, am just happy to contribute even though this might not be the best forum for enterprise automation :O)
 
Hi!
EDIT4: The full working solution is now at: https://github.com/Harze2k/PowerShell/blob/main/Intune/Install-LanguageCabs
Got limited here with the size of the code haha :) Also bonus, the script is actually working, running parallel jobs to finish as quick as possible. \o/
Watch out for when uudump change their site though, might mess things up though..
Hi how to run this script ? i downloaded from github but it exit with errors
+ if ((Update-ExitCode -Path $progressFile -Part "Install-LanguageCabs" ...
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Update-ExitCode:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException


TaskPath TaskName State
-------- -------- -----
\ asSystem_InstallOffice_FixPins... Ready
\ asSystem_InstallOffice_FixPins... Ready
\ asSystem_InstallOffice_FixPins... Ready
 
Harze2k's calling a PS function (Update-ExitCode), which he didn't include in his GitHub sources.

FYI, his script is designed for InTune deployment environments and not for home use.
Just run my original script as provided.
 
Hi how to run this script ? i downloaded from github but it exit with errors
+ if ((Update-ExitCode -Path $progressFile -Part "Install-LanguageCabs" ...
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Update-ExitCode:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException


TaskPath TaskName State
-------- -------- -----
\ asSystem_InstallOffice_FixPins... Ready
\ asSystem_InstallOffice_FixPins... Ready
\ asSystem_InstallOffice_FixPins... Ready
Yes as Garlin said basically its for more of a enterprise deployment with more functions that are chained together. So if that's the case just use his tool :) But since you tested the code for update exit code is just a quick little function to write in a xml file like this:

Code:
function Update-ExitCode {
    [CmdletBinding()]
    param ([Parameter(Mandatory=$true, Position=0)]
        [string]$Path,
        [Parameter(Mandatory=$true)]
        [string]$Part,
        [Parameter(Mandatory=$false)]
        [string]$ExitCode,
        [Parameter(Mandatory=$false)]
        [switch]$ReturnOnly)
    try {
        # Read the contents of the JSON file
        $json = Get-Content -Path $Path -Raw | ConvertFrom-Json
    }
    catch {
        Write-Warning "Error reading JSON file: $_"
        return
    }
    # Find the item with the matching Part value
    $item = $json.Progress | Where-Object { $_.Part -eq $Part }
    if (!$item) {
        Write-Warning "Part '$Part' not found in JSON file"
        return
    }
    # If the ReturnOnly switch is specified, output the ExitCode value and return
    if ($ReturnOnly) {
        Write-Output $item.ExitCode
        return
    }
    # Update the ExitCode value if a new value is provided
    if ($ExitCode) {
        $item.ExitCode = $ExitCode
    }
    Write-Output "Part: $($item.Part) ExitCode: $($item.ExitCode)"
    try {
        # Write the updated JSON back to the file
        $json | ConvertTo-Json -Depth 100 | Set-Content $Path
    }
    catch {
        Write-Warning "Error writing JSON file: $_"
    }
}

And then the way i created this xml file in the first place was super basic with another function:

Code:
Function Set-CheckProgressJSON {
    param([string]$ProgressFile)
@"
{
    "Progress": [
    {
        "Part": "SendFirstLogs",
        "ExitCode": ""
    },
    {
        "Part": "InstallOffice",
        "ExitCode": ""
    },
    {
        "Part": "PinIcons",
        "ExitCode": ""
    },
    {
        "Part": "Install-LanguageCabs",
        "ExitCode": ""
    },
    {
        "Part": "SendLastLogs",
        "ExitCode": ""
    }
    ]
}
"@ | Out-File -FilePath $progressFile -Force
}
But none of this is needed for home use, i wouldn't even bother this for my own pc at home :D But if you do you need to edit the functions so they suit your specific environment. I doubt you need check for if the automatic psadt install of Office is done etc :)
 
Back
Top