Skip to content

Commit a64ac93

Browse files
committed
Merge remote-tracking branch 'origin/dev-master'
2 parents f5087d6 + f1efc3a commit a64ac93

6 files changed

Lines changed: 11 additions & 185 deletions

File tree

Community Scripts/silent-install.ps1

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
param(
44
# Latest stable version of NefCon installer
55
[Parameter(Mandatory=$false)]
6-
[string]$NefConURL = "https://github.com/nefarius/nefcon/releases/download/v1.14.0/nefcon_v1.14.0.zip",
6+
[string]$NefConURL = "https://github.com/nefarius/nefcon/releases/download/v1.17.40/nefcon_v1.17.40.zip",
77

88
# Latest stable version of VDD driver only
99
[Parameter(Mandatory=$false)]
@@ -14,38 +14,19 @@ param(
1414
$tempDir = $PSScriptRoot;
1515
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null;
1616

17-
# nefcon not enable disable command,so...we keep this
18-
# Define path to devcon executable
19-
$devconExe = Join-Path $tempDir "devcon.exe";
20-
# Download and run DevCon Installer
21-
if (-not (Test-Path $devconExe))
22-
{
23-
$devconPath = Join-Path $tempDir "Devcon.Installer.exe";
24-
if (-not (Test-Path $devconPath))
25-
{
26-
Write-Host "Downloading DevCon..." -ForegroundColor Cyan;
27-
Invoke-WebRequest -Uri "https://github.com/Drawbackz/DevCon-Installer/releases/download/1.4-rc/Devcon.Installer.exe" -OutFile $devconPath;
28-
}
29-
Write-Host "Installing DevCon..." -ForegroundColor Cyan;
30-
Start-Process -FilePath $devconPath -ArgumentList "install -hash $DevconHash -update -dir `"$tempDir`"" -Wait -NoNewWindow;
31-
Write-Host "Installing DevCon Completed..." -ForegroundColor Cyan;
32-
}
33-
3417
# Define path to nefcon executable
3518
$NefConExe = Join-Path $tempDir "x64\nefconc.exe";
3619
# Download and run DevCon Installer
3720
if (-not (Test-Path $NefConExe))
3821
{
3922
$NefConZipPath = Join-Path $tempDir "nefcon.zip";
40-
# $devconPath = Join-Path $tempDir "Devcon.Installer.exe";
4123
if (-not (Test-Path $NefConZipPath))
4224
{
4325
Write-Host "Downloading NefCon..." -ForegroundColor Cyan;
4426
Invoke-WebRequest -Uri $NefConURL -OutFile $NefConZipPath -UseBasicParsing -ErrorAction Stop;
4527
}
4628
Write-Host "extracting NefCon..." -ForegroundColor Cyan;
4729
Expand-Archive -Path $NefConZipPath -DestinationPath $tempDir -Force -ErrorAction Stop;
48-
# Start-Process -FilePath $devconPath -ArgumentList "install -hash $DevconHash -update -dir `"$tempDir`"" -Wait -NoNewWindow;
4930
Write-Host "extracting NefCon Completed..." -ForegroundColor Cyan;
5031
}
5132

Community Scripts/silent-uninstall.ps1

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ param(
77
# Create temp directory
88
$tempDir = $PSScriptRoot;
99
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null;
10-
# Define path to devcon executable
11-
$devconExe = Join-Path $tempDir "devcon.exe";
12-
& $devconExe disable "Root\MttVDD";
13-
Start-Sleep -Seconds 2;
14-
& $devconExe remove "Root\MttVDD";
10+
$NefConExe = Join-Path $tempDir "x64\nefconc.exe";
11+
Push-Location $tempDir;
12+
& $NefConExe remove "Root\MttVDD";
13+
& $NefConExe --uninstall-driver --inf-path .\VirtualDisplayDriver\VirtualDisplayDriver.inf;
1514
Write-Host "Driver installation removed." -ForegroundColor Green;
16-
15+
Pop-Location;
1716

Community Scripts/virtual-driver-manager.ps1

Lines changed: 5 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
<#
22
.SYNOPSIS
33
A comprehensive script to manage the Virtual Display Driver.
4-
It can install, uninstall, enable, disable, toggle, and check the status of the driver.
4+
It can enable, disable, toggle, and check the status of the driver.
55
66
.DESCRIPTION
77
This script handles the full lifecycle of the Virtual Display Driver.
88
- If no action is specified, it interactively prompts the user to select one.
9-
- For install/uninstall, it automatically resolves the correct version of Microsoft's DevCon utility using a nearest-build matching algorithm for maximum compatibility.
109
- For enable/disable/toggle/status, it uses fast, built-in PowerShell commands.
1110
- It requires Administrator privileges and will self-elevate if needed by re-launching in a new window.
1211
- All temporary files are automatically cleaned up unless in Verbose mode for diagnostics.
1312
1413
.PARAMETER Action
1514
Specifies the operation to perform. If omitted, the script will prompt for a selection.
1615
17-
.PARAMETER DriverVersion
18-
Used only with the 'install' action to specify a version of the Virtual Display Driver, otherwise defaults to 'latest'.
1916
2017
.PARAMETER Json
2118
If present, all output will be in JSON format for easy parsing by other programs.
@@ -32,12 +29,6 @@ If present, prints detailed diagnostic information and prevents the temporary fo
3229
# Run without an action to get an interactive menu. The window will pause when finished.
3330
.\virtual-driver-manager.ps1
3431
35-
# Install the driver and pause for review afterwards (default behavior).
36-
.\virtual-driver-manager.ps1 -Action install
37-
38-
# Uninstall the driver and close the window automatically.
39-
.\virtual-driver-manager.ps1 -Action uninstall -Silent
40-
4132
.EXAMPLE
4233
# --- USAGE FROM CMD.EXE OR ANOTHER PROCESS ---
4334
@@ -50,7 +41,7 @@ powershell.exe -ExecutionPolicy Bypass -File .\virtual-driver-manager.ps1 -Actio
5041
[CmdletBinding(SupportsShouldProcess = $true)]
5142
param(
5243
[Parameter(Mandatory = $false)]
53-
[ValidateSet('install', 'uninstall', 'enable', 'disable', 'toggle', 'status')]
44+
[ValidateSet('enable', 'disable', 'toggle', 'status')]
5445
[string]$Action,
5546

5647
[Parameter(Mandatory = $false)]
@@ -104,7 +95,7 @@ if (-not $PSBoundParameters.ContainsKey('Action')) {
10495
exit 1
10596
}
10697

107-
$options = 'install', 'uninstall', 'enable', 'disable', 'toggle', 'status'
98+
$options = 'enable', 'disable', 'toggle', 'status'
10899
Write-Host "`nPlease select an action to perform:" -ForegroundColor Yellow
109100

110101
for ($i = 0; $i -lt $options.Length; $i++) {
@@ -162,10 +153,6 @@ if (-Not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdenti
162153
#----------------------------------------------------------------------
163154
# SECTION 4: SETUP AND GUARANTEED CLEANUP
164155
#----------------------------------------------------------------------
165-
# Create a unique temporary directory to avoid conflicts if the script is run multiple times concurrently.
166-
$tempDir = Join-Path $env:TEMP "VDD-Manager-$(Get-Random)"
167-
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
168-
Write-Verbose "Created temporary directory at $tempDir"
169156

170157
# Use a try/catch/finally block to ensure that no matter what happens (success or error),
171158
# the 'finally' block will ALWAYS run to clean up temporary files.
@@ -196,135 +183,7 @@ try {
196183
#----------------------------------------------------------------------
197184
# SECTION 6: MAIN ACTION LOGIC
198185
#----------------------------------------------------------------------
199-
if ($Action -in @('install', 'uninstall')) {
200-
201-
#--- 6a. Automatically Resolve DevCon Hash ---
202-
Write-Log -Message "Action '$Action' requires the DevCon utility. Determining correct version..."
203-
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
204-
$osBuild = [int]$osInfo.BuildNumber
205-
206-
$osMajorVersion = 'Server'
207-
if ($osInfo.Caption -match 'Windows 11') { $osMajorVersion = '11' }
208-
elseif ($osInfo.Caption -match 'Windows 10') { $osMajorVersion = '10' }
209-
210-
Write-Log -Message "Detected: Windows $osMajorVersion (Build $osBuild)"
211-
Write-Verbose "OS detection complete. Starting DevCon source matching."
212-
213-
# This map is the core of the matching logic. It translates the human-readable version names
214-
# from the devcon_sources.json file into their corresponding OS build numbers for comparison.
215-
$versionNameToBuildMap = @{
216-
"Windows 11 version 24H2" = 26100; "Windows 11 version 23H2" = 22631; "Windows 11 version 22H2" = 22621;
217-
"Windows 11 version 21H2" = 22000; "Windows Server 2022" = 20348; "Windows 10 version 2004" = 19041;
218-
"Windows 10 version 1903" = 18362; "Windows 10 version 1809" = 17763; "Windows Server 2019" = 17763
219-
}
220-
221-
$sourcesUrl = "https://raw.githubusercontent.com/Drawbackz/DevCon-Installer/refs/heads/master/devcon_sources.json"
222-
Write-Verbose "Fetching DevCon sources from $sourcesUrl"
223-
$devconSources = Invoke-RestMethod -Uri $sourcesUrl
224-
225-
# Enrich the downloaded source list with a calculated 'BuildNumber' property to make it sortable.
226-
$enrichedSources = $devconSources | ForEach-Object {
227-
$source = $_; $matchedBuild = 0
228-
foreach ($entry in $versionNameToBuildMap.GetEnumerator()) {
229-
if ($source.Name.Contains($entry.Key)) { $matchedBuild = $entry.Value; break }
230-
}
231-
$source | Add-Member -MemberType NoteProperty -Name "BuildNumber" -Value $matchedBuild; $source
232-
} | Where-Object { $_.BuildNumber -gt 0 }
233-
234-
$osFamilySources = $enrichedSources | Where-Object { $_.Name -like "*Windows $osMajorVersion*" -or ($osMajorVersion -eq 'Server' -and $_.Name -like "*Server*") }
235-
236-
# --- NEAREST-BUILD MATCHING LOGIC ---
237-
# 1. Try for a perfect match first.
238-
$bestMatch = $osFamilySources | Where-Object { $_.BuildNumber -eq $osBuild } | Select-Object -First 1
239-
240-
if (-not $bestMatch) {
241-
Write-Log -Message "No exact DevCon match for build $osBuild. Finding nearest available version..." -Status 'Warning'
242-
# 2. If no exact match, find the newest version that is still older than (or equal to) the current OS.
243-
# This is the safest fallback, as it guarantees API compatibility.
244-
$bestOlderMatch = $osFamilySources | Where-Object { $_.BuildNumber -le $osBuild } | Sort-Object BuildNumber -Descending | Select-Object -First 1
245-
246-
# 3. If no older versions exist, find the oldest version that is newer than the current OS.
247-
# This is a less-safe fallback but better than failing completely.
248-
$bestNewerMatch = $osFamilySources | Where-Object { $_.BuildNumber -gt $osBuild } | Sort-Object BuildNumber | Select-Object -First 1
249-
250-
if ($bestOlderMatch) { $bestMatch = $bestOlderMatch } elseif ($bestNewerMatch) { $bestMatch = $bestNewerMatch }
251-
Write-Verbose "Nearest older match: $($bestOlderMatch.Name) | Nearest newer match: $($bestNewerMatch.Name)"
252-
}
253-
254-
if (-not $bestMatch) { throw "Could not find any compatible DevCon versions for your OS (Build $osBuild)." }
255-
256-
$devconHash = ($bestMatch.Sources | Where-Object { $_.Architecture -eq 'X64' }).Sha256
257-
Write-Log -Message "Using DevCon Source: $($bestMatch.Name) (Build $($bestMatch.BuildNumber))" -Status 'Success'
258-
Write-Verbose "Selected DevCon Hash (X64): $devconHash"
259-
if (-not $devconHash) { throw "Could not find a 64-bit DevCon hash in the selected source: $($bestMatch.Name)" }
260-
261-
#--- 6b. Acquire DevCon Utility ---
262-
Write-Log -Message "Acquiring secure DevCon utility..."
263-
$devconInstallerUrl = "https://github.com/Drawbackz/DevCon-Installer/releases/download/1.4-rc/Devcon.Installer.exe"
264-
$devconInstallerPath = Join-Path $tempDir "Devcon.Installer.exe"
265-
Write-Verbose "Downloading DevCon Installer from $devconInstallerUrl"
266-
Invoke-WebRequest -Uri $devconInstallerUrl -OutFile $devconInstallerPath
267-
Write-Verbose "DevCon Installer downloaded successfully."
268-
269-
# Use the hash to ensure the DevCon-Installer utility downloads the correct, secure version of DevCon.
270-
$devconArgs = "install -hash $devconHash -update -dir `"$tempDir`""
271-
Write-Verbose "Running DevCon Installer with arguments: $devconArgs"
272-
Start-Process -FilePath $devconInstallerPath -ArgumentList $devconArgs -Wait -NoNewWindow
273-
274-
$devconExe = Join-Path $tempDir "devcon.exe"
275-
if (-not (Test-Path $devconExe)) { throw "Failed to acquire devcon.exe." }
276-
Write-Verbose "devcon.exe acquired successfully at $devconExe"
277-
278-
#--- 6c. Execute Install or Uninstall ---
279-
if ($Action -eq 'install') {
280-
Write-Log -Message "Starting driver installation..."
281-
$downloadUrl = $null
282-
if ($DriverVersion -eq "latest") {
283-
$apiUrl = "https://api.github.com/repos/VirtualDrivers/Virtual-Display-Driver/releases/latest"
284-
# Technical Choice: Many APIs, including GitHub's, require a User-Agent header.
285-
# Omitting this can lead to connection errors (like 403 Forbidden or 404 Not Found).
286-
$headers = @{ "User-Agent" = "PowerShell-VDD-Manager-Script" }
287-
288-
Write-Verbose "Querying GitHub API for latest driver release: $apiUrl"
289-
$releaseInfo = Invoke-RestMethod -Uri $apiUrl -Headers $headers
290-
Write-Verbose "API call successful. Latest release found: $($releaseInfo.tag_name)"
291-
292-
$asset = $releaseInfo.assets | Where-Object { $_.name -match "x64\.zip$" } | Select-Object -First 1
293-
if (-not $asset) { throw "Could not find a 64-bit driver asset (x64.zip) in the latest GitHub release." }
294-
295-
$downloadUrl = $asset.browser_download_url
296-
Write-Verbose "Found driver asset: $($asset.name)"
297-
}
298-
else {
299-
$downloadUrl = "https://github.com/VirtualDrivers/Virtual-Display-Driver/releases/download/$DriverVersion/Signed-Driver-v$DriverVersion-x64.zip"
300-
Write-Verbose "Using specified driver version: $DriverVersion"
301-
}
302-
303-
if (-not $downloadUrl) { throw "Could not determine a valid driver download URL for version '$DriverVersion'." }
304-
305-
Write-Verbose "Downloading driver from URL: $downloadUrl"
306-
$driverZipPath = Join-Path $tempDir "driver.zip"
307-
Invoke-WebRequest -Uri $downloadUrl -OutFile $driverZipPath
308-
Write-Verbose "Driver ZIP file downloaded to $driverZipPath"
309-
310-
Expand-Archive -Path $driverZipPath -DestinationPath $tempDir -Force
311-
Write-Verbose "Driver archive expanded."
312-
313-
# Use DevCon to install the driver by pointing to its INF file and specifying its unique Hardware ID.
314-
# "Root\MttVDD" identifies this as a root-enumerated virtual device.
315-
Write-Verbose "Running DevCon to install the driver..."
316-
& $devconExe install (Join-Path $tempDir "MttVDD.inf") "Root\MttVDD"
317-
}
318-
else { # Action must be 'uninstall'
319-
Write-Log -Message "Starting driver uninstallation..."
320-
if (Get-VirtualDisplayDevice) {
321-
Write-Verbose "Driver found. Preparing to remove."
322-
& $devconExe remove "Root\MttVDD"
323-
}
324-
else { Write-Log -Message "Driver is not currently installed. Nothing to do." }
325-
}
326-
}
327-
elseif ($Action -in @('enable', 'disable', 'toggle')) {
186+
if ($Action -in @('enable', 'disable', 'toggle')) {
328187
$device = Get-VirtualDisplayDevice
329188
if (-not $device) { Write-Log -Message "Device not found. Cannot perform '$Action'. Please install the driver first." -Status 'Warning' }
330189
elseif ($Action -eq 'enable') { Write-Log -Message "Enabling device: $($device.FriendlyName)..."; $device | Enable-PnpDevice -Confirm:$false }
@@ -383,16 +242,7 @@ finally {
383242
# This block ALWAYS runs, ensuring cleanup happens after success or failure.
384243
# If the user ran with -Verbose, we assume they are debugging.
385244
# We will NOT delete the temporary folder so they can inspect its contents.
386-
if ($PSBoundParameters.ContainsKey('Verbose')) {
387-
Write-Verbose "Verbose mode is active. Temporary directory will not be deleted so you can inspect its contents: $tempDir"
388-
}
389-
else {
390-
if (Test-Path $tempDir) {
391-
# This Write-Verbose message will not be visible without -Verbose, but is good practice.
392-
Write-Verbose "Cleaning up temporary directory: $tempDir"
393-
#Remove-Item -Path $tempDir -Recurse -Force
394-
}
395-
}
245+
396246
}
397247

398248
# Add a final pause unless in Silent or JSON mode so the user can see the output.

Community Scripts/x64/nefconc.exe

841 KB
Binary file not shown.

Community Scripts/x64/nefconw.exe

798 KB
Binary file not shown.

Virtual Display Driver (HDR)/MttVDD/Driver.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ Copyright (c) Microsoft Corporation
4040
#include <map>
4141
#include <set>
4242

43-
44-
45-
46-
4743
#define PIPE_NAME L"\\\\.\\pipe\\MTTVirtualDisplayPipe"
4844

4945
#pragma comment(lib, "xmllite.lib")

0 commit comments

Comments
 (0)