Files
SGU-CredentialProvider/scripts/Get-SguRustDeskDevice.ps1
T

72 lines
4.1 KiB
PowerShell

[CmdletBinding()]
param(
[string]$ComputerName,
[switch]$RevealPassword,
[string]$InventoryRoot = "$env:ProgramData\SGU\RustDesk\Devices"
)
$ErrorActionPreference = 'Stop'
function Assert-Administrator {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
throw 'Only a local administrator can read the RustDesk device inventory.'
}
}
function Initialize-DataProtection {
if (-not ('SguRustDeskDataProtection' -as [type])) {
Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
public static class SguRustDeskDataProtection {
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DataBlob { public int cbData; public IntPtr pbData; }
[DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool CryptProtectData(ref DataBlob input, string description, IntPtr entropy, IntPtr reserved, IntPtr prompt, int flags, out DataBlob output);
[DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool CryptUnprotectData(ref DataBlob input, IntPtr description, IntPtr entropy, IntPtr reserved, IntPtr prompt, int flags, out DataBlob output);
[DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr LocalFree(IntPtr memory);
private const int CryptProtectLocalMachine = 0x4;
private static DataBlob ToBlob(byte[] value) { var blob = new DataBlob { cbData = value.Length, pbData = IntPtr.Zero }; if (value.Length > 0) { blob.pbData = Marshal.AllocHGlobal(value.Length); Marshal.Copy(value, 0, blob.pbData, value.Length); } return blob; }
private static byte[] FromBlob(DataBlob blob) { var value = new byte[blob.cbData]; if (blob.cbData > 0) Marshal.Copy(blob.pbData, value, 0, blob.cbData); return value; }
public static byte[] Protect(byte[] value) { var input = ToBlob(value); var output = new DataBlob(); try { if (!CryptProtectData(ref input, null, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, CryptProtectLocalMachine, out output)) throw new Win32Exception(Marshal.GetLastWin32Error()); return FromBlob(output); } finally { if (input.pbData != IntPtr.Zero) Marshal.FreeHGlobal(input.pbData); if (output.pbData != IntPtr.Zero) LocalFree(output.pbData); } }
public static byte[] Unprotect(byte[] value) { var input = ToBlob(value); var output = new DataBlob(); try { if (!CryptUnprotectData(ref input, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, out output)) throw new Win32Exception(Marshal.GetLastWin32Error()); return FromBlob(output); } finally { if (input.pbData != IntPtr.Zero) Marshal.FreeHGlobal(input.pbData); if (output.pbData != IntPtr.Zero) LocalFree(output.pbData); } }
}
'@ -ErrorAction Stop
}
}
Assert-Administrator
Initialize-DataProtection
if (-not (Test-Path -LiteralPath $InventoryRoot -PathType Container)) {
return @()
}
$entries = @(Get-ChildItem -LiteralPath $InventoryRoot -Filter '*.json' -File |
ForEach-Object {
$metadata = Get-Content -LiteralPath $_.FullName -Raw | ConvertFrom-Json
if ($ComputerName -and -not $metadata.ComputerName.Equals($ComputerName, [StringComparison]::OrdinalIgnoreCase)) {
return
}
$result = [ordered]@{
ComputerName = [string]$metadata.ComputerName
RustDeskId = [string]$metadata.RustDeskId
RegisteredAt = [datetime]$metadata.RegisteredAt
}
if ($RevealPassword) {
$secretPath = [string]$metadata.SecretPath
if (-not (Test-Path -LiteralPath $secretPath -PathType Leaf)) {
throw "The protected RustDesk credential for $($metadata.ComputerName) is missing."
}
$result.AccessPassword = [Text.Encoding]::UTF8.GetString(
[SguRustDeskDataProtection]::Unprotect(
[IO.File]::ReadAllBytes($secretPath)))
}
[pscustomobject]$result
})
$entries | Sort-Object ComputerName