try { $enumDef = " using System; [FlagsAttribute] public enum OfficeChannel { FirstReleaseCurrent = 0, Current = 1, FirstReleaseDeferred = 2, Deferred = 3, MonthlyTargeted=4, Monthly=5, SemiAnnualTargeted=6, SemiAnnual=7 } " Add-Type -TypeDefinition $enumDef -ErrorAction SilentlyContinue } catch { } try { $enumBitness = " using System; [FlagsAttribute] public enum Bitness { Both = 0, v32 = 1, v64 = 2 } " Add-Type -TypeDefinition $enumBitness -ErrorAction SilentlyContinue } catch { } try { $enum = " using System; namespace Microsoft.Office { [FlagsAttribute] public enum Products { Unknown = 0, O365ProPlusRetail = 1, O365BusinessRetail = 2, VisioProRetail = 4, ProjectProRetail = 8, SPDRetail = 16, VisioProXVolume = 32, VisioStdXVolume = 64, ProjectProXVolume = 128, ProjectStdXVolume = 256, InfoPathRetail = 512, SkypeforBusinessEntryRetail = 1024, LyncEntryRetail = 2048, AccessRuntimeRetail = 4096 } } " Add-Type -TypeDefinition $enum -ErrorAction SilentlyContinue } catch {} try { $enum = " using System; namespace Microsoft.Office { [FlagsAttribute] public enum ProductSelection { All = 0, O365ProPlusRetail = 1, O365BusinessRetail = 2, VisioProRetail = 4, ProjectProRetail = 8, SPDRetail = 16, VisioProXVolume = 32, VisioStdXVolume = 64, ProjectProXVolume = 128, ProjectStdXVolume = 256, InfoPathRetail = 512, SkypeforBusinessEntryRetail = 1024, LyncEntryRetail = 2048, AccessRuntimeRetail = 4096 } } " Add-Type -TypeDefinition $enum -ErrorAction SilentlyContinue } catch {} [System.Collections.ArrayList]$missingFiles = @() Function Write-Log { PARAM ( [String]$Message, [String]$Path = $Global:UpdateAnywhereLogPath, [String]$LogName = $Global:UpdateAnywhereLogFileName, [int]$severity, [string]$component ) try { $Path = $Global:UpdateAnywhereLogPath $LogName = $Global:UpdateAnywhereLogFileName if([String]::IsNullOrWhiteSpace($Path)){ # Get Windows Folder Path $windowsDirectory = [Environment]::GetFolderPath("Windows") # Build log folder $Path = "$windowsDirectory\CCM\logs" } if([String]::IsNullOrWhiteSpace($LogName)){ # Set log file name $LogName = "Office365UpdateAnywhere.log" } # Build log path $LogFilePath = Join-Path $Path $LogName # Create log file If (!($(Test-Path $LogFilePath -PathType Leaf))) { $null = New-Item -Path $LogFilePath -ItemType File -ErrorAction SilentlyContinue } $TimeZoneBias = Get-WmiObject -Query "Select Bias from Win32_TimeZone" $Date= Get-Date -Format "HH:mm:ss.fff" $Date2= Get-Date -Format "MM-dd-yyyy" $type=1 if ($LogFilePath) { ""| Out-File -FilePath $LogFilePath -Append -NoClobber -Encoding default } } catch { } } Function Set-Reg { PARAM ( [String]$hive, [String]$keyPath, [String]$valueName, [String]$value, [String]$Type ) Try { $null = New-ItemProperty -Path "$($hive):\$($keyPath)" -Name "$($valueName)" -Value "$($value)" -PropertyType $Type -Force -ErrorAction Stop } Catch { Write-Log -Message $_.Exception.Message -severity 3 -component $LogFileName } } Function StartProcess { Param ( [Parameter()] [String]$execFilePath, [Parameter()] [String]$execParams, [Parameter()] [bool]$WaitForExit = $false ) Try { $startExe = new-object System.Diagnostics.ProcessStartInfo $startExe.FileName = $execFilePath $startExe.Arguments = $execParams $startExe.CreateNoWindow = $false $startExe.UseShellExecute = $false $execStatement = [System.Diagnostics.Process]::Start($startExe) if ($WaitForExit) { $execStatement.WaitForExit() } } Catch { Write-Log -Message $_.Exception.Message -severity 1 -component "Office 365 Update Anywhere" } } function Test-ItemPathUNC() { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [String]$Path, [Parameter()] [String]$FileName = $null ) Process { $pathExists = $false if ($FileName) { $filePath = "$Path\$FileName" $pathExists = [System.IO.File]::Exists($filePath) } else { $pathExists = [System.IO.Directory]::Exists($Path) if (!($pathExists)) { $pathExists = [System.IO.File]::Exists($Path) } } return $pathExists; } } function Copy-ItemUNC() { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [String]$SourcePath, [Parameter(Mandatory=$true)] [String]$TargetPath, [Parameter(Mandatory=$true)] [String]$FileName ) Process { $drvLetter = FindAvailable $Network = New-Object -ComObject "Wscript.Network" try { if (!($drvLetter.EndsWith(":"))) { $drvLetter += ":" } $target = $drvLetter + "\" $Network.MapNetworkDrive($drvLetter, $TargetPath) #New-PSDrive -Name $drvLetter -PSProvider FileSystem -Root $TargetPath | Out-Null Copy-Item -Path $SourcePath -Destination $target -Force } finally { #Remove-PSDrive $drvLetter $Network.RemoveNetworkDrive($drvLetter) } } } function FindAvailable() { $drives = Get-WmiObject -Class Win32_LogicalDisk | select DeviceID for($n=90;$n -gt 68;$n--) { $letter= [char]$n + ":" $exists = $drives | where { $_.DeviceID -eq $letter } if ($exists) { if ($exists.Count -eq 0) { return $letter } } else { return $letter } } return $null } function Get-XMLLanguages() { [CmdletBinding(SupportsShouldProcess=$true)] param( [Parameter(Mandatory=$true)] [String]$Path ) Process { [string[]]$languages = @() [xml]$configXml = Get-Content $Path if ($configXml.Configuration.Add) { foreach ($product in $configXml.Configuration.Add.Product) { foreach ($language in $product.Language) { $languages += $language.ID } } } return $languages } } Function Get-OfficeVersion { <# .Synopsis Gets the Office Version installed on the computer .DESCRIPTION This function will query the local or a remote computer and return the information about Office Products installed on the computer .NOTES Name: Get-OfficeVersion Version: 1.0.5 DateCreated: 2015-07-01 DateUpdated: 2016-10-14 .LINK https://github.com/OfficeDev/Office-IT-Pro-Deployment-Scripts .PARAMETER ComputerName The computer or list of computers from which to query .PARAMETER ShowAllInstalledProducts Will expand the output to include all installed Office products .EXAMPLE Get-OfficeVersion Will return the locally installed Office product .EXAMPLE Get-OfficeVersion -ComputerName client01,client02 Will return the installed Office product on the remote computers .EXAMPLE Get-OfficeVersion | select * Will return the locally installed Office product with all of the available properties #> [CmdletBinding(SupportsShouldProcess=$true)] param( [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true, Position=0)] [string[]]$ComputerName = $env:COMPUTERNAME, [switch]$ShowAllInstalledProducts, [System.Management.Automation.PSCredential]$Credentials ) begin { $HKLM = [UInt32] "0x80000002" $HKCR = [UInt32] "0x80000000" $excelKeyPath = "Excel\DefaultIcon" $wordKeyPath = "Word\DefaultIcon" $installKeys = 'SOFTWARE\Microsoft\Windows\CurrentVersionninstall', 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersionninstall' $officeKeys = 'SOFTWARE\Microsoft\Office', 'SOFTWARE\Wow6432Node\Microsoft\Office' $defaultDisplaySet = 'DisplayName','Version', 'ComputerName' $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultDisplaySet) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet) } process { $results = new-object PSObject[] 0; $MSexceptionList = "mui","visio","project","proofing","visual" foreach ($computer in $ComputerName) { if ($Credentials) { $os=Get-WMIObject win32_operatingsystem -computername $computer -Credential $Credentials } else { $os=Get-WMIObject win32_operatingsystem -computername $computer } $osArchitecture = $os.OSArchitecture if ($Credentials) { $regProv = Get-Wmiobject -list "StdRegProv" -namespace root\default -computername $computer -Credential $Credentials } else { $regProv = Get-Wmiobject -list "StdRegProv" -namespace root\default -computername $computer } [System.Collections.ArrayList]$VersionList = New-Object -TypeName System.Collections.ArrayList [System.Collections.ArrayList]$PathList = New-Object -TypeName System.Collections.ArrayList [System.Collections.ArrayList]$PackageList = New-Object -TypeName System.Collections.ArrayList [System.Collections.ArrayList]$ClickToRunPathList = New-Object -TypeName System.Collections.ArrayList [System.Collections.ArrayList]$ConfigItemList = New-Object -TypeName System.Collections.ArrayList $ClickToRunList = new-object PSObject[] 0; foreach ($regKey in $officeKeys) { $officeVersion = $regProv.EnumKey($HKLM, $regKey) foreach ($key in $officeVersion.sNames) { if ($key -match "\d{2}\.\d") { if (!$VersionList.Contains($key)) { $AddItem = $VersionList.Add($key) } $path = join-path $regKey $key $configPath = join-path $path "Common\Config" $configItems = $regProv.EnumKey($HKLM, $configPath) if ($configItems) { foreach ($configId in $configItems.sNames) { if ($configId) { $Add = $ConfigItemList.Add($configId.ToUpper()) } } } $cltr = New-Object -TypeName PSObject $cltr | Add-Member -MemberType NoteProperty -Name InstallPath -Value "" $cltr | Add-Member -MemberType NoteProperty -Name UpdatesEnabled -Value $false $cltr | Add-Member -MemberType NoteProperty -Name UpdateUrl -Value "" $cltr | Add-Member -MemberType NoteProperty -Name StreamingFinished -Value $false $cltr | Add-Member -MemberType NoteProperty -Name Platform -Value "" $cltr | Add-Member -MemberType NoteProperty -Name ClientCulture -Value "" $packagePath = join-path $path "Common\InstalledPackages" $clickToRunPath = join-path $path "ClickToRun\Configuration" $virtualInstallPath = $regProv.GetStringValue($HKLM, $clickToRunPath, "InstallationPath").sValue [string]$officeLangResourcePath = join-path $path "Common\LanguageResources" $mainLangId = $regProv.GetDWORDValue($HKLM, $officeLangResourcePath, "SKULanguage").uValue if ($mainLangId) { $mainlangCulture = [globalization.cultureinfo]::GetCultures("allCultures") | where {$_.LCID -eq $mainLangId} if ($mainlangCulture) { $cltr.ClientCulture = $mainlangCulture.Name } } [string]$officeLangPath = join-path $path "Common\LanguageResources\InstalledUIs" $langValues = $regProv.EnumValues($HKLM, $officeLangPath); if ($langValues) { foreach ($langValue in $langValues) { $langCulture = [globalization.cultureinfo]::GetCultures("allCultures") | where {$_.LCID -eq $langValue} } } if ($virtualInstallPath) { } else { $clickToRunPath = join-path $regKey "ClickToRun\Configuration" $virtualInstallPath = $regProv.GetStringValue($HKLM, $clickToRunPath, "InstallationPath").sValue } if ($virtualInstallPath) { if (!$ClickToRunPathList.Contains($virtualInstallPath.ToUpper())) { $AddItem = $ClickToRunPathList.Add($virtualInstallPath.ToUpper()) } $cltr.InstallPath = $virtualInstallPath $cltr.StreamingFinished = $regProv.GetStringValue($HKLM, $clickToRunPath, "StreamingFinished").sValue $cltr.UpdatesEnabled = $regProv.GetStringValue($HKLM, $clickToRunPath, "UpdatesEnabled").sValue $cltr.UpdateUrl = $regProv.GetStringValue($HKLM, $clickToRunPath, "UpdateUrl").sValue $cltr.Platform = $regProv.GetStringValue($HKLM, $clickToRunPath, "Platform").sValue $cltr.ClientCulture = $regProv.GetStringValue($HKLM, $clickToRunPath, "ClientCulture").sValue $ClickToRunList += $cltr } $packageItems = $regProv.EnumKey($HKLM, $packagePath) $officeItems = $regProv.EnumKey($HKLM, $path) foreach ($itemKey in $officeItems.sNames) { $itemPath = join-path $path $itemKey $installRootPath = join-path $itemPath "InstallRoot" $filePath = $regProv.GetStringValue($HKLM, $installRootPath, "Path").sValue if (!$PathList.Contains($filePath)) { $AddItem = $PathList.Add($filePath) } } foreach ($packageGuid in $packageItems.sNames) { $packageItemPath = join-path $packagePath $packageGuid $packageName = $regProv.GetStringValue($HKLM, $packageItemPath, "").sValue if (!$PackageList.Contains($packageName)) { if ($packageName) { $AddItem = $PackageList.Add($packageName.Replace(' ', '').ToLower()) } } } } } } foreach ($regKey in $installKeys) { $keyList = new-object System.Collections.ArrayList $keys = $regProv.EnumKey($HKLM, $regKey) foreach ($key in $keys.sNames) { $path = join-path $regKey $key $installPath = $regProv.GetStringValue($HKLM, $path, "InstallLocation").sValue if (!($installPath)) { continue } if ($installPath.Length -eq 0) { continue } $buildType = "64-Bit" if ($osArchitecture -eq "32-bit") { $buildType = "32-Bit" } if ($regKey.ToUpper().Contains("Wow6432Node".ToUpper())) { $buildType = "32-Bit" } if ($key -match "{.{8}-.{4}-.{4}-1000-0000000FF1CE}") { $buildType = "64-Bit" } if ($key -match "{.{8}-.{4}-.{4}-0000-0000000FF1CE}") { $buildType = "32-Bit" } if ($modifyPath) { if ($modifyPath.ToLower().Contains("platform=x86")) { $buildType = "32-Bit" } if ($modifyPath.ToLower().Contains("platform=x64")) { $buildType = "64-Bit" } } $primaryOfficeProduct = $false $officeProduct = $false foreach ($officeInstallPath in $PathList) { if ($officeInstallPath) { try{ $installReg = "^" + $installPath.Replace('\', '\') $installReg = $installReg.Replace('(', '\(') $installReg = $installReg.Replace(')', '\)') if ($officeInstallPath -match $installReg) { $officeProduct = $true } } catch {} } } if (!$officeProduct) { continue }; $name = $regProv.GetStringValue($HKLM, $path, "DisplayName").sValue $primaryOfficeProduct = $true if ($ConfigItemList.Contains($key.ToUpper()) -and $name.ToUpper().Contains("MICROSOFT OFFICE")) { foreach($exception in $MSexceptionList){ if($name.ToLower() -match $exception.ToLower()){ $primaryOfficeProduct = $false } } } else { $primaryOfficeProduct = $false } $clickToRunComponent = $regProv.GetDWORDValue($HKLM, $path, "ClickToRunComponent").uValue $uninstallString = $regProv.GetStringValue($HKLM, $path, "UninstallString").sValue if (!($clickToRunComponent)) { if ($uninstallString) { if ($uninstallString.Contains("OfficeClickToRun")) { $clickToRunComponent = $true } } } $modifyPath = $regProv.GetStringValue($HKLM, $path, "ModifyPath").sValue $version = $regProv.GetStringValue($HKLM, $path, "DisplayVersion").sValue $cltrUpdatedEnabled = $NULL $cltrUpdateUrl = $NULL $clientCulture = $NULL; [string]$clickToRun = $false if ($clickToRunComponent) { $clickToRun = $true if ($name.ToUpper().Contains("MICROSOFT OFFICE")) { $primaryOfficeProduct = $true } foreach ($cltr in $ClickToRunList) { if ($cltr.InstallPath) { if ($cltr.InstallPath.ToUpper() -eq $installPath.ToUpper()) { $cltrUpdatedEnabled = $cltr.UpdatesEnabled $cltrUpdateUrl = $cltr.UpdateUrl if ($cltr.Platform -eq 'x64') { $buildType = "64-Bit" } if ($cltr.Platform -eq 'x86') { $buildType = "32-Bit" } $clientCulture = $cltr.ClientCulture } } } } if (!$primaryOfficeProduct) { if (!$ShowAllInstalledProducts) { continue } } $object = New-Object PSObject -Property @{DisplayName = $name; Version = $version; InstallPath = $installPath; ClickToRun = $clickToRun; Bitness=$buildType; ComputerName=$computer; ClickToRunUpdatesEnabled=$cltrUpdatedEnabled; ClickToRunUpdateUrl=$cltrUpdateUrl; ClientCulture=$clientCulture } $object | Add-Member MemberSet PSStandardMembers $PSStandardMembers $results += $object } } } $results = Get-Unique -InputObject $results return $results; } } Function Get-InstalledLanguages() { [CmdletBinding()] Param( [string]$computer = $env:COMPUTERNAME ) process { $returnLangs = @() $mainRegPath = Get-OfficeCTRRegPath if ($mainRegPath) { if (Test-Path -Path "hklm:\$mainRegPath\ProductReleaseIDs") { $activeConfig = Get-ItemProperty -Path "hklm:\$mainRegPath\ProductReleaseIDs" if($activeConfig.ActiveConfiguration){ $activeId = $activeConfig.ActiveConfiguration $languages = Get-ChildItem -Path "hklm:\$mainRegPath\ProductReleaseIDs\$activeId