66# --------------------------------------------------------------------------*/
77
88# check if file present
9- $global :maxcount = 30
9+ $global :maxcount = 10
1010function is_present ($filepath )
1111{
1212 $isavailable = Test-Path $filepath
1313 return $isavailable
1414}
1515
16+ function log_file ()
17+ {
18+ $originalLogFile = " DvServer_log.txt"
19+ $incrementalLogFile = $originalLogFile
20+ $counter = 1
21+
22+ while (Test-Path $incrementalLogFile ) {
23+ $incrementalLogFile = " {0}-{1}.txt" -f $originalLogFile.Replace (' .txt' , ' ' ), $counter
24+ $counter ++
25+ }
26+
27+ return $incrementalLogFile
28+
29+ }
30+
1631# check if all the required binaries are present or not
1732function check_executables ()
1833{
19- if ((is_present(" DVServer\dvserver.cat" ) -eq $true ) -and
20- (is_present(" DVServer\DVServer.dll" ) -eq $true ) -and
21- (is_present(" DVServer\DVServer.inf" ) -eq $true ) -and
22- (is_present(" DVServer\dvserverkmd.cat" ) -eq $true ) -and
23- (is_present(" DVServer\DVServerKMD.inf" ) -eq $true ) -and
24- (is_present(" DVServer\DVServerKMD.sys" ) -eq $true ) -and
25- (is_present(" DVEnabler.dll" ) -eq $true ) -and
26- (is_present(" GraphicsDriver\Graphics\iigd_dch.inf" ) -eq $true )){
27- Write-Host " Setup files present"
28- return " SUCCESS"
34+ $files = " DVServer\dvserver.cat" , " DVServer\DVServer.dll" , " DVServer\DVServer.inf" , " DVServer\dvserverkmd.cat" , " DVServer\DVServerKMD.inf" , " DVServer\DVServerKMD.sys" , " DVEnabler.dll"
35+
36+ # ArrayList to store the names of missing files
37+ $missingFiles = New-Object System.Collections.ArrayList
38+
39+ foreach ($file in $files ) {
40+ if (-not (is_present $file )) {
41+ [void ]$missingFiles.Add ($file )
42+ }
2943 }
30- Write-Host " Setup files don't exist.. Exiting.."
31- return " FAIL"
44+
45+ # Output the result
46+ if ($missingFiles.Count -eq 0 ) {
47+ Write-Host " Setup files present"
48+ }
49+ else {
50+ Write-Host " The following files needed for installation are missing:"
51+ Write-Host ($missingFiles -join " `n " )
52+ return " FAIL"
53+ }
54+ }
55+
56+ function dvserver_cleanup ()
57+ {
58+ if (pnputil.exe / enum- drivers | findstr / i dvserverkmd.inf) {
59+ $driverPackage = Get-WmiObject - Class Win32_PnPSignedDriver | Where-Object { $_.DeviceName -eq " DVServerKMD Device" }
60+ if ($driverPackage ) {
61+ $publishedName = $driverPackage.InfName
62+ pnputil.exe / delete- driver " $publishedName " / force / uninstall
63+ }
64+ }
65+
66+ Write-Host " Driver Installation failed.. "
67+ Write-Host " Please Reboot the system and Run the Installation Script Again."
68+ Stop-Transcript
69+
70+ Exit
3271}
3372
3473function start_dvenabler ()
@@ -45,17 +84,18 @@ function start_dvenabler()
4584 $count = 0
4685
4786 rundll32.exe DVEnabler.dll, dvenabler_init
87+ Write-Host " Starting DVEnabler... Please wait..."
4888 # Before Rebooting the system, we need to make sure that DVEnabler.dll has been kick started
49- # So adding a loop with a counter of maxcount = 30 , To check if DVEnabler has started
50- # If DVEnabler doesnt get started before 30 iteration, we will exit the script.
89+ # So adding a loop with a counter of maxcount = 10 , To check if DVEnabler has started
90+ # If DVEnabler doesn’t get started before 10 iteration, we will exit the script.
5191 while ($count -lt $maxcount ){
5292 $dve = tasklist / m | findstr " DVEnabler.dll"
5393 if ($dve ) {
5494 Write-Host " DVEnabler started as service ."
5595 break
5696 } else {
57- Write-Host " Starting DVEnabler... Please wait..."
5897 $count ++
98+ Write-Host - NoNewline " $ ( $count ) /$maxcount Done `r " ; sleep 1
5999 continue
60100 }
61101 }
@@ -69,63 +109,134 @@ function start_dvenabler()
69109 # Copying DVEnabler.DLL to system32 is required as part of the installation
70110 cp DVEnabler.dll C:\Windows\System32
71111
72- # regiter a task to start the dvenabler.dll as a service during every user logon
112+ # Resgister the DVEnabler task during workstation lock and unlock
113+ Register_ScheduledTask
114+
115+ return " SUCCESS"
116+ }
117+
118+ function Register_ScheduledTask ()
119+ {
120+ $TASK_SESSION_UNLOCK = 8 # TASK_SESSION_STATE_CHANGE_TYPE.TASK_SESSION_UNLOCK (taskschd.h)
121+ $TASK_SESSION_LOCK = 7 # TASK_SESSION_STATE_CHANGE_TYPE.TASK_SESSION_LOCK (taskschd.h)
122+
123+ $stateChangeTrigger = Get-CimClass `
124+ - Namespace ROOT\Microsoft\Windows\TaskScheduler `
125+ - ClassName MSFT_TaskSessionStateChangeTrigger
126+
127+ $onUnlockTrigger = New-CimInstance ` - CimClass $stateChangeTrigger `
128+ - Property @ { StateChange = $TASK_SESSION_UNLOCK } ` - ClientOnly
129+
130+ $onLockTrigger = New-CimInstance ` - CimClass $stateChangeTrigger `
131+ - Property @ { StateChange = $TASK_SESSION_LOCK } ` - ClientOnly
132+
73133 unregister-scheduledtask - TaskName " DVEnabler" - confirm:$false - ErrorAction SilentlyContinue
134+ unregister-scheduledtask - TaskName " StopDVEnabler" - confirm:$false - ErrorAction SilentlyContinue
135+
136+ # Register a task to start the dvenabler.dll as a service during every user logon or user unlock
74137 $ac = New-ScheduledTaskAction - Execute " rundll32.exe" - Argument " C:\Windows\System32\DVEnabler.dll,dvenabler_init"
75138 $tr = New-ScheduledTaskTrigger - AtLogOn
76- $pr = New-ScheduledTaskPrincipal - Groupid " INTERACTIVE"
77- Register-ScheduledTask - TaskName " DVEnabler" - Trigger $tr - TaskPath " \Microsoft\Windows\DVEnabler" - Action $ac - Principal $pr
139+ $pr = New-ScheduledTaskPrincipal - Groupid " INTERACTIVE" - RunLevel Highest
140+ $settings = New-ScheduledTaskSettingsSet - AllowStartIfOnBatteries - ExecutionTimeLimit 0 - MultipleInstances Queue
141+ Register-ScheduledTask - TaskName " DVEnabler" - Trigger @ ($tr , $onUnlockTrigger ) - TaskPath " \Microsoft\Windows\DVEnabler" - Action $ac - Principal $pr - Settings $settings
142+
143+ # Register a task to Stop the dvenabler.dll during every user lock
144+ $ac = New-ScheduledTaskAction - Execute " powershell.exe" - Argument " -ExecutionPolicy Bypass -NoProfile -WindowStyle Hidden -Command `" Stop-ScheduledTask -TaskName '\Microsoft\Windows\DVEnabler\DvEnabler'`" "
145+ $pr = New-ScheduledTaskPrincipal - Groupid " INTERACTIVE" - RunLevel Highest
146+ $settings = New-ScheduledTaskSettingsSet - AllowStartIfOnBatteries - ExecutionTimeLimit 0 - MultipleInstances Queue
147+ Register-ScheduledTask - TaskName " StopDVEnabler" - Trigger $onLockTrigger - TaskPath " \Microsoft\Windows\DVEnabler" - Action $ac - Principal $pr - Settings $settings
78148
79149 return " SUCCESS"
150+
80151}
81152
82153# #Main##
154+ $logfile = log_file
155+ Start-Transcript - Path $logfile - Append
156+
83157$ret = check_executables
84158if ($ret -eq " FAIL" ) {
159+ Stop-Transcript
85160 Exit
86161}
87162else {
163+ # Do a refresh before starting the installation.
164+ pnputil / scan- devices
165+
88166 if ((is_present(" DVServer.cer" ) -eq $true ) -and
89167 (is_present(" DVServerKMD.cer" ) -eq $true )){
90168 Write-Host " Start DVServer Certificate installation..."
91169 certutil - addstore root DVServer.cer
92170 certutil - addstore root DVServerKMD.cer
93171 }
94-
95- Write-Host " Start Windows GFX Driver installation..."
96- pnputil.exe / add-driver .\GraphicsDriver\Graphics\iigd_dch.inf / install
97172
98173 Write-Host " Start Zerocopy Driver installation..."
99174 pnputil.exe / add-driver .\DVServer\DVServerKMD.inf / install
100175 $count = 0
101176 # Before starting DVEnabler.dll we should make sure that DVServer UMD has started or not
102- # So adding a loop with a counter of maxcount = 30, To check if DVServer UMD has started
103- # if DVserver UMD doesnt get started before 30 iteration, we will exit the script
177+ # So adding a loop with a counter of maxcount = 10, To check if DVServer UMD has started
178+ # if DVserver UMD doesn’t get started before 10 iteration, we will exit the script
179+ Write-Host " DVServer loading...Please wait..."
104180 while ($count -lt $maxcount ){
105181 $dvs = tasklist / m | findstr " dvserver.dll"
106182 if ($dvs ) {
107183 Write-Host " DVServer loaded successfully..."
108184 break
109185 } else {
110- Write-Host " DVServer loading...Please wait..."
111186 $count ++
187+ Write-Host - NoNewline " $ ( $count ) /$maxcount Done `r " ; sleep 1
112188 continue
113189 }
114190 }
191+
192+ # Reset the count
193+ $count = 0
194+
115195 if (! $dvs ) {
116- Write-Host " Failed to load DVServer UMD... Exiting"
117- Exit
196+ Write-Host " Trying to install DVServer UMD..."
197+ pnputil.exe / add-driver .\DVServer\DVServer.inf / install
198+ while ($count -lt $maxcount ){
199+ $dvs = tasklist / m | findstr " dvserver.dll"
200+ if ($dvs ) {
201+ Write-Host " DVServer loaded successfully..."
202+ break
203+ } else {
204+ $count ++
205+ Write-Host - NoNewline " $ ( $count ) /$maxcount Done `r " ; sleep 1
206+ continue
207+ }
208+ }
209+
210+ }
211+
212+ if (! $dvs ) {
213+ Write-Host " Failed to load DVServer UMD..."
214+ dvserver_cleanup
118215 }
119216
120- # call start_dvnabler to run the dvenabler.sll as a service
217+ # call start_dvenabler to run the dvenabler.dll as a service
121218 $dve = start_dvenabler
122219 if ($dve -eq " SUCCESS" ) {
123- Write-Host " Dvnabler succusfully started...."
220+ Write-Host " Dvenabler successfully started...."
124221 Write-Host " Rebooting Windows VM..."
222+ Stop-Transcript
125223 Restart-Computer
126224 } else {
127- Write-Host " Fail to start Dvnabler.... Exiting!"
128- Exit
225+ Write-Host " Failed to start DVEnabler...."
226+
227+ # Before cleanup, make IDD as primary monitor , so that the user can see the PowerShell window
228+
229+ # Get the second display device name
230+ $secondDisplay = (Get-WmiObject - Namespace " root\CIMV2" - Class Win32_VideoController | Select-Object - Skip 1 - First 1 ).Name
231+
232+ # Set the second display as the primary display using DisplaySwitch.exe
233+ DisplaySwitch.exe / internal
234+ DisplaySwitch.exe / external:$secondDisplay
235+
236+ # Restart the Explorer process to apply the changes
237+ Stop-Process - Name " explorer" - Force
238+
239+ dvserver_cleanup
129240 }
130241
131242}
0 commit comments