# Update-LibreOffice.ps1
# Written by Bill Stewart (bstewart AT iname.com)

#requires -RunAsAdministrator
#requires -Version 5

<#

.SYNOPSIS

Downloads and optionally installs the latest version of LibreOffice.

.DESCRIPTION

Downloads and optionally installs the latest version of LibreOffice, including offline help. Requires internet access.

.PARAMETER DownloadPath

Specify the path where to download the LibreOffice installer (.msi) packages.

.PARAMETER LogFilePath

Specifies the path and filename of the log file if the -EnableLogging parameter is specified.

.PARAMETER HelpLanguage

Specifies the language for the offline help package. The default is the current locale.

.PARAMETER EnableLogging

Enables logging to the log file path specified by the -LogFilePath parameter. If you omit the -LogFilePath parameter, the log file is the same path and filename as the script, except for the '.log' extension.

.PARAMETER Install

Automatically starts the installation after downloading completes.

.PARAMETER Quiet

Runs the installation of the packages without user interaction.

#>

[CmdletBinding()]
param(
  [Parameter(Position = 0,Mandatory)]
  [ValidateNotNullOrEmpty()]
  [String]
  $DownloadPath,

  [String]
  $LogFilePath,

  [ValidateNotNullOrEmpty()]
  [String]
  $HelpLanguage = (Get-Culture).Name,

  [Switch]
  $EnableLogging,

  [Switch]
  $Install,

  [Switch]
  $Quiet
)

function Get-LibreOfficeLatestVersion {
  $url = "http://download.documentfoundation.org/libreoffice/stable/"
  $pattern = '<tr><td valign="top">&nbsp;</td><td><a href="((?:\d+\.){1,3}\d+)'
  $webContent = (Invoke-WebRequest $url -UseBasicParsing |
    Select-Object -ExpandProperty Content) -split "`n"
  if ( $null -ne $webContent ) {
    $webContent |
    Select-String $pattern |
    ForEach-Object {
      $_.Matches[0].Groups[1].Value
    } | Sort-Object { $_ -as [Version] } | Select-Object -Last 1
  }
}

function Get-LibreOfficeInstalledVersion {
  $keyPath = "HKLM:SOFTWARE\LibreOffice\LibreOffice"
  $currentVersion = Get-ChildItem $keyPath -ErrorAction SilentlyContinue |
  Select-Object -ExpandProperty Name |
  Split-Path -Leaf |
  Sort-Object |
  Select-Object -Last 1
  if ( $null -ne $currentVersion ) {
    $path = (Get-ItemProperty (Join-Path $keyPath $currentVersion)).Path
    if ( $null -ne $path ) {
      $item = Get-Item -LiteralPath $path -ErrorAction SilentlyContinue
      if ( $null -ne $item ) {
        $item.VersionInfo.ProductVersion
      }
    }
  }
}

function Get-Platform {
  $result = "x86"
  $sysType = Get-WmiObject Win32_ComputerSystem |
  Select-Object -ExpandProperty SystemType
  if ( $sysType -like "*x64*" ) {
    $osArch = Get-WmiObject Win32_OperatingSystem |
    Select-Object -ExpandProperty OSArchitecture
    if ( $osArch -eq "64-bit" ) {
      $result = "x86_64"
    }
  }
  return $result
}

function Join-URLPath {
  param(
    [String]
    $part1,

    [String]
    $part2
  )
  while ( $part1[$part1.Length - 1] -eq "/" ) {
    $part1 = $part1.Substring(0,$part1.Length - 1)
  }
  "{0}/{1}" -f $part1,$part2
}

function Get-LibreOfficeLatestPackage {
  param(
    [Parameter(Mandatory)]
    [ValidateNotNullOrEmpty()]
    [String]
    $downloadPath,

    [Parameter(Mandatory)]
    [ValidateNotNullOrEmpty()]
    [String]
    $latestVersion
  )
  $platform = Get-Platform
  if ( $platform -eq "x86_64" ) {
    $fileNames = @(
      "LibreOffice_{0}_Win_x86-64.msi" -f $latestVersion
      "LibreOffice_{0}_Win_x86-64_helppack_{1}.msi" -f $latestVersion,$HelpLanguage
    )
  }
  else {
    $fileNames = @(
      "LibreOffice_{0}_Win_x86.msi" -f $latestVersion
      "LibreOffice_{0}_Win_x86_helppack_{1}.msi" -f $latestVersion,$HelpLanguage
    )
  }
  $remotePath = "http://download.documentfoundation.org/libreoffice/stable/$latestVersion/win/$platform/"
  foreach ( $fileName in $fileNames ) {
    $url = Join-URLPath $remotePath $fileName
    $downloadFileName = Join-Path $downloadPath $fileName
    Write-Host "Download: $url"
    $timeSpan = Measure-Command { Invoke-WebRequest -Uri $url -OutFile $downloadFileName }
    if ( $? ) {
      $downloadFileName
      Write-Host ('Downloaded {0} [{1:N0} byte(s) in {2}]' -f $downloadFileName,
      (Get-Item $downloadFileName).Length,$timeSpan)
    }
  }
}

function Get-Version {
  [CmdletBinding()]
  param(
    [Version]
    $version
  )
  $major = [Math]::Max($version.Major,0)
  $minor = [Math]::Max($version.Minor,0)
  $build = [Math]::Max($version.Build,0)
  $revision = [Math]::Max($version.Revision,0)
  return New-Object Version($major,$minor,$build,$revision)
}

if ( $EnableLogging ) {
  if ( -not $LogFilePath ) {
    $LogFilePath = "{0}.log" -f (Join-Path $PSScriptRoot ([IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)))
  }
  else {
    if ( ($LogFilePath -notlike "*\*") -or ($LogFilePath -notlike "*/*") ) {
      $LogFilePath = Join-Path $PSScriptRoot $LogFilePath
    }
  }
  Start-Transcript $LogFilePath
  if ( -not $? ) {
    return
  }
}

$LatestVersion = Get-LibreOfficeLatestVersion
if ( -not $LatestVersion ) {
  if ( $EnableLogging ) {
    Stop-Transcript
  }
  return
}
Write-Host "Latest LibreOffice version: $LatestVersion"

$InstalledVersion = Get-LibreOfficeInstalledVersion
if ( -not $InstalledVersion ) {
  $InstalledVersion = "0.0.0.0"
  Write-Host "LibreOffice not installed"
}
else {
  Write-Host "LibreOffice installed version: $InstalledVersion"
}
if ( (Get-Version $LatestVersion) -gt (Get-Version $InstalledVersion) ) {
  if ( $Quiet ) {
    $Stopwatch = New-Object Diagnostics.Stopwatch
    $Stopwatch.Start()
  }
  $DownloadFileNames = Get-LibreOfficeLatestPackage $DownloadPath $LatestVersion
  if ( $Install ) {
    $MsiExec = Join-Path ([Environment]::GetFolderPath([Environment+SpecialFolder]::System)) "msiexec.exe"
    $StartArgs = @{
      "FilePath" = $MsiExec
      "Wait"     = $true
    }
    foreach ( $DownloadFileName in $DownloadFileNames ) {
      $StartArgs.ArgumentList = '/i',('"{0}"' -f $DownloadFileName)
      if ( $Quiet ) {
        $StartArgs.ArgumentList += '/qb-','REBOOT=ReallySuppress'
      }
      $Message = 'Run: {0} {1}' -f $MsiExec,($StartArgs.ArgumentList -join ' ')
      Write-Host $Message
      $timeSpan = Measure-Command { Start-Process @StartArgs }
      if ( $Quiet ) {
        Write-Host "Installation completed in $timeSpan"
      }
    }
  }
  if ( $Quiet ) {
    $Stopwatch.Stop()
    Write-Host ("Full completion time: {0}" -f $Stopwatch.Elapsed)
  }
}

if ( $EnableLogging ) {
  Stop-Transcript
}