-
-
Save nicolonsky/b04dd77129577f782178c0c049344101 to your computer and use it in GitHub Desktop.
# 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 |
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 :)
@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()
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(
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.
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
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.
@TomislavPeharec have you tried to run the script manually on a machine or event browsed to HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration?
@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.
This script can also be run under user-context, right?
Run this script using the logged-on credentials: Yes
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.
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.
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
@dungadaman you can just perform a $null
check for the $targetVersion
I just updated the snippet
@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.
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 ;-)
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.
Can I anyone please let me know?
@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).
@TomislavPeharec thank you so much.
Can someone help? I am getting No Office ClickToRun on some computers even though they are running office 365 C2R version
Oh! I feel so dumb. Didn't though about this. Thanks a lot. :)