Scripts/Update-OneDriveSetup.ps1
<#
.SYNOPSIS Update OneDrive during Windows image creation .DESCRIPTION The version of OneDrive bundled with a Windows release will often be out-of-date by the time of deployment to a client system. While OneDrive will update itself, updates for older versions can require Administrator privileges, which users may not have. By pre-installing the latest update, unwanted UAC prompts can be avoided, while also streamlining the initial logon process. .PARAMETER SetupDestDir Path to the directory where the OneDrive setup file will be stored. The default is "$env:ProgramData\Microsoft\OneDriveSetup". .PARAMETER SetupFilePath Path to the OneDrive setup file. The default is "OneDriveSetup.exe" in the current working directory. .PARAMETER SkipRunningSetup Skips executing OneDrive setup. .PARAMETER SkipUpdatingDefaultProfile Skips updating the default user profile to run OneDrive setup on login. .EXAMPLE Update-OneDriveSetup Copies OneDrive setup to the default destination path, runs setup, and updates the default user profile. .NOTES OneDrive release notes https://support.microsoft.com/en-us/office/onedrive-release-notes-845dcf18-f921-435e-bf28-4e24b95e5fc0 .LINK https://github.com/ralish/PSWinGlue #> #Requires -Version 3.0 [CmdletBinding()] [OutputType([Void])] Param( [ValidateNotNullOrEmpty()] [String]$SetupFilePath = 'OneDriveSetup.exe', [ValidateNotNullOrEmpty()] [String]$SetupDestDir = "$env:ProgramData\Microsoft\OneDriveSetup", [Switch]$SkipRunningSetup, [Switch]$SkipUpdatingDefaultProfile ) $PowerShellCore = New-Object -TypeName Version -ArgumentList 6, 0 if ($PSVersionTable.PSVersion -ge $PowerShellCore -and $PSVersionTable.Platform -ne 'Win32NT') { throw '{0} is only compatible with Windows.' -f $MyInvocation.MyCommand.Name } $User = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() if (!$User.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw '{0} requires Administrator privileges.' -f $MyInvocation.MyCommand.Name } if ($SkipRunningSetup -and $SkipUpdatingDefaultProfile) { throw 'Nothing to do as all operations skipped!' } $SetupFile = Get-Item -Path $SetupFilePath -ErrorAction Stop if ($SetupFile -isnot [IO.FileInfo]) { throw 'OneDrive setup path is not a file: {0}' -f $SetupFilePath } elseif ($SetupFile.Extension -ne '.exe') { throw 'OneDrive setup file must be an executable: {0}' -f $SetupFilePath } if (!(Test-Path -Path $SetupDestDir -PathType Container)) { Write-Verbose -Message 'Creating OneDrive setup directory ...' $null = New-Item -Path $SetupDestDir -ItemType Directory -Force -ErrorAction Ignore } $SetupDest = Get-Item -Path $SetupDestDir -ErrorAction Stop if ($SetupDest -isnot [IO.DirectoryInfo]) { throw 'OneDrive setup destination is not a directory: {0}' -f $SetupDestDir } Write-Verbose -Message 'Copying OneDrive setup file ...' $SetupDestFilePath = Join-Path -Path $SetupDestDir -ChildPath 'OneDriveSetup.exe' Copy-Item -Path $SetupFilePath -Destination $SetupDestFilePath -Force [IO.FileInfo]$SetupFilePath = Get-Item -Path $SetupDestFilePath -ErrorAction Stop if (!$SkipRunningSetup) { Write-Verbose -Message 'Terminating any existing OneDrive setup ...' Stop-Process -Name 'OneDriveSetup' -ErrorAction Ignore Write-Verbose -Message 'Running OneDrive setup ...' $OneDriveSetup = Start-Process -FilePath $SetupFilePath.FullName -ArgumentList '/silent' -Wait -PassThru if ($OneDriveSetup.ExitCode -notin ('0', '3010')) { throw ('OneDrive setup returned exit code: {0}' -f $OneDriveSetup.ExitCode) } } if (!$SkipUpdatingDefaultProfile) { Write-Verbose -Message 'Updating OneDrive setup path for default user profile ...' if (!('PSWinGlue.UpdateOneDriveSetup' -as [Type])) { $GetDefaultUserProfileDirectory = @' [DllImport("userenv.dll", EntryPoint = "GetDefaultUserProfileDirectoryW", SetLastError = true)] public static extern bool GetDefaultUserProfileDirectory(IntPtr lpProfileDir, out uint lpcchSize); [DllImport("userenv.dll", CharSet = CharSet.Unicode, EntryPoint = "GetDefaultUserProfileDirectoryW", ExactSpelling = true, SetLastError = true)] public static extern bool GetDefaultUserProfileDirectory(System.Text.StringBuilder lpProfileDir, out uint lpcchSize); '@ Add-Type -Namespace 'PSWinGlue' -Name 'UpdateOneDriveSetup' -MemberDefinition $GetDefaultUserProfileDirectory } $DefaultUserProfileBufSize = 0 $null = [PSWinGlue.UpdateOneDriveSetup]::GetDefaultUserProfileDirectory([IntPtr]::Zero, [ref]$DefaultUserProfileBufSize) if (!$DefaultUserProfileBufSize) { throw 'Failed to determine buffer size for GetDefaultUserProfileDirectory().' } $DefaultUserProfilePath = New-Object -TypeName 'Text.StringBuilder' -ArgumentList ($DefaultUserProfileBufSize - 1) if ([PSWinGlue.UpdateOneDriveSetup]::GetDefaultUserProfileDirectory($DefaultUserProfilePath, [ref]$DefaultUserProfileBufSize) -eq $false) { throw (New-Object -TypeName 'ComponentModel.Win32Exception') } $DefaultUserProfileHive = Join-Path -Path $DefaultUserProfilePath.ToString() -ChildPath 'NTUSER.DAT' Write-Debug -Message ('Default user profile registry hive: {0}' -f $DefaultUserProfileHive) $Registry = Start-Process -FilePath 'reg' -ArgumentList 'LOAD', 'HKLM\OneDriveSetup', "`"$DefaultUserProfileHive`"" -Wait -PassThru if ($Registry.ExitCode -ne 0) { throw 'Failed to load the default user profile registry hive with error code: {0}' -f $Registry.ExitCode } Set-ItemProperty -Path 'HKLM:\OneDriveSetup\Software\Microsoft\Windows\CurrentVersion\Run' -Name 'OneDriveSetup' -Value $SetupFilePath.FullName $Registry = Start-Process -FilePath 'reg' -ArgumentList 'UNLOAD', 'HKLM\OneDriveSetup' -Wait -PassThru if ($Registry.ExitCode -ne 0) { throw 'Failed to unload the default user profile registry hive with error code: {0}' -f $Registry.ExitCode } } |