OneDrive Photos no Windows: remoção controlada e governança de armazenamento em escala

O Microsoft OneDrive passou a distribuir, junto do cliente de sincronização, um aplicativo separado de fotos — o OneDrive Photos (OneDrive.App.exe). Em ambientes gerenciados, ele chega sem pedir licença: aparece no Menu Iniciar, cria atalhos, adiciona mais um processo em segundo plano e gera chamados de suporte de usuários que não sabem o que é aquilo. Este artigo trata o problema em dois níveis que costumam ser analisados separadamente, mas que pertencem à mesma disciplina de governança de dados (data governance): como remover o aplicativo de forma controlada e reversível em todo o parque, e como enxergar e governar o consumo de armazenamento do OneDrive por usuário dentro do tenant.

O foco aqui é operacional e defensável em auditoria. Todo comando e comportamento citado está ancorado exclusivamente na documentação oficial da Microsoft (Microsoft Learn), referenciada ao final.

Pesquisando sobre esse tema me deparei com muitos blogs informando coisas erradas e fora da documentação, sempre que ler um blog busque na documentação oficial e compare, não acredite se antes verificar. neste BLOG TUDO É ANCORADO NA DOCUMENTAÇÕ OFICIAL.

O que é o OneDrive Photos (OneDrive.App.exe)

O OneDrive Photos é um aplicativo de visualização e organização de imagens que a Microsoft passou a instalar como parte do pacote do OneDrive, e não como um produto avulso. Tecnicamente, o ponto central é a separação de executáveis:

ComponenteExecutávelPapel
Cliente de sincronizaçãoOneDrive.exeSincroniza arquivos entre o dispositivo e o OneDrive/SharePoint. É o núcleo funcional.
Aplicativo de fotosOneDrive.App.exeVisualizador/galeria de imagens. Componente adicional, orientado a experiência de consumidor.

Os dois binários residem sob o mesmo diretório de instalação:

none

# Instalação machine-wide (por máquina)
C:\Program Files\Microsoft OneDrive\OneDrive.App.exe
# Instalação per-user (por usuário)
%LocalAppData%\Microsoft\OneDrive\OneDrive.App.exe

O ponto que gera atrito em ambientes corporativos é duplo. Primeiro, o OneDrive Photos é fortemente orientado a conta pessoal da Microsoft (personal Microsoft account) — o que o torna inútil em muitas estações Windows Enterprise ingressadas apenas com identidade corporativa (Microsoft Entra). Segundo, ele acompanha o ciclo de atualização do OneDrive: sempre que o cliente é atualizado, o atalho tende a reaparecer. Qualquer remoção que não seja recorrente é temporária por natureza.

2. Por que isto é governança, e não apenas “remover um atalho”

É tentador tratar o OneDrive Photos como incômodo cosmético. Ele não é. Para o administrador, o aparecimento não anunciado de um componente é um evento de governança porque toca três eixos:

Superfície e higiene do endpoint. Cada aplicativo adicional é mais um processo, mais um alvo de sincronização e mais um item que o service desk precisa explicar. Padronização de imagem (image standardization) existe justamente para que o que está na máquina seja intencional.

Fronteira de dados pessoais vs. corporativos. Um visualizador de fotos orientado a conta pessoal, rodando em hardware corporativo, embaralha a fronteira entre dados pessoais e dados da organização — exatamente a fronteira que uma política de governança de dados existe para manter nítida.

Reversibilidade e auditoria. A pergunta certa não é “como faço isso sumir”, e sim “como removo de forma reversível, sem colateral na sincronização, com registro de auditoria e cobertura de todo o parque”. É esta a diferença entre um comando avulso e um controle.

E há um segundo movimento, quase sempre esquecido quando se fala do OneDrive Photos: se o assunto é o OneDrive no ambiente, o consumo de armazenamento por usuário é a parte da governança que realmente move risco e custo. Voltaremos a isso na seção 8.

3. Anatomia técnica: onde o atalho vive e o que remover

O que incomoda o usuário final não é o binário — é o atalho (.lnk) no Menu Iniciar e, em alguns cenários, na Área de Trabalho. Os atalhos podem existir tanto em locais all-users (machine-wide) quanto por perfil de usuário:

EscopoLocalCaminho
All-usersMenu IniciarC:\ProgramData\Microsoft\Windows\Start Menu\Programs
All-usersÁrea de TrabalhoC:\Users\Public\Desktop
Per-userMenu Iniciar%AppData%\Microsoft\Windows\Start Menu\Programs
Per-userÁrea de Trabalho%UserProfile%\Desktop

A implicação prática é importante: um script que só olha o perfil do usuário que está executando não cobre um dispositivo multiusuário. Para tratar “todo o ambiente”, a detecção precisa iterar todos os perfis presentes na máquina — o que exige execução no contexto SYSTEM.

Um segundo cuidado de engenharia: identificar o atalho pelo alvo resolvido (TargetPath), e não pelo nome do arquivo. Nomes de atalho variam por idioma e por versão; o alvo, não — ele sempre aponta para OneDrive.App.exe. Resolver o TargetPath elimina falsos positivos e falsos negativos de uma vez.

4. Decisão de arquitetura: remover o atalho, nunca o executável

A tentação de excluir OneDrive.App.exe diretamente deve ser resistida. O binário do OneDrive Photos é entregue e mantido pelo mesmo mecanismo de atualização do cliente de sincronização; apagá-lo pode desestabilizar o próprio OneDrive e será revertido na atualização seguinte. A abordagem correta e de menor risco é remover apenas os atalhos:

  • A sincronização de arquivos (OneDrive.exe) permanece intacta e disponível aos usuários.
  • Nenhuma modificação é feita em arquivos de programa protegidos.
  • A operação é idempotente e segura para reexecução.
  • O único efeito colateral é que a atualização do OneDrive recria os atalhos — problema resolvido pela recorrência da distribuição (seção 5).

Mito a corrigir: “Para remover o OneDrive Photos, basta apagar o executável.” Apagar OneDrive.App.exe tende a causar instabilidade no cliente OneDrive e é desfeito na próxima atualização. A remoção suportada e sem colateral na sincronização é a dos atalhos, aplicada de forma recorrente. Se a intenção for eliminar o Photos por completo em uma máquina que não usa OneDrive, o caminho é desinstalar o próprio OneDrive — o Photos sai junto.

5. Distribuição via Intune Remediations em todo o ambiente

O par detecção + remediação foi desenhado para o recurso Remediations do Microsoft Intune (renomeado a partir de Proactive Remediations; hoje em Dispositivos > Gerenciar dispositivos > Scripts e correções). O modelo é exatamente o que precisamos: um script de detecção decide, um script de remediação corrige apenas quando necessário, e tudo roda de forma recorrente e monitorável.

Regras do recurso que moldam o design dos scripts (todas da documentação oficial):

  • A remediação só executa se a detecção terminar com exit 1. Qualquer outro código — inclusive saída vazia — é interpretado como “sem problema”.
  • Os scripts devem estar em UTF-8 (sem BOM, se a verificação de assinatura estiver ativa).
  • A saída máxima capturada é de 2.048 caracteres — por isso os scripts reportam resumos curtos.
  • Scripts sem verificação de assinatura rodam com política de execução Bypass.
  • Não inclua comandos de reinicialização, senhas ou dados pessoais nos scripts.

Configuração recomendada do pacote:

OpçãoValor recomendadoRacional
Executar com credenciais do usuário conectadoNão (SYSTEM)Necessário para varrer todos os perfis e locais all-users.
Forçar verificação de assinaturaNão (ou Sim, se você assina os scripts)Assinar é a prática mais robusta; sem assinatura, roda em Bypass.
Executar em PowerShell de 64 bitsNãoNão há dependência de 64 bits nestes scripts.
AgendamentoDiárioO atalho reaparece a cada atualização do OneDrive; a recorrência reaplica a correção.

Como o cliente recupera a política de Remediations a cada ~8 horas e reexecuta scripts recorrentes a cada 24 horas, um agendamento diário mantém o ambiente convergente sem custo relevante de desempenho. Para atribuição, use grupos de dispositivos (não misture grupos de usuário e de dispositivo em include/exclude).

6. Script de detecção reformulado

O script de detecção monta dinamicamente a lista de raízes de busca (all-users + todos os perfis de usuário), enumera .lnk e confirma cada candidato pelo TargetPath. Ele emite exit 1 quando encontra ao menos um atalho do OneDrive Photos e exit 0 caso contrário.

powershell

[CmdletBinding()]
param(
[string] $TargetExecutable = 'OneDrive.App.exe'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Get-ShortcutSearchRoot {
$roots = [System.Collections.Generic.List[string]]::new()
if ($env:ProgramData) {
$roots.Add((Join-Path $env:ProgramData 'Microsoft\Windows\Start Menu\Programs'))
}
$roots.Add((Join-Path $env:PUBLIC 'Desktop'))
$usersPath = Join-Path $env:SystemDrive 'Users'
if (Test-Path -LiteralPath $usersPath) {
$skip = @('Public', 'Default', 'Default User', 'All Users', 'DefaultAppPool')
Get-ChildItem -LiteralPath $usersPath -Directory -Force -ErrorAction SilentlyContinue |
Where-Object { $skip -notcontains $_.Name } |
ForEach-Object {
$roots.Add((Join-Path $_.FullName 'AppData\Roaming\Microsoft\Windows\Start Menu\Programs'))
$roots.Add((Join-Path $_.FullName 'Desktop'))
}
}
$roots | Where-Object { $_ -and (Test-Path -LiteralPath $_) } | Select-Object -Unique
}
function Find-PhotosShortcut {
param(
[Parameter(Mandatory)] [string[]] $SearchRoot,
[Parameter(Mandatory)] [string] $Executable
)
$shell = New-Object -ComObject WScript.Shell
$hits = [System.Collections.Generic.List[string]]::new()
try {
foreach ($root in $SearchRoot) {
$links = Get-ChildItem -LiteralPath $root -Filter '*.lnk' -File -Recurse -Force -ErrorAction SilentlyContinue
foreach ($link in $links) {
try { $target = $shell.CreateShortcut($link.FullName).TargetPath } catch { continue }
if ($target -and $target.TrimEnd('"').EndsWith($Executable, [System.StringComparison]::OrdinalIgnoreCase)) {
$hits.Add($link.FullName)
}
}
}
}
finally {
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($shell)
}
$hits
}
try {
$roots = @(Get-ShortcutSearchRoot)
if ($roots.Count -eq 0) { Write-Output 'Compliant: nenhuma raiz de atalho encontrada.'; exit 0 }
$found = @(Find-PhotosShortcut -SearchRoot $roots -Executable $TargetExecutable)
if ($found.Count -gt 0) {
Write-Output ("NonCompliant: {0} atalho(s) do OneDrive Photos detectado(s)." -f $found.Count)
exit 1
}
Write-Output 'Compliant: nenhum atalho do OneDrive Photos detectado.'
exit 0
}
catch {
Write-Output ("DetectionError: {0}" -f $_.Exception.Message)
exit 0
}

Validação antes de produção: teste os scripts em um anel piloto (pilot ring) antes de distribuir amplamente. Ajuste a lista de perfis a ignorar conforme as convenções do seu ambiente.

Script de remediação reformulado

A remediação reaproveita a mesma lógica de descoberta, mas remove cada atalho confirmado e grava um log de auditoria local. É idempotente e retorna exit 0 em sucesso.

powershell

[CmdletBinding(SupportsShouldProcess)]
param(
[string] $TargetExecutable = 'OneDrive.App.exe',
[string] $LogPath = (Join-Path $env:ProgramData 'CorpIT\Logs\OneDrivePhotos-Remediation.log')
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Write-AuditLog {
param([string] $Message, [string] $Level = 'INFO')
$line = '{0:yyyy-MM-dd HH:mm:ss} [{1}] {2}' -f (Get-Date), $Level, $Message
try {
$dir = Split-Path -Path $LogPath -Parent
if (-not (Test-Path -LiteralPath $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
Add-Content -LiteralPath $LogPath -Value $line -Encoding UTF8
} catch { }
}
function Get-ShortcutSearchRoot {
$roots = [System.Collections.Generic.List[string]]::new()
if ($env:ProgramData) { $roots.Add((Join-Path $env:ProgramData 'Microsoft\Windows\Start Menu\Programs')) }
$roots.Add((Join-Path $env:PUBLIC 'Desktop'))
$usersPath = Join-Path $env:SystemDrive 'Users'
if (Test-Path -LiteralPath $usersPath) {
$skip = @('Public', 'Default', 'Default User', 'All Users', 'DefaultAppPool')
Get-ChildItem -LiteralPath $usersPath -Directory -Force -ErrorAction SilentlyContinue |
Where-Object { $skip -notcontains $_.Name } |
ForEach-Object {
$roots.Add((Join-Path $_.FullName 'AppData\Roaming\Microsoft\Windows\Start Menu\Programs'))
$roots.Add((Join-Path $_.FullName 'Desktop'))
}
}
$roots | Where-Object { $_ -and (Test-Path -LiteralPath $_) } | Select-Object -Unique
}
try {
$shell = New-Object -ComObject WScript.Shell
$removed = 0; $failed = 0
try {
foreach ($root in @(Get-ShortcutSearchRoot)) {
$links = Get-ChildItem -LiteralPath $root -Filter '*.lnk' -File -Recurse -Force -ErrorAction SilentlyContinue
foreach ($link in $links) {
try { $target = $shell.CreateShortcut($link.FullName).TargetPath } catch { continue }
if ($target -and $target.TrimEnd('"').EndsWith($TargetExecutable, [System.StringComparison]::OrdinalIgnoreCase)) {
if ($PSCmdlet.ShouldProcess($link.FullName, 'Remove shortcut')) {
try {
Remove-Item -LiteralPath $link.FullName -Force -ErrorAction Stop
$removed++; Write-AuditLog -Message ("Removido: {0}" -f $link.FullName)
} catch {
$failed++; Write-AuditLog -Level 'WARN' -Message ("Falha ao remover {0}: {1}" -f $link.FullName, $_.Exception.Message)
}
}
}
}
}
}
finally { [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($shell) }
if ($failed -gt 0) { Write-Output ("Remediation parcial: {0} removido(s), {1} falha(s)." -f $removed, $failed); exit 1 }
Write-Output ("Remediation concluida: {0} atalho(s) removido(s)." -f $removed)
exit 0
}
catch {
Write-AuditLog -Level 'ERROR' -Message $_.Exception.Message
Write-Output ("RemediationError: {0}" -f $_.Exception.Message)
exit 1
}

O SupportsShouldProcess permite ensaiar a remoção com -WhatIf fora do Intune, e o log em %ProgramData%\CorpIT\Logs dá rastreabilidade por dispositivo — evidência útil quando alguém perguntar “o que a TI removeu daquela máquina e quando”.

Governança de armazenamento: análise do OneDrive por usuário

Aqui está a parte que transforma uma limpeza de atalho em governança de verdade. Se o OneDrive está no ambiente, a pergunta estratégica é: quem está consumindo quanto, contra qual quota, e há espaço sendo ocupado por contas que não deveriam mais existir?

A fonte oficial e escalável para isso é o relatório getOneDriveUsageAccountDetail do Microsoft Graph, exposto no PowerShell pelo cmdlet Get-MgReportOneDriveUsageAccountDetail. Ele entrega, por conta, o esquema abaixo (colunas do CSV oficial):

ColunaUso em governança
Owner Principal Name / Owner Display NameIdentificação da conta.
Storage Used (Byte)Consumo real — numerador do percentual de quota.
Storage Allocated (Byte)Quota atribuída — denominador.
File Count / Active File CountVolume e atividade — sinaliza contas dormentes com muito dado.
Last Activity DateIdade da última atividade — insumo para retenção/arquivamento.
Is DeletedConta já removida cujo OneDrive ainda ocupa espaço.

O script abaixo consome esse relatório, calcula o percentual de quota por usuário, classifica cada conta em faixas de risco (Saudável / Atenção / Crítico) e, opcionalmente, enriquece cada linha com o status de conta habilitada e licenciada — permitindo separar consumo legítimo de contas órfãs (orphaned accounts).

powershell

[CmdletBinding()]
param(
[ValidateSet('D7','D30','D90','D180')] [string] $Period = 'D7',
[ValidateRange(1,100)] [int] $WarnThreshold = 80,
[ValidateRange(1,100)] [int] $CriticalThreshold = 90,
[string] $OutputPath = ".\OneDrive-Storage-Inventory_$(Get-Date -Format 'yyyyMMdd').csv",
[switch] $IncludeLicenseStatus
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Import-Module Microsoft.Graph.Reports -ErrorAction Stop
$scopes = @('Reports.Read.All')
if ($IncludeLicenseStatus) { Import-Module Microsoft.Graph.Users -ErrorAction Stop; $scopes += 'User.Read.All' }
if (-not (Get-MgContext -ErrorAction SilentlyContinue)) { Connect-MgGraph -Scopes $scopes -NoWelcome }
$tempCsv = Join-Path ([System.IO.Path]::GetTempPath()) ("od_usage_{0}.csv" -f ([guid]::NewGuid()))
Get-MgReportOneDriveUsageAccountDetail -Period $Period -OutFile $tempCsv
$raw = Import-Csv -LiteralPath $tempCsv
Remove-Item -LiteralPath $tempCsv -Force -ErrorAction SilentlyContinue
$licenseCache = @{}
if ($IncludeLicenseStatus) {
Get-MgUser -All -Property 'UserPrincipalName','AccountEnabled','AssignedLicenses' -ErrorAction SilentlyContinue |
ForEach-Object {
$licenseCache[$_.UserPrincipalName.ToLowerInvariant()] = [pscustomobject]@{
AccountEnabled = $_.AccountEnabled
HasLicense = ($_.AssignedLicenses.Count -gt 0)
}
}
}
$report = foreach ($row in $raw) {
$usedBytes = $row.'Storage Used (Byte)' -as [double]
$allocBytes = $row.'Storage Allocated (Byte)' -as [double]
$percent = if ($allocBytes -gt 0) { [math]::Round(($usedBytes / $allocBytes) * 100, 2) } else { 0 }
$tier = if ($percent -ge $CriticalThreshold) { 'Critico' }
elseif ($percent -ge $WarnThreshold) { 'Atencao' } else { 'Saudavel' }
$enabled = $null; $licensed = $null
if ($IncludeLicenseStatus -and $row.'Owner Principal Name') {
$entry = $licenseCache[$row.'Owner Principal Name'.ToLowerInvariant()]
if ($entry) { $enabled = $entry.AccountEnabled; $licensed = $entry.HasLicense }
}
[pscustomobject]@{
OwnerPrincipal = $row.'Owner Principal Name'
LastActivityDate = $row.'Last Activity Date'
FileCount = $row.'File Count' -as [int]
UsedGB = [math]::Round($usedBytes / 1GB, 2)
AllocatedGB = [math]::Round($allocBytes / 1GB, 2)
QuotaUsedPercent = $percent
RiskTier = $tier
AccountEnabled = $enabled
HasLicense = $licensed
IsDeleted = $row.'Is Deleted'
}
}
$report | Sort-Object QuotaUsedPercent -Descending |
Export-Csv -LiteralPath $OutputPath -NoTypeInformation -Encoding UTF8
Write-Host "Inventario gerado: $OutputPath" -ForegroundColor Green

Precisão de permissões: o relatório exige Reports.Read.All (delegada ou de aplicativo); o enriquecimento por licença adiciona User.Read.All. Para permissões delegadas, o tenant deve conceder ao usuário uma função administrativa apropriada do Entra para ler relatórios de uso do Microsoft 365. Valide contra as políticas da sua organização antes de rodar em produção.

Uma observação de conformidade que vale registrar: por padrão, os relatórios de uso do Microsoft 365 podem exibir nomes de usuário ofuscados (concealed/anonymized) conforme a configuração de privacidade do centro de administração. Se o seu inventário precisa dos UPNs reais, essa configuração precisa permitir a identificação — decisão que deve passar pela sua área de privacidade, não ser assumida silenciosamente pelo script.

Agindo sobre o consumo: quotas e contas órfãs

Inventário sem ação é relatório. Com o CSV em mãos, dois controles nativos fecham o ciclo:

Quota padrão do tenant e por usuário. O padrão de quota do OneDrive é definido no nível do tenant e pode ser ajustado por usuário. Via SharePoint Online Management Shell:

powershell

# Quota padrão do tenant (valor em MB). Ex.: 1 TB = 1048576, 5 TB = 5242880
Set-SPOTenant -OneDriveStorageQuota 1048576
# Quota de um usuário específico (site do OneDrive), com nível de aviso
Set-SPOSite -Identity "https://contoso-my.sharepoint.com/personal/usuario_contoso_com" `
-StorageQuota 2097152 -StorageQuotaWarningLevel 1887436

Vale lembrar da regra oficial: se você definir uma quota acima do que a licença do usuário permite, o valor é arredondado para baixo até o máximo licenciado. Não há como “burlar” o teto de licença via quota.

Contas órfãs que ainda ocupam espaço. As linhas do inventário com IsDeleted = True, ou com AccountEnabled = False/HasLicense = False (quando você usa -IncludeLicenseStatus), são candidatas a retenção/arquivamento e liberação de espaço. Antes de qualquer exclusão, verifique se há retenção (retention) ou bloqueio legal (legal hold) do Microsoft Purview sobre o conteúdo — a exclusão de uma conta não apaga dados sob hold, e agir sem checar isso é como remover o executável do Photos: parece resolver, mas cria um problema maior depois.

Correção de mitos

“Se o OneDrive está desabilitado para o usuário, o Photos não é instalado.” O OneDrive Photos acompanha a instalação do cliente OneDrive no dispositivo, não o estado de uso da conta. Mesmo com pouquíssimos usuários ativos no OneDrive, o Photos pode aparecer onde o cliente estiver instalado. Se o dispositivo não usa OneDrive, a via limpa é desinstalar o cliente — o Photos sai junto.

“Removi o atalho uma vez, está resolvido.” A atualização do OneDrive recria os atalhos. Sem uma distribuição recorrente (Intune Remediations em agendamento diário), a remoção regride na próxima atualização.

“Governança do OneDrive é sobre o app de fotos.” O app é higiene de endpoint. Governança do OneDrive, no sentido que move risco e custo, é sobre quem armazena o quê, contra qual quota, e o que fazer com contas órfãs — a análise da seção 8.

Opinião do Arquiteto

O OneDrive Photos é sintoma de um padrão recorrente: componentes voltados ao consumidor chegam ao endpoint corporativo pela porta dos fundos das atualizações. A resposta madura não é caçar cada atalho manualmente, e sim ter um mecanismo padrão de convergência — detecção + remediação recorrente, no contexto certo, com log de auditoria — que trate qualquer reaparecimento como rotina, não como incidente.

Mas o ponto que eu deixaria gravado é este: quando o OneDrive Photos aparece, ele é um bom gatilho para uma pergunta maior que quase nunca é feita no calor do chamado — “nós realmente sabemos como o armazenamento do OneDrive está distribuído no nosso tenant?”. Remover o atalho leva minutos. Descobrir que 8% das contas consomem 60% da quota, ou que há terabytes presos em contas desabilitadas, muda decisões de licenciamento, de retenção e de custo. O incômodo cosmético é a deixa; a governança de armazenamento é o valor.

Referências oficiais (Microsoft Learn)


Todo o conteúdo deste blog é gratuito e sempre será. Se este material te ajudou, compartilhe com quem administra Microsoft 365.

Aviso técnico: os scripts foram desenhados para os cenários descritos e devem ser validados em um anel piloto e contra as políticas da sua organização antes do uso em produção. Teste em ambiente controlado antes de distribuir em escala.


Deixe uma resposta