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
)
# Check for Microsoft.Graph module and install if needed
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) {
Write-Host "Installing Microsoft.Graph module..."
Install-Module Microsoft.Graph -Scope CurrentUser -Force
# Check for and install required Microsoft.Graph modules
$requiredModules = @(
'Microsoft.Graph.Authentication',
'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 {
@ -32,7 +41,9 @@ function Connect-GraphWithDebug {
$scopes = @(
"Files.Read.All",
"Files.ReadWrite.All",
"offline_access"
"offline_access",
"openid",
"profile"
)
Write-Host "Connecting to Microsoft Graph..."
@ -150,7 +161,9 @@ function Get-LivePhotoBundle {
[Parameter(Mandatory)]
$item,
[Parameter(Mandatory)]
$drive
$drive,
[Parameter(Mandatory)]
$AccessToken
)
try {
@ -158,88 +171,45 @@ function Get-LivePhotoBundle {
Write-Host "Found HEIC file: $($item.Name)" -ForegroundColor Cyan
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($item.Name)
# Get current auth context and token
$context = Get-MgContext
if (-not $context) {
throw "No authentication context found"
}
# Get the video component using the direct video format API
$videoPath = Join-Path $SaveTo "$baseName.mov"
$tmpFile = Join-Path $SaveTo "tmp-file.mov"
$token = $context.AccessToken
Write-Host "Using token: $($token.Substring(0, 10))..." -ForegroundColor Gray
# Get the item details with special fields
$itemEndpoint = "https://graph.microsoft.com/v1.0/drives/$($drive.Id)/items/$($item.Id)"
Write-Host "Getting item details..."
$headers = @{
'Authorization' = "Bearer $token"
'Accept' = 'application/json'
}
# First try to get item metadata
try {
$response = Invoke-MgGraphRequest -Uri $itemEndpoint -Method GET
Write-Host "Got item metadata"
if (-not (Test-Path $videoPath)) {
Write-Host "Attempting to download video component..."
# Try to get the video component using Graph API
$videoEndpoint = "$itemEndpoint/content"
$videoPath = Join-Path $SaveTo "$baseName.mov"
# Use exactly the same endpoint and headers as original script
$videoUri = "https://api.onedrive.com/v1.0/drive/items/$($item.Id)/content?format=video"
Write-Host "Using video endpoint: $videoUri"
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 {
# Use exact same headers as original script
$headers = @{
'Authorization' = "BEARER $AccessToken" # Note: BEARER in uppercase
}
# Try with special query parameters
$queryParams = @(
"select=video",
"expand=video",
"format=mov"
)
foreach ($param in $queryParams) {
$tryUrl = "${videoEndpoint}?$param"
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
Write-Host "Calling OneDrive API for video..."
$WebRequest = Invoke-WebRequest -Method "GET" -Uri $videoUri -Header $headers -ErrorAction SilentlyContinue -OutFile $tmpFile -PassThru
Write-Host "WebRequest: Done Calling OneDrive API"
if ((Test-Path $tmpFile) -and (Get-Item $tmpFile).Length -gt 0) {
$fileName = ($WebRequest.Headers.'Content-Disposition'.Split('=',2)[-1]).Trim('"')
if ($fileName) {
Write-Host "Renaming $tmpFile to $fileName"
if (Test-Path $videoPath) {
Remove-Item $videoPath
}
}
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
Rename-Item -Path $tmpFile -NewName $fileName
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 {
Write-Host "Failed to get item metadata: $_" -ForegroundColor Red
catch {
Write-Host "Failed to download video component: $_" -ForegroundColor Red
Remove-Item $tmpFile -ErrorAction SilentlyContinue
}
} else {
Write-Host "Video file already exists: $videoPath" -ForegroundColor Yellow
return $true
}
}
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 {
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"
$redirectUri = "https://photos.onedrive.com/auth/login"
# Get token using device code flow
$deviceCode = Get-MgDeviceCode -ClientId $ClientId -Scopes $scopes
Write-Host "Please visit: $($deviceCode.VerificationUri)"
Write-Host "Enter code: $($deviceCode.UserCode)"
$token = Get-MgToken -DeviceCode $deviceCode -ErrorAction Stop
return $token.AccessToken
try {
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
$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"
$form = New-Object Windows.Forms.Form
$form.Text = "Authenticate to OneDrive"
$form.Size = New-Object Drawing.Size @(700,600)
$form.Width = 660
$form.Height = 775
$web = New-Object System.Windows.Forms.WebBrowser
$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
@ -279,13 +296,14 @@ if (!(Test-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) {
Write-Host "`nGetting OneDrive Photos token..."
$photosToken = Get-ODPhotosToken
Write-Host "`nQuerying OneDrive items..."
$items = Get-DriveItems -FolderPath $PathToScan
# print the items to the console
# $items | Format-List | Out-String | Write-Host
if ($items) {
# Get drive reference
@ -307,8 +325,8 @@ if (Connect-GraphWithDebug) {
try {
$result = Test-DownloadItem -ItemId $item.Id -SavePath $SaveTo -item $item
if ($result) {
# Try to get the video component
$hasVideo = Get-LivePhotoBundle -item $item -drive $drive
# Try to get the video component, passing all items and the photos token
$hasVideo = Get-LivePhotoBundle -item $item -drive $drive -AccessToken $photosToken.'AccessToken-OneDrive.ReadWrite'
if ($hasVideo) {
Write-Host "Successfully processed Live Photo bundle for: $($item.Name)" -ForegroundColor Green
} else {