Add self-hosted RustDesk bootstrap management
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
[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
|
||||
Reference in New Issue
Block a user