v2, use old api endpoint

This commit is contained in:
tigeren 2024-12-23 14:04:54 +08:00
parent 5109e1ec3b
commit c4fa4ae57f
1 changed files with 115 additions and 97 deletions

View File

@ -20,10 +20,19 @@ param (
[string] $TenantId [string] $TenantId
) )
# Check for Microsoft.Graph module and install if needed # Check for and install required Microsoft.Graph modules
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) { $requiredModules = @(
Write-Host "Installing Microsoft.Graph module..." 'Microsoft.Graph.Authentication',
Install-Module Microsoft.Graph -Scope CurrentUser -Force 'Microsoft.Graph.Files',
'Microsoft.Graph.Users.Actions'
)
foreach ($module in $requiredModules) {
if (-not (Get-Module -ListAvailable -Name $module)) {
Write-Host "Installing $module module..."
Install-Module $module -Scope CurrentUser -Force
}
Import-Module $module -Force
} }
function Connect-GraphWithDebug { function Connect-GraphWithDebug {
@ -32,7 +41,9 @@ function Connect-GraphWithDebug {
$scopes = @( $scopes = @(
"Files.Read.All", "Files.Read.All",
"Files.ReadWrite.All", "Files.ReadWrite.All",
"offline_access" "offline_access",
"openid",
"profile"
) )
Write-Host "Connecting to Microsoft Graph..." Write-Host "Connecting to Microsoft Graph..."
@ -150,7 +161,9 @@ function Get-LivePhotoBundle {
[Parameter(Mandatory)] [Parameter(Mandatory)]
$item, $item,
[Parameter(Mandatory)] [Parameter(Mandatory)]
$drive $drive,
[Parameter(Mandatory)]
$AccessToken
) )
try { try {
@ -158,88 +171,45 @@ function Get-LivePhotoBundle {
Write-Host "Found HEIC file: $($item.Name)" -ForegroundColor Cyan Write-Host "Found HEIC file: $($item.Name)" -ForegroundColor Cyan
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($item.Name) $baseName = [System.IO.Path]::GetFileNameWithoutExtension($item.Name)
# Get current auth context and token # Get the video component using the direct video format API
$context = Get-MgContext $videoPath = Join-Path $SaveTo "$baseName.mov"
if (-not $context) { $tmpFile = Join-Path $SaveTo "tmp-file.mov"
throw "No authentication context found"
}
$token = $context.AccessToken if (-not (Test-Path $videoPath)) {
Write-Host "Using token: $($token.Substring(0, 10))..." -ForegroundColor Gray Write-Host "Attempting to download video component..."
# Get the item details with special fields # Use exactly the same endpoint and headers as original script
$itemEndpoint = "https://graph.microsoft.com/v1.0/drives/$($drive.Id)/items/$($item.Id)" $videoUri = "https://api.onedrive.com/v1.0/drive/items/$($item.Id)/content?format=video"
Write-Host "Getting item details..." Write-Host "Using video endpoint: $videoUri"
$headers = @{ try {
'Authorization' = "Bearer $token" # Use exact same headers as original script
'Accept' = 'application/json' $headers = @{
} 'Authorization' = "BEARER $AccessToken" # Note: BEARER in uppercase
# First try to get item metadata
try {
$response = Invoke-MgGraphRequest -Uri $itemEndpoint -Method GET
Write-Host "Got item metadata"
# Try to get the video component using Graph API
$videoEndpoint = "$itemEndpoint/content"
$videoPath = Join-Path $SaveTo "$baseName.mov"
if (-not (Test-Path $videoPath)) {
Write-Host "Attempting to download video component..."
# Try different content types
$videoHeaders = @{
'Authorization' = "Bearer $token"
'Accept' = 'video/quicktime'
'Prefer' = 'respond-async'
} }
# Try with special query parameters Write-Host "Calling OneDrive API for video..."
$queryParams = @( $WebRequest = Invoke-WebRequest -Method "GET" -Uri $videoUri -Header $headers -ErrorAction SilentlyContinue -OutFile $tmpFile -PassThru
"select=video", Write-Host "WebRequest: Done Calling OneDrive API"
"expand=video", if ((Test-Path $tmpFile) -and (Get-Item $tmpFile).Length -gt 0) {
"format=mov" $fileName = ($WebRequest.Headers.'Content-Disposition'.Split('=',2)[-1]).Trim('"')
) if ($fileName) {
Write-Host "Renaming $tmpFile to $fileName"
foreach ($param in $queryParams) { if (Test-Path $videoPath) {
$tryUrl = "${videoEndpoint}?$param" Remove-Item $videoPath
Write-Host "Trying URL: $tryUrl"
try {
Invoke-MgGraphRequest -Uri $tryUrl -Headers $videoHeaders -Method GET -OutputFilePath $videoPath
if ((Test-Path $videoPath) -and (Get-Item $videoPath).Length -gt 0) {
Write-Host "Successfully downloaded video component" -ForegroundColor Green
return $true
} }
} Rename-Item -Path $tmpFile -NewName $fileName
catch {
Write-Host "Attempt failed with $param : $_" -ForegroundColor Yellow
Remove-Item $videoPath -ErrorAction SilentlyContinue
}
}
# If all attempts failed, try one last time with direct Graph API call
try {
$finalEndpoint = "$itemEndpoint/video"
Write-Host "Trying final endpoint: $finalEndpoint"
Invoke-MgGraphRequest -Uri $finalEndpoint -Method GET -OutputFilePath $videoPath
if ((Test-Path $videoPath) -and (Get-Item $videoPath).Length -gt 0) {
Write-Host "Successfully downloaded video using final attempt" -ForegroundColor Green
return $true return $true
} }
} }
catch {
Write-Host "Final attempt failed: $_" -ForegroundColor Red
Remove-Item $videoPath -ErrorAction SilentlyContinue
}
} else {
Write-Host "Video file already exists: $videoPath" -ForegroundColor Yellow
return $true
} }
} catch {
catch { Write-Host "Failed to download video component: $_" -ForegroundColor Red
Write-Host "Failed to get item metadata: $_" -ForegroundColor Red Remove-Item $tmpFile -ErrorAction SilentlyContinue
}
} else {
Write-Host "Video file already exists: $videoPath" -ForegroundColor Yellow
return $true
} }
} }
return $false return $false
@ -250,23 +220,70 @@ function Get-LivePhotoBundle {
} }
} }
# Add this helper function to get a Photos-specific token if needed # Remove the old Get-ODPhotosToken function and use this updated version
function Get-ODPhotosToken { function Get-ODPhotosToken {
param( param(
[string]$ClientId = "073204aa-c1e0-4e66-a200-e5815a0aa93d" # OneDrive Photos client ID [string]$ClientId = "073204aa-c1e0-4e66-a200-e5815a0aa93d",
[string]$Scope = "OneDrive.ReadWrite,offline_access,openid,profile",
[string]$RedirectURI = "https://photos.onedrive.com/auth/login"
) )
$scopes = "OneDrive.ReadWrite offline_access" try {
$redirectUri = "https://photos.onedrive.com/auth/login" [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
# Get token using device code flow $URIGetAccessToken = "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id=$ClientId&nonce=uv.$(New-Guid).Guid&response_mode=form_post&scope=$Scope&response_type=code&redirect_URI=$RedirectURI"
$deviceCode = Get-MgDeviceCode -ClientId $ClientId -Scopes $scopes
Write-Host "Please visit: $($deviceCode.VerificationUri)" $form = New-Object Windows.Forms.Form
Write-Host "Enter code: $($deviceCode.UserCode)" $form.Text = "Authenticate to OneDrive"
$form.Size = New-Object Drawing.Size @(700,600)
$form.Width = 660
$form.Height = 775
$token = Get-MgToken -DeviceCode $deviceCode -ErrorAction Stop $web = New-Object System.Windows.Forms.WebBrowser
return $token.AccessToken $web.IsWebBrowserContextMenuEnabled = $true
$web.Width = 600
$web.Height = 700
$web.Location = "25, 25"
$web.ScriptErrorsSuppressed = $true
$DocComplete = {
if ($web.Url.AbsoluteUri -match "access_token=|error|code=|logout|/auth/login") {
$form.Close()
}
}
$web.Add_DocumentCompleted($DocComplete)
$form.Controls.Add($web)
$web.Navigate($URIGetAccessToken)
Write-Host "Please login in the opened browser window..."
$form.ShowDialog() | Out-Null
$Authentication = New-Object PSObject
# Get tokens from cookies
$web.Document.Cookie -split ';' | ForEach-Object {
$cookie = $_ -split '='
if ($cookie.Count -eq 2) {
$cookieValue = [uri]::UnescapeDataString($cookie[1])
$Authentication | Add-Member NoteProperty $cookie[0].Trim() $cookieValue
}
}
if (-not $Authentication.'AccessToken-OneDrive.ReadWrite') {
Write-Error "Failed to get authentication token. Please try again."
return $null
}
Write-Host "Successfully obtained authentication token"
return $Authentication
}
catch {
Write-Error "Error in Get-ODPhotosToken: $_"
return $null
}
} }
# Main execution # Main execution
@ -279,14 +296,15 @@ if (!(Test-Path $SaveTo)) {
New-Item -ItemType Directory -Force -Path $SaveTo New-Item -ItemType Directory -Force -Path $SaveTo
} }
# Connect to Graph API # Get both authentication tokens
Write-Host "Getting Graph API token..."
if (Connect-GraphWithDebug) { if (Connect-GraphWithDebug) {
Write-Host "`nGetting OneDrive Photos token..."
$photosToken = Get-ODPhotosToken
Write-Host "`nQuerying OneDrive items..." Write-Host "`nQuerying OneDrive items..."
$items = Get-DriveItems -FolderPath $PathToScan $items = Get-DriveItems -FolderPath $PathToScan
# print the items to the console
# $items | Format-List | Out-String | Write-Host
if ($items) { if ($items) {
# Get drive reference # Get drive reference
$drive = Get-MgDrive -Filter "driveType eq 'personal'" | Select-Object -First 1 $drive = Get-MgDrive -Filter "driveType eq 'personal'" | Select-Object -First 1
@ -307,8 +325,8 @@ if (Connect-GraphWithDebug) {
try { try {
$result = Test-DownloadItem -ItemId $item.Id -SavePath $SaveTo -item $item $result = Test-DownloadItem -ItemId $item.Id -SavePath $SaveTo -item $item
if ($result) { if ($result) {
# Try to get the video component # Try to get the video component, passing all items and the photos token
$hasVideo = Get-LivePhotoBundle -item $item -drive $drive $hasVideo = Get-LivePhotoBundle -item $item -drive $drive -AccessToken $photosToken.'AccessToken-OneDrive.ReadWrite'
if ($hasVideo) { if ($hasVideo) {
Write-Host "Successfully processed Live Photo bundle for: $($item.Name)" -ForegroundColor Green Write-Host "Successfully processed Live Photo bundle for: $($item.Name)" -ForegroundColor Green
} else { } else {