v2, use old api endpoint
This commit is contained in:
parent
5109e1ec3b
commit
c4fa4ae57f
|
|
@ -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,90 +171,47 @@ 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
|
|
||||||
if (-not $context) {
|
|
||||||
throw "No authentication context found"
|
|
||||||
}
|
|
||||||
|
|
||||||
$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"
|
|
||||||
|
|
||||||
# Try to get the video component using Graph API
|
|
||||||
$videoEndpoint = "$itemEndpoint/content"
|
|
||||||
$videoPath = Join-Path $SaveTo "$baseName.mov"
|
$videoPath = Join-Path $SaveTo "$baseName.mov"
|
||||||
|
$tmpFile = Join-Path $SaveTo "tmp-file.mov"
|
||||||
|
|
||||||
if (-not (Test-Path $videoPath)) {
|
if (-not (Test-Path $videoPath)) {
|
||||||
Write-Host "Attempting to download video component..."
|
Write-Host "Attempting to download video component..."
|
||||||
|
|
||||||
# Try different content types
|
# Use exactly the same endpoint and headers as original script
|
||||||
$videoHeaders = @{
|
$videoUri = "https://api.onedrive.com/v1.0/drive/items/$($item.Id)/content?format=video"
|
||||||
'Authorization' = "Bearer $token"
|
Write-Host "Using video endpoint: $videoUri"
|
||||||
'Accept' = 'video/quicktime'
|
|
||||||
'Prefer' = 'respond-async'
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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 {
|
try {
|
||||||
Invoke-MgGraphRequest -Uri $tryUrl -Headers $videoHeaders -Method GET -OutputFilePath $videoPath
|
# Use exact same headers as original script
|
||||||
if ((Test-Path $videoPath) -and (Get-Item $videoPath).Length -gt 0) {
|
$headers = @{
|
||||||
Write-Host "Successfully downloaded video component" -ForegroundColor Green
|
'Authorization' = "BEARER $AccessToken" # Note: BEARER in uppercase
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
Rename-Item -Path $tmpFile -NewName $fileName
|
||||||
return $true
|
return $true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Write-Host "Final attempt failed: $_" -ForegroundColor Red
|
Write-Host "Failed to download video component: $_" -ForegroundColor Red
|
||||||
Remove-Item $videoPath -ErrorAction SilentlyContinue
|
Remove-Item $tmpFile -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Video file already exists: $videoPath" -ForegroundColor Yellow
|
Write-Host "Video file already exists: $videoPath" -ForegroundColor Yellow
|
||||||
return $true
|
return $true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
|
||||||
Write-Host "Failed to get item metadata: $_" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue