Tried and seems to be working, thank you Also prefer 21 version, don't need to store in the cloud or anything like that, nor use any email. But need to use some excel functions only available in 365. Couple of questions, what's the purpose of the "enable visual ui with lstc logo" in officertool? And regarding "disable acquisition and telemetry", i understand it always keep it off, no matter how many times i run it, right? Or it enable/disable it everytime?
I do some testing, if any differences in speed I can say that Invoke-CimMethod is less code to write than gwmi Invoke-CimMethod Code: if ($Args[0] -eq '/InstallProductKey') { $KEY = $Args[1] $ErrorActionPreference = "Stop" gwmi try { Invoke-CimMethod -MethodName InstallProductKey -Query "select * from SoftwareLicensingService" -Arguments @{ProductKey=$KEY} return "Error:0" } catch { # return wmi last error, in hex format $HResult = ‘{0:x}’ -f @($_.Exception).HResult return "Error:$($HResult)" } } Code: if ($Args[0] -eq '/InstallProductKey') { $KEY = $Args[1] $ErrorActionPreference = "Stop" $LicensingService = gwmi -ClassName SoftwareLicensingService -ErrorAction SilentlyContinue if (-not $LicensingService) { return "Error:CLASS_NOT_FOUND" } try { $LicensingService.InstallProductKey($KEY) return "Error:0" } catch { # return wmi last error, in hex format $HResult = ‘{0:x}’ -f @($_.Exception).HResult return "Error:$($HResult)" } } the same thing in License install how much code is needed here?! Code: if ($Args[0] -eq '/InstallLicense') { $LicenseFile = $Args[1] $ErrorActionPreference = "Stop" if([System.IO.File]::Exists($LicenseFile)-ne $true) { return "Error:FILE_NOT_FOUND" } $LicensingService = gwmi -ClassName SoftwareLicensingService -ErrorAction SilentlyContinue if (-not $LicensingService) { return "Error:CLASS_NOT_FOUND" } try { $LicensingService.InstallLicense( [System.IO.File]::ReadAllText( $LicenseFile )) return "Error:0" } catch { # return wmi last error, in hex format $HResult = ‘{0:x}’ -f @($_.Exception).HResult return "Error:$($HResult)" } } and with the second method Code: if ($Args[0] -eq '/InstallLicense') { $LicenseFile = $Args[1] $ErrorActionPreference = "Stop" if([System.IO.File]::Exists($LicenseFile)-ne $true) { return "Error:FILE_NOT_FOUND" } try { Invoke-CimMethod -MethodName InstallLicense -Query "select * from SoftwareLicensingService" -Arguments @{License="$([System.IO.File]::ReadAllText($LicenseFile))"} return "Error:0" } catch { # return wmi last error, in hex format $HResult = ‘{0:x}’ -f @($_.Exception).HResult return "Error:$($HResult)" } }
after little testing manage to remove and short lot of code the bare minimum code for WMI operation I hope it will improve the speed too. Code: the shortest code in PS to activate a product iwmi -Path "$($CLASS).ID='$($ID)'" -Name Activate the shortest code in PS to install a license gwmi -Class SoftwareLicensingService | iwmi -Name InstallLicense -Args @([System.IO.File]::ReadAllText($LicenseFile)) the shortest code in PS to install/uninstall a product key gwmi -Class SoftwareLicensingService | iwmi -Name InstallProductKey -Args $KEY icim -MethodName UninstallProductKey -Query "select * from $($CLASS) where ($($FILTER))" Full Code Code: if ($Args[0] -eq '/QUERY_BASIC') { $class = $Args[2]; $value = @($Args[1]).Replace(' ','') $wmi_Object = gwmi -Query "select $($value) from $($class)" -ErrorAction SilentlyContinue if (-not $wmi_Object) { return "Error:WMI_SEARCH_FAILURE" } foreach ($item in $wmi_Object) { $line = ''; $value.Split(",")|%{$line += ",$($item.GetPropertyValue("$_"))"} Write-Host $line } return } if ($Args[0] -eq '/QUERY_ADVENCED') { $class = $Args[2]; $filter = $Args[3]; $value = @($Args[1]).Replace(' ','') $wmi_Object = gwmi -Query "select $($value) from $($class) where ($($filter))" -ErrorAction SilentlyContinue if (-not $wmi_Object) { return "Error:WMI_SEARCH_FAILURE" } foreach ($item in $wmi_Object) { $line = ''; $value.Split(",")|%{$line += ",$($item.GetPropertyValue("$_"))"} Write-Host $line } return } if ($Args[0] -eq '/ACTIVATE') { $CLASS = $Args[1] $ID = $Args[2] $ErrorActionPreference = "Stop" try { iwmi -Path "$($CLASS).ID='$($ID)'" -Name Activate return "Error:0" } catch { # return wmi last error, in hex format $HResult = ‘{0:x}’ -f @($_.Exception).HResult return "Error:$($HResult)" } } if ($Args[0] -eq '/UninstallProductKey') { $CLASS = $Args[1] $FILTER = $Args[2] try { icim -MethodName UninstallProductKey -Query "select * from $($CLASS) where ($($FILTER))" return "Error:0" } catch { # return wmi last error, in hex format $HResult = ‘{0:x}’ -f @($_.Exception).HResult return "Error:$($HResult)" } } if ($Args[0] -eq '/InstallProductKey') { $KEY = $Args[1] $ErrorActionPreference = "Stop" try { gwmi -Class SoftwareLicensingService | iwmi -Name InstallProductKey -Args $KEY return "Error:0" } catch { # return wmi last error, in hex format $HResult = ‘{0:x}’ -f @($_.Exception).HResult return "Error:$($HResult)" } } if ($Args[0] -eq '/InstallLicense') { $LicenseFile = $Args[1] $ErrorActionPreference = "Stop" if([System.IO.File]::Exists($LicenseFile)-ne $true) { return "Error:FILE_NOT_FOUND" } try { gwmi -Class SoftwareLicensingService | iwmi -Name InstallLicense -Args @([System.IO.File]::ReadAllText($LicenseFile)) return "Error:0" } catch { # return wmi last error, in hex format $HResult = ‘{0:x}’ -f @($_.Exception).HResult return "Error:$($HResult)" } } return $null
so I sit in this thing today. and managed to make it even more compact about `Activate` I think I can't make it - more compact than it is now it good for the experience with PS WMI Code: iwmi -Path "$($CLASS).ID='$($ID)'" -Name Activate gcim $CLASS -filter "ID='$($ID)'" | icim -Name Activate gwmi SoftwareLicensingService | % {$_.InstallProductKey($KEY)} gwmi -Class SoftwareLicensingService | iwmi -Name InstallProductKey -Args $KEY gwmi SoftwareLicensingService | % {$_.InstallLicense(@([System.IO.File]::ReadAllText($LicenseFile)))} gwmi -Class SoftwareLicensingService | iwmi -Name InstallLicense -Args @([System.IO.File]::ReadAllText($LicenseFile)) That's what I got so far ... after a lot of trial and error with icim\gcim & gwmi\iwmi Code: Using Filter\Path iwmi -Path "$($CLASS).ID='$($ID)'" -Name Activate gcim $CLASS -filter "ID='$($ID)'" | icim -Name Activate Using Query icim -Name Activate -Query "select * from $($CLASS) where (ID='$($ID)')" gwmi -Query "select * from $($CLASS) where ID='$($ID)'" | % {$_.Activate()} ....... After .. after ... Using [wmi] tag I was able to make it Even more compact For static class it's the best solution
Something that builds as an Idea... will get the office licenses, clean all licenses, and re-added them again. Output. here. Code: ### Found license: VisioPro2024PreviewVL_KMS_Client_AE ### Found license: ProjectPro2024PreviewVL_KMS_Client_AE ### Found license: ProPlus2024PreviewVL_KMS_Client_AE Un-install license: 0990975c-d5c4-eb88-bc84-0ba4fc7ff1b9 Un-install license: 0b7faf31-c4a8-a8ae-a034-a266db487f08 Un-install license: 1d435f47-bea8-5891-7674-dd1d3e03c490 Un-install license: 215ad112-94d6-9157-11a2-d25123930edb Un-install license: 4bada8e2-5ec8-a135-449d-2849b6c8d5eb Un-install license: 73e79f34-ec45-ecb3-7d11-eb6723c9f5d6 Un-install license: 7aa92662-74e0-1bab-eaed-0e3e6b9f0ae9 Un-install license: bcc975a5-233d-f352-c92a-d501fef591fc Un-install license: bf838077-8faa-ef02-c3bf-998827d894ae Un-install license: fda4f580-bbce-b75d-85ef-75daa9fc8507 Un-install license: fdf82507-1037-cb40-219b-fe56da5e5598 Re-Install License: pkeyconfig-office.xrm-ms Re-Install License: pkeyconfig-office-client15.xrm-ms Re-Install License: client-issuance-root.xrm-ms Re-Install License: client-issuance-stil.xrm-ms Re-Install License: client-issuance-ul.xrm-ms Re-Install License: client-issuance-ul-oob.xrm-ms Re-Install License: client-issuance-root-bridge-test.xrm-ms Re-Install License: client-issuance-bridge-office.xrm-ms Re-Install License: VisioPro2024PreviewVL_KMS_Client_AE.xrm-ms Re-Install License: ProjectPro2024PreviewVL_KMS_Client_AE-ul-oob.xrm-ms Re-Install License: ProPlus2024PreviewVL_KMS_Client_AE-ul-oob.xrm-ms v2.0 Code: cls Write-Host $InstallPath = $null $LicenseList = $null $ServiceClass = gwmi SoftwareLicensingService $InstallPath_X64 = Get-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun" -Name "InstallPath" -ea 0 $InstallPath_X86 = Get-ItemProperty -path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\ClickToRun" -Name "InstallPath" -ea 0 if ($InstallPath_X64 -and (Test-path $InstallPath_X64.InstallPath)) { $InstallPath = $InstallPath_X64.InstallPath } if ($InstallPath_X86 -and (Test-path $InstallPath_X86.InstallPath)) { $InstallPath = $InstallPath_X86.InstallPath } if (-not $InstallPath) { return } # Get licenses $LicenseWMI = (GWMI SoftwareLicensingProduct -ErrorAction SilentlyContinue)|? ApplicationId -EQ '0ff1ce15-a989-479d-af46-f275c6370663'| ? LicenseIsAddon -EQ $false if (-not $LicenseWMI) { return } $LicenseList = $LicenseWMI.Name.Substring(19).Replace(' edition',' ') $Client_List = "pkeyconfig-office.xrm-ms,pkeyconfig-office-client15.xrm-ms,client-issuance-root.xrm-ms,client-issuance-stil.xrm-ms,client-issuance-ul.xrm-ms,client-issuance-ul-oob.xrm-ms,client-issuance-root-bridge-test.xrm-ms,client-issuance-bridge-office.xrm-ms" $LicenseList | % { "### Found license: $($_)" } Write-Host # Clean licenses try { $compilerParameters = New-Object -TypeName CodeDom.Compiler.CompilerParameters $compilerParameters.CompilerOptions = '/unsafe' Add-Type -CompilerParameters $compilerParameters @" using System; using System.Runtime.InteropServices; public class API { unsafe delegate uint SLOpenDelegate(void** phSLC); unsafe delegate uint SLGetSLIDListDelegate(void* hSLC, int eQueryIdType, Guid* pQueryId, int eReturnIdType, uint* pnReturnIds, Guid** ppReturnIds); unsafe delegate uint SLUninstallLicenseDelegate(void* hSLC, Guid* pLicenseFileId); [DllImport("kernel32.dll")] static extern IntPtr LoadLibrary(string path); [DllImport("kernel32.dll")] static extern IntPtr GetProcAddress(IntPtr hModule, string procName); public static void CleanLicenses() { UninstallLicenses("sppc"); string ospp = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\OfficeSoftwareProtectionPlatform", "Path", null); if (ospp != null) { Console.WriteLine("Found Office Software Protection installed, cleaning"); UninstallLicenses(ospp + "osppc.dll"); } } public static void UninstallLicenses(string dllPath) { IntPtr sppc = LoadLibrary(dllPath); SLOpenDelegate open = (SLOpenDelegate)Marshal.GetDelegateForFunctionPointer(GetProcAddress(sppc, "SLOpen"), typeof(SLOpenDelegate)); SLGetSLIDListDelegate getSLIDList = (SLGetSLIDListDelegate)Marshal.GetDelegateForFunctionPointer(GetProcAddress(sppc, "SLGetSLIDList"), typeof(SLGetSLIDListDelegate)); SLUninstallLicenseDelegate uninstallLicense = (SLUninstallLicenseDelegate)Marshal.GetDelegateForFunctionPointer(GetProcAddress(sppc, "SLUninstallLicense"), typeof(SLUninstallLicenseDelegate)); unsafe { void* phSLC; open(&phSLC); uint pnReturnIds; Guid* ppReturnIds; Guid officeGuid = new Guid("0ff1ce15-a989-479d-af46-f275c6370663"); if (getSLIDList(phSLC, 0, &officeGuid, 6, &pnReturnIds, &ppReturnIds) != 0) { return; } for (int i = 0; i < pnReturnIds; i++) { Console.WriteLine("Un-install license: " + ppReturnIds[i]); uninstallLicense(phSLC, &ppReturnIds[i]); } } } } "@ } catch { return } [API]::CleanLicenses() # Restore licenses Write-Host $Client_List.Split(",") |% { $LicenseFile = Join-Path $InstallPath "root\Licenses16\$($_)" if (Test-Path $LicenseFile) { "Re-Install License: $($_)" $ServiceClass.InstallLicense(@([IO.File]::ReadAllText($LicenseFile))) | Out-Null }} $LicenseList |% { $LicenseName = "$($_)".Replace(" ","") $LicenseFile = Join-Path $InstallPath "root\Licenses16\$($LicenseName)" "Re-Install License: $($LicenseName)$($patteren).xrm-ms" foreach ($patteren in "-ppd,-ul,-ul-oob".Split(',')) { if (Test-Path "$($LicenseFile)$($patteren).xrm-ms") { $ServiceClass.InstallLicense(@([IO.File]::ReadAllText("$($LicenseFile)$($patteren).xrm-ms"))) | Out-Null }} } return
Forget to add a replacement alternative to '/rilc' & '/ato' so build a new PS code for that, using the original one from SLMGR.vbs and in insider build, convert will use PS code instead vbs Code: # Private Sub ReinstallLicenses() # strOemFolder = shell.ExpandEnvironmentStrings("%SystemRoot%") & "\system32\oem" # strSppTokensFolder = shell.ExpandEnvironmentStrings("%SystemRoot%") & "\system32\spp\tokens" # Set folder = fso.GetFolder(strSppTokensFolder) # For Each subFolder in folder.SubFolders # InstallLicenseFiles subFolder, fso # Next # If (fso.FolderExists(strOemFolder)) Then # InstallLicenseFiles strOemFolder, fso # End If # End Sub to this Code: $LicensingService = GWMI SoftwareLicensingService -ErrorAction Stop if (-not $LicensingService) { return } $OEM = Join-Path $ENV:SystemRoot "system32\oem" $tokens = Join-Path $ENV:SystemRoot "system32\spp\tokens" if (Test-Path $tokens) { dir $tokens -Filter *.xrm-ms -Recurse -Name | % { $LicenseFile = Join-Path $tokens $_ if (Test-Path $LicenseFile) { $LicensingService.InstallLicense([IO.FILE]::ReadAllText($LicenseFile)) }}} if (Test-Path $OEM) { dir $OEM -Filter *.xrm-ms -Recurse -Name | % { $LicenseFile = Join-Path $tokens $_ if (Test-Path $LicenseFile) { $LicensingService.InstallLicense([IO.FILE]::ReadAllText($LicenseFile)) }}} and also Code: #objProduct.Activate() #objService.RefreshLicenseStatus() #objProduct.refresh_ to this Code: $LicensingService = GWMI SoftwareLicensingService -ErrorAction Stop $LicensingProduct = gwmi -Query "select * from SoftwareLicensingProduct where (ApplicationId='55c92734-d682-4d71-983e-d6ec3f16059f' and PartialProductKey is not null)" -ErrorAction Stop if (-not $LicensingProduct) { return } if (-not $LicensingService) { return } $LicensingProduct.Activate() $LicensingService.RefreshLicenseStatus() $LicensingProduct.refresh_
Is there a difference between installing Microsoft 365 Home Premium and convert and activate it to get Microsoft Office Mondo 2016 and install Microsoft Office Mondo 2016 right away? Also, is Microsoft 365 Home Premium actually called Microsoft 365 Family?
Each License equ different features I would say, if you want to enjoy 365 Use sub discription account
Mondo license and 365 license are different products With different features If you prefer using 365 ... You can consider buy a sub description But if not, it will convert to mondo license