param( [ValidateSet('Query','Apply','Restore')][string]$Action='Query', [string]$BackupPath='C:\ProgramData\VDI\single-display-20261103\before.xml' ) $ErrorActionPreference='Stop' # Run as the logged-in desktop user. Detach desktop outputs, never disable GPUs. Add-Type -ReferencedAssemblies System.Xml,System.Core,System -TypeDefinition @' using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Xml.Serialization; public static class VdiSingleDisplay { [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)] public struct Device { public int cb; [MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)] public string Name; [MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)] public string Description; public int Flags; [MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)] public string Id; [MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)] public string Key; } [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)] public struct Mode { [MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)] public string name; public short spec,driver,size,extra; public int fields,x,y,orientation,fixedOutput; public short color,duplex,yres,tt,collate; [MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)] public string form; public short logPixels; public int bpp,width,height,flags,hz,icmMethod,icmIntent,media,dither,reserved1,reserved2,panWidth,panHeight; } public class Record { public Device device; public Mode mode; public bool hasMode; } [DllImport("user32.dll",CharSet=CharSet.Unicode)] static extern bool EnumDisplayDevices(string name,uint index,ref Device device,uint flags); [DllImport("user32.dll",CharSet=CharSet.Unicode)] static extern bool EnumDisplaySettings(string name,int index,ref Mode mode); [DllImport("user32.dll",CharSet=CharSet.Unicode)] static extern int ChangeDisplaySettingsEx(string name,ref Mode mode,IntPtr hwnd,uint flags,IntPtr param); [DllImport("user32.dll",CharSet=CharSet.Unicode,EntryPoint="ChangeDisplaySettingsExW")] static extern int Commit(string name,IntPtr mode,IntPtr hwnd,uint flags,IntPtr param); public static Record[] Query() { var result=new List(); for(uint i=0;;i++) { Device d=new Device(); d.cb=Marshal.SizeOf(typeof(Device)); if(!EnumDisplayDevices(null,i,ref d,0)) return result.ToArray(); if((d.Flags&8)!=0) continue; Mode m=new Mode(); m.size=(short)Marshal.SizeOf(typeof(Mode)); bool ok=EnumDisplaySettings(d.Name,-1,ref m); result.Add(new Record {device=d,mode=m,hasMode=ok}); } } static void Check(int code,string operation) { if(code!=0) throw new InvalidOperationException(operation+" failed: "+code+" (no reboot will be requested)"); } public static string Target(Record[] records) { string found=null; foreach(var r in records) if((r.device.Flags&1)!=0 && r.device.Description.IndexOf("Virtual Display Driver",StringComparison.OrdinalIgnoreCase)>=0) { if(found!=null) throw new InvalidOperationException("Multiple active VDD outputs; refuse ambiguous selection"); if(!r.hasMode || r.mode.width<640 || r.mode.height<480) throw new InvalidOperationException("Invalid active VDD mode"); found=r.device.Name; } if(found==null) throw new InvalidOperationException("No active VDD; do not detach anything"); return found; } public static void Save(Record[] records,string path) { using(var stream=new FileStream(path,FileMode.CreateNew,FileAccess.Write)) new XmlSerializer(typeof(Record[])).Serialize(stream,records); } public static Record[] Load(string path) { using(var stream=File.OpenRead(path)) return (Record[])new XmlSerializer(typeof(Record[])).Deserialize(stream); } static void Stage(Record record,bool active,bool primary) { Mode m=record.mode; m.size=(short)Marshal.SizeOf(typeof(Mode)); m.extra=0; if(active) { if(!record.hasMode) throw new InvalidOperationException("Missing original mode"); m.fields=0x20|0x40000|0x80000|0x100000|0x400000; } else { m.width=m.height=0; m.fields=0x20|0x80000|0x100000; } Check(ChangeDisplaySettingsEx(record.device.Name,ref m,IntPtr.Zero,0x10000001u|(primary?0x10u:0u),IntPtr.Zero),"Stage "+record.device.Name); } public static void Apply(Record[] before,string keep) { foreach(var r0 in before) if(r0.device.Name==keep) { Record r=new Record {device=r0.device,mode=r0.mode,hasMode=r0.hasMode}; Mode m=r.mode; m.x=m.y=0; r.mode=m; Stage(r,true,true); } foreach(var r in before) if(r.device.Name!=keep && (r.device.Flags&1)!=0) Stage(r,false,false); Check(Commit(null,IntPtr.Zero,IntPtr.Zero,0,IntPtr.Zero),"Commit single display"); } public static void Restore(Record[] before) { Record[] now=Query(); foreach(var old in before) { bool matched=false; foreach(var r in now) if(r.device.Name==old.device.Name && r.device.Id==old.device.Id && r.device.Key==old.device.Key) matched=true; if(!matched) throw new InvalidOperationException("Display identity changed; refuse stale restore: "+old.device.Name); } foreach(var r in before) if((r.device.Flags&4)!=0) Stage(r,true,true); foreach(var r in before) if((r.device.Flags&4)==0) { bool currentlyActive=false; foreach(var current in now) if(current.device.Name==r.device.Name) currentlyActive=(current.device.Flags&1)!=0; if((r.device.Flags&1)!=0 || currentlyActive) Stage(r,(r.device.Flags&1)!=0,false); } Check(Commit(null,IntPtr.Zero,IntPtr.Zero,0,IntPtr.Zero),"Restore topology"); } } '@ function Report { @([VdiSingleDisplay]::Query() | ForEach-Object { @{device=$_.device.Name; description=$_.device.Description; active=(($_.device.Flags-band 1)-ne 0); primary=(($_.device.Flags-band 4)-ne 0); width=$_.mode.width; height=$_.mode.height; hz=$_.mode.hz; x=$_.mode.x; y=$_.mode.y} }) | ConvertTo-Json -Depth 4 -Compress } if($Action -eq 'Query') { Report; exit 0 } if($Action -eq 'Restore') { [VdiSingleDisplay]::Restore([VdiSingleDisplay]::Load($BackupPath)); Report; exit 0 } $before=[VdiSingleDisplay]::Query() $keep=[VdiSingleDisplay]::Target($before) $target=@($before | Where-Object {$_.device.Name -eq $keep})[0] if($target.mode.width -ne 2560 -or $target.mode.height -ne 1440 -or $target.mode.hz -ne 60 -or ($target.device.Flags-band 4)-eq 0) { throw 'Required existing 2560x1440@60 VDD primary is absent; nothing changed' } $active=@($before | Where-Object {($_.device.Flags-band 1)-ne 0}) if($active.Count -eq 1 -and ($active[0].device.Flags-band 4)-ne 0) { Report; exit 0 } New-Item -ItemType Directory -Force (Split-Path $BackupPath) | Out-Null [VdiSingleDisplay]::Save($before,$BackupPath) try { [VdiSingleDisplay]::Apply($before,$keep) Start-Sleep -Seconds 2 $actual=@([VdiSingleDisplay]::Query() | Where-Object {($_.device.Flags-band 1)-ne 0}) if($actual.Count -ne 1 -or $actual[0].device.Name -ne $keep -or ($actual[0].device.Flags-band 4)-eq 0) { throw 'Single VDD primary read-back failed' } $old=@($before | Where-Object {$_.device.Name -eq $keep})[0] if($actual[0].mode.width-ne $old.mode.width -or $actual[0].mode.height-ne $old.mode.height -or $actual[0].mode.hz-ne $old.mode.hz) { throw 'VDD mode changed unexpectedly' } Report } catch { $failure=$_ [VdiSingleDisplay]::Restore($before) throw $failure }