Skip to content

Instantly share code, notes, and snippets.

@nicolonsky
Last active January 30, 2024 12:39
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nicolonsky/b04dd77129577f782178c0c049344101 to your computer and use it in GitHub Desktop.
Save nicolonsky/b04dd77129577f782178c0c049344101 to your computer and use it in GitHub Desktop.
Intune / Configuration Manager Proactive Remediation to trigger Office Click to Run Updater (intended to run for the logged on user to show built-in update pop-up)
# See Microsoft 365 Apps Version history https://learn.microsoft.com/en-us/officeupdates/update-history-microsoft365-apps-by-date#version-history
$targetVersions = @{
'CurrentChannel' = [System.Version]::Parse('16.0.16130.20306')
'MonthlyEnterpriseChannel1' = [System.Version]::Parse('16.0.16026.20238')
'MonthlyEnterpriseChannel2' = [System.Version]::Parse('16.0.15928.20298')
'Semi-AnnualEnterpriseChannel(Preview)' = [System.Version]::Parse('16.0.16130.20306')
'Semi-AnnualEnterpriseChannel1' = [System.Version]::Parse('16.0.15601.20578')
'Semi-AnnualEnterpriseChannel2' = [System.Version]::Parse('16.0.14931.20944')
'CurrentChannel(Preview)' = [System.Version]::Parse('16.0.16227.20094')
}
$configuration = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration"
$displayVersion = $null
if ( [System.Version]::TryParse($configuration.VersionToReport, $([ref]$displayVersion))) {
Write-Output ("Discovered VersionToReport {0}" -f $displayVersion.ToString())
$targetVersion = $targetVersions.Values | Where-Object { $_.Build -eq $displayVersion.Build } | Select-Object -Unique -First 1
Write-Output ("Mapped minimum target version to {0}" -f $targetVersion.ToString())
if ($null -eq $targetVersion -or $displayVersion -lt $targetVersion) {
Write-Output ("Current Office365 Version {0} is lower than specified target version {1}" -f $displayVersion.ToString(), $targetVersion.ToString())
Write-Output "Triggering remediation..."
Exit 1
} else {
Write-Output ("Current Office365 Version {0} matches specified target version {1}" -f $displayVersion.ToString(), $targetVersion.ToString())
Exit 0
}
} else {
throw "Unable to parse VersionToReport for Office"
}
$processArgs = @{
'FilePath' = "$env:ProgramFiles\Common Files\microsoft shared\ClickToRun\OfficeC2RClient.exe"
'ArgumentList' = "/update user"
'Wait' = $true
}
if (-not (Test-Path $processArgs['FilePath'])) { throw "OfficeC2RClient.exe not found!" }
Start-Process @processArgs
@droushd
Copy link

droushd commented Mar 16, 2023

see line 25 in Detect -- i think you meant TargetVersion
Write-Output ("Mapped minimum target version to {0}" -f $targetVersion.ToString())

@Tuttu
Copy link

Tuttu commented Mar 17, 2023

Get-ItemProperty : Impossible de lier l'argument au paramètre « Path », car il a la valeur Null. Au caractère C:\Windows\IMECache\HealthScripts\4531a757-b7ad-41e6-b60f-b0f07818eeac_1\detect.ps1:16 : 43 + $versionRegistry = Get-ItemProperty -Path $path -Name "DisplayVersion ... + ~~~~~ + CategoryInfo : InvalidData : (:) [Get-ItemProperty], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetItemProp ertyCommand Unable to parse displayVersion for Office Au caractère C:\Windows\IMECache\HealthScripts\4531a757-b7ad-41e6-b60f-b0f07818eeac_1\detect.ps1:36 : 5 + throw "Unable to parse displayVersion for Office" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OperationStopped: (Unable to parse...sion for Office:String) [], RuntimeException + FullyQualifiedErrorId : Unable to parse displayVersion for Office
Getting this error when using a Proactive Remediation though it worked well when started manually. It says that the Path ($path) is null.
The PR is set to execute as the logged in user.

@duffman0
Copy link

Set "Run script in 64-bit PowerShell" to YES, or it will not find the correct registry key

@Tuttu
Copy link

Tuttu commented Mar 17, 2023

Set "Run script in 64-bit PowerShell" to YES, or it will not find the correct registry key

Oh! I feel so dumb. Didn't though about this. Thanks a lot. :)

@duffman0
Copy link

Set "Run script in 64-bit PowerShell" to YES, or it will not find the correct registry key

Oh! I feel so dumb. Didn't though about this. Thanks a lot. :)

That's OK, I had the same problem yesterday and took me 30 mins to realise :)

@pandrews1976
Copy link

@nicolonsky have a scenario that is resulting in some errors in the script. We have some clients that were not updating so their VersionToReport is much lower that what is listed above. For example we have a device on CurrentChannel but the build is 15831. When the detection script runs the $targetVersion returns a null value and then the Write-Output fails because you are trying to call a null-valued expression.

write output done. output = Discovered VersionToReport 16.0.15831.20208 , error = You cannot call a method on a null-valued expression.
At C:\WINDOWS\IMECache\HealthScripts\2a956338-8770-4e9e-9572-0e1ad1cda88e_1\detect.ps1:21 char:5
+     Write-Output ("Mapped minimum target version to {0}" -f $targetVe ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\WINDOWS\IMECache\HealthScripts\2a956338-8770-4e9e-9572-0e1ad1cda88e_1\detect.ps1:28 char:9
+         Write-Output ("Current Office365 Version {0} matches specifie ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

We tried changing line 19 from -eq to -ne which worked to ensure $targetVersion was populated. However the version selected was not for current channel but rather the Semi-Annual Channel build of 15601. So then when the evaluation on line 23 happened that DisplayVersion was actually greater than the TargetVersion and therefore the detection evaluated as False and exited the script with Exit Code 0, when it should have remediated the system.

Would it not be better for line 23 to be an evaluation of whether or not the DisplayVersion.Build is in the list of targetedVersions, if not then execute the remediation. And we don't really need line 21 and line 24 could just state the

Current Office365 Version {0} is lower than minimum target version" -f $displayVersion.ToString()

@pandrews1976
Copy link

This is how we ended up modify the script:

`# See Microsoft 365 Apps Version history https://learn.microsoft.com/en-us/officeupdates/update-history-microsoft365-apps-by-date#version-history

$targetVersions = @{
'CurrentChannel' = [System.Version]::Parse('16.0.16130.20306')
'MonthlyEnterpriseChannel1' = [System.Version]::Parse('16.0.16026.20238')
'MonthlyEnterpriseChannel2' = [System.Version]::Parse('16.0.15928.20298')
'Semi-AnnualEnterpriseChannel(Preview)' = [System.Version]::Parse('16.0.16130.20306')
'Semi-AnnualEnterpriseChannel1' = [System.Version]::Parse('16.0.15601.20578')
'Semi-AnnualEnterpriseChannel2' = [System.Version]::Parse('16.0.14931.20944')
}

$configuration = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration"
$displayVersion = $null

if ( [System.Version]::TryParse($configuration.VersionToReport, $([ref]$displayVersion))) {

Write-Output ("Discovered VersionToReport {0}" -f $displayVersion.ToString())

#$targetVersion = $targetVersions.Values | Where-Object { $_.Build -eq $displayVersion.Build } | Select-Object -Unique -First 1
#Write-Output ("Mapped minimum target version to {0}" -f $targetVersion.ToString())

if ($displayVersion -notin $targetVersions.values) {
    Write-Output ("Current Office365 Version {0} is not in list of applicable versions" -f $displayVersion.ToString())
    Write-Output "Triggering remediation..."
    Exit 1
} else {
    Write-Output ("Current Office365 Version {0} is in current version list" -f $displayVersion.ToString())
    Write-Output "No update needed"
    Exit 0
}

} else {
throw "Unable to parse VersionToReport for Office"
}`

But one issue I foresee is if the client gets updated to a newer version that what is in the targetVersions it might cause some issues. Perhaps the else statement needs to encapsulate the $targetVersion line that I commented out and then we evaluate for if Display is less than Target.

@thejoerae
Copy link

When I ran it against some machines, it came back with the "You cannot call a method on a null-valued expression" error. Noticed some people are running the Current Channel (Preview) build on their systems, so I added this line to $targetversions to fix that:

'Current Channel (Preview)' = [System.Version]::Parse('16.0.16227.20094')

And thank you for the script - this saved us a ton of headaches today

@TomislavPeharec
Copy link

Was getting the following error when I ran it as Proactive Remediation in Intune:

Get-ItemProperty : Cannot find path 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' because it does not exis t. At C:\WINDOWS\IMECache\HealthScripts\f88a1e33-yyyy-402c-yyyyy-96e37be39ff0_1\detect.ps1:13 char:18 + ... iguration = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Office\C ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (HKLM:\SOFTWARE\...n\Configuration:String) [Get-ItemProperty], ItemNotFo undException + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyCommand Unable to parse VersionToReport for Office At C:\WINDOWS\IMECache\HealthScripts\f88a1e33-yyyyy-yyyy-yyyyy-96e37be39ff0_1\detect.ps1:33 char:5 + throw "Unable to parse VersionToReport for Office" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OperationStopped: (Unable to parse...port for Office:String) [], RuntimeException + FullyQualifiedErrorId : Unable to parse VersionToReport for Office

Also can confirm that issue here was the fact that script didn't run in 64-bit Powershell.

@pandrews1976
Copy link

@TomislavPeharec have you tried to run the script manually on a machine or event browsed to HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration?

@TomislavPeharec
Copy link

@pandrews1976 Sorry, thought that my message already implied that - Yes, the Registry key is accessible when script is ran manually on the machine and I was able to get the Proactive Remediation properly working after changing to 64-bit PS in the Properties.

I just wanted to highlight the error in case someone runs into the same issue as I did.

@dungadaman
Copy link

This script can also be run under user-context, right?
Run this script using the logged-on credentials: Yes

@Tuttu
Copy link

Tuttu commented Mar 21, 2023

Yes, it can be used in user context. If so, it will display a message to the user about getting updates and prompting to close Office apps.

@dungadaman
Copy link

Yes, it can be used in user context. If so, it will display a message to the user about getting updates and prompting to close Office apps.

Actually, i have added 'ArgumentList' = "/update user updatepromptuser=false forceappshutdown=true" to force close the apps. In my test experience, this works best, with of course, propably missing latest edits of user documents. But my company agrees with this heavy method. Office needs to be patched quickly because of recent Outlook vulnerability.

@dungadaman
Copy link

Update: i've ran the detection script against a much older office installation and it fails and result in Exit code 0, thus not trying to remediate

Major Minor Build Revision


16 0 15427 20210

@nicolonsky
Copy link
Author

@dungadaman you can just perform a $null check for the $targetVersion I just updated the snippet

@dungadaman
Copy link

@dungadaman you can just perform a $null check for the $targetVersion I just updated the snippet
Thank you. I'll try asap. But at the moment, even with your latest edit, Remedation status Failed on every pc. Running your script interactively works. So something is wrong when deploying through Intune remediation.

@mdd-dsidler
Copy link

Set "Run script in 64-bit PowerShell" to YES, or it will not find the correct registry key

Oh! I feel so dumb. Didn't though about this. Thanks a lot. :)

That's OK, I had the same problem yesterday and took me 30 mins to realise :)

Good to hear I was not the only one ;-)

@Ali121-coder
Copy link

Ali121-coder commented Mar 29, 2023

Hi Everyone,

thank you for the script it worked for me perfectly. Few things I need to ask if someone can help me out with it.

1- should we target the devices or users in the proactive remediation package or it won’t matter?

2- what about the schedule? Should I run it once or daily or hourly? What’s a best practice and it won’t trigger the installation again and again on the fixed devices?

It would be really great if someone can guide me with it.

@Ali121-coder
Copy link

Can I anyone please let me know?

@TomislavPeharec
Copy link

@Ali121-coder In our case, we targeted the device group.

In the beginning we let it run hourly to get the clients checked and updated as soon as possible. Later we changed it so that it runs every few hours.
Even if you set it to run hourly, remediation will only run in case your clients haven’t updated to the version/s specified in the detection script.

In case the client already updated to the desired version (with PR or manually by the user), this info will be provided in the PR report (you just need to select all columns to be visible).

@Ali121-coder
Copy link

@TomislavPeharec thank you so much.

@femilovechild
Copy link

Can someone help? I am getting No Office ClickToRun on some computers even though they are running office 365 C2R version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment