Esqueci a senha de um usuário padrão em um servidor interno. Felizmente, eu havia me conectado a este servidor anteriormente usando o RDCMan (Remote Desktop Connection Manager) em outro computador e salvado a senha. Após algum esforço, consegui recuperar a senha.
O script PowerShell que funcionou finalmente foi encontrado no seguinte endereço:
A descoberta deste link foi possível graças a um artigo no blog "The Garden" (cnblogs) que apresentou três soluções, incluindo uma com PowerShell.
https://www.cnblogs.com/Thorndike/p/15325079.html
Como a primeira tentaitva não funcionou, procurei por palavras-chave dentro do script e encontrei a solução (pesquisas no Baidu e Bing não produziram resultados úteis; desta vez, o Google foi o moter de busca eficaz).
O script final e funcional é:
param($RDGFilePath,
$EncryptedPassword,
$RDCManExecutablePath
)
# Se o caminho do executável do RDCMan não for fornecido, tenta encontrá-lo
if (-not $RDCManExecutablePath) {
$RDCManExecutablePath = (Get-ChildItem -Path @('C:\Program Files\Microsoft', 'C:\Program Files (x86)\Microsoft') -Filter "RDCMan.exe" -Recurse -ErrorAction SilentlyContinue)[0]
}
# Verifica se o RDCMan foi encontrado
if (-not $RDCManExecutablePath) {
Write-Error "O Remote Desktop Connection Manager (RDCMan) deve estar instalado. Se estiver instalado, use o parâmetro -RDCManExecutablePath para especificar o local do executável."
Exit
} else {
Write-Host "Carregando o assembly do RDCMan em: $($RDCManExecutablePath.FullName)"
try {
# Carrega o assembly do RDCMan
$Assembly = [Reflection.Assembly]::LoadFile($RDCManExecutablePath.FullName)
} catch {
Write-Host "Erro ao carregar o assembly: $($_.Exception.Message)"
Exit
}
try {
Import-Module $Assembly
} catch {
Write-Host "Erro ao importar o módulo: $($_.Exception.Message)"
exit
}
}
# Se um arquivo .rdg for fornecido, descriptografa as credenciais contidas nele
if ($RDGFilePath) {
Write-Host "Processando o arquivo RDG: $RDGFilePath"
[xml]$XmlContent = Get-Content $RDGFilePath
$CredentialNodes = $XmlContent.SelectNodes("//logonCredentials")
$DecryptedCredentials = @()
foreach ($node in $CredentialNodes) {
try {
# Cria uma instância das configurações de criptografia
$EncryptionSettings = New-Object -TypeName RdcMan.EncryptionSettings
# Descriptografa a senha
$Password = [RdcMan.Encryption]::DecryptString($node.password, $EncryptionSettings)
} catch {
Write-Host "Falha ao descriptografar uma senha: $($_.Exception.Message)"
continue # Pula para o próximo nó em caso de erro
}
# Adiciona as credenciais descriptografadas à lista, se a descriptografia foi bem-sucedida
if ($Password -and ($Password -notlike '*Failed to decrypt*')) {
$CredentialObject = New-Object PSObject
$CredentialObject | Add-Member -Type NoteProperty -Name "ProfileName" -Value $node.ProfileName -Force
$CredentialObject | Add-Member -Type NoteProperty -Name "UserName" -Value $node.username -Force
$CredentialObject | Add-Member -Type NoteProperty -Name "Password" -Value $Password -Force
$CredentialObject | Add-Member -Type NoteProperty -Name "Domain" -Value $node.domain -Force
$DecryptedCredentials += $CredentialObject
}
}
# Exibe as credenciais descriptografadas
if ($DecryptedCredentials) {
$DecryptedCredentials | Format-Table -AutoSize
} else {
Write-Host "Nenhuma credencial descriptografada encontrada no arquivo."
}
} elseif ($EncryptedPassword) {
# Se apenas uma senha criptografada for fornecida, descriptografa-a diretamente
$EncryptionSettings = New-Object -TypeName RdcMan.EncryptionSettings
$Password = [RdcMan.Encryption]::DecryptString($EncryptedPassword, $EncryptionSettings)
Write-Host "Senha descriptografada: $Password"
}
No meu caso, usei uma versão portátil do RDCMan, então precisei passar o caminho do executável como parâmetro:
.\MeuScriptDescriptografador.ps1 -RDGFilePath '.\MeuArquivo.rdg' -RDCManExecutablePath 'D:\PortableApps\RDCMan\RDCMan.exe'
Outra tentativa de script que fiz foi:
function Decrypt-RDCManCredentials ($FilePath) {
<#
.SYNOPSIS
Este script tenta descriptografar todas as senhas armazenadas em um arquivo de configuração do RDCMan.
.EXAMPLE
Decrypt-RDCManCredentials -FilePath "C:\Caminho\Para\SeuArquivo.rdg"
#>
if (-not $FilePath) {
# Se nenhum arquivo for especificado, tenta usar o arquivo de configurações padrão
$DefaultConfigPath = "$env:LOCALAPPDATA\microsoft\remote desktop connection manager\rdcman.settings"
if (Test-Path $DefaultConfigPath) {
[xml]$Config = Get-Content $DefaultConfigPath
$FilesToOpen = Select-Xml -Xml $Config -XPath "//FilesToOpen/*"
$FilesToOpen | ForEach-Object {
Write-Host "Processando arquivo: $($_.Node.InnerText)"
Decrypt-RDCManCredentials -FilePath $_.Node.InnerText
}
} else {
Write-Host "Arquivo de configurações padrão não encontrado. Por favor, especifique o caminho do arquivo .rdg."
}
} else {
Write-Host "Lendo o arquivo: $FilePath"
$FileContent = Get-Content $FilePath
[xml]$XmlData = $FileContent
# Tenta selecionar os nós de credenciais
$CredentialNodes = Select-Xml -Xml $XmlData -XPath "//logonCredentials"
# O caminho para a senha pode variar dependendo da versão do RDCMan
$CredentialNodes | ForEach-Object {
$Node = $_.Node
$EncryptedPassword = $null
$PasswordText = $null
# Tenta obter a senha do atributo 'password'
if ($Node.Password) {
$EncryptedPassword = $Node.Password
}
# Em algumas versões, a senha pode estar no texto do nó, dentro de um elemento específico
elseif ($Node.SelectSingleNode(".//password") -and $Node.SelectSingleNode(".//password").#text) {
$EncryptedPassword = $Node.SelectSingleNode(".//password").#text
}
if ($EncryptedPassword) {
$PasswordText = Decrypt-DPAPI $EncryptedPassword
$Output = "$($Node.Domain)\$($Node.Username) - Senha: $PasswordText"
if ($EncryptedPassword) { $Output += " (Hash: $EncryptedPassword)" }
Write-Output $Output
} else {
Write-Host "Não foi possível encontrar a senha para $($Node.Domain)\$($Node.Username)"
}
}
}
}
function Decrypt-DPAPI ($EncryptedString) {
# Carrega o assembly System.Security no runspace do PowerShell
Add-Type -assembly System.Security
$AsciiEncoding = [System.Text.Encoding]::ASCII
$UnicodeEncoding = [System.Text.Encoding]::UNICODE
# Tenta descriptografar a senha usando o escopo CurrentUser
try {
$EncryptedBytes = [System.Convert]::FromBase64String($EncryptedString)
$DecryptedBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($EncryptedBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
$DecodedPassword = $UnicodeEncoding.GetString($DecryptedBytes)
return $DecodedPassword
}
catch {
# Se falhar com CurrentUser, tenta com LocalMachine
try {
$EncryptedBytes = [System.Convert]::FromBase64String($EncryptedString)
$DecryptedBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($EncryptedBytes, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine)
$DecodedPassword = $UnicodeEncoding.GetString($DecryptedBytes)
return $DecodedPassword
}
catch {
# Retorna uma mensagem de erro se ambas as tentativas falharem
return "Falha ao descriptografar"
}
}
}
O script do Thorndkie (do cnblogs), com correções manuais após reconhecimento de texto:
# Copia o executável do RDCMan para um local temporário como DLL
Copy-Item 'C:\Program Files (x86)\Microsoft\Remote Desktop Connection Manager\RDCMan.exe' 'C:\windows\temp\RDCMan.dll'
# Importa o módulo a partir do arquivo copiado
Import-Module 'C:\windows\temp\RDCMan.dll'
# Cria uma instância das configurações de criptografia
$EncryptionSettings = New-Object -TypeName RdcMan.EncryptionSettings
# Lê as senhas criptografadas de um arquivo (uma por linha)
$EncryptedLines = Get-Content RDCManpass.txt
# Descriptografa cada linha
foreach ($line in $EncryptedLines) {
$EncryptedPassword = $line
[RdcMan.Encryption]::DecryptString($EncryptedPassword, $EncryptionSettings)
}
Executar o script diretamente no Windows 10 pode gerar erros. A solução encontrada foi:
https://blog.csdn.net/qq_15585305/article/details/131436046
Para passagem de parâmetros em scripts PowerShell, consultei este artigo: