├── v2
├── bin
│ ├── ControlzEx.dll
│ ├── MahApps.Metro.dll
│ ├── System.Windows.Interactivity.dll
│ ├── LICENSE
│ └── LICENSE+
├── Show-OSUpgradeBackground.ps1
├── Create-Runspaces.ps1
├── Xaml
│ └── SplashScreen.xaml
└── Create-FullScreenBackground.ps1
├── v1
├── bin
│ ├── MahApps.Metro.dll
│ ├── System.Windows.Interactivity.dll
│ ├── LICENSE
│ └── LICENSE+
├── Show-OSUpgradeBackground.ps1
├── Create-FullScreenBackground.ps1
└── Invoke-PSScriptAsUser.ps1
└── README.md
/v2/bin/ControlzEx.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SMSAgentSoftware/CustomW10UpgradeSplashScreen/HEAD/v2/bin/ControlzEx.dll
--------------------------------------------------------------------------------
/v1/bin/MahApps.Metro.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SMSAgentSoftware/CustomW10UpgradeSplashScreen/HEAD/v1/bin/MahApps.Metro.dll
--------------------------------------------------------------------------------
/v2/bin/MahApps.Metro.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SMSAgentSoftware/CustomW10UpgradeSplashScreen/HEAD/v2/bin/MahApps.Metro.dll
--------------------------------------------------------------------------------
/v1/bin/System.Windows.Interactivity.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SMSAgentSoftware/CustomW10UpgradeSplashScreen/HEAD/v1/bin/System.Windows.Interactivity.dll
--------------------------------------------------------------------------------
/v2/bin/System.Windows.Interactivity.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SMSAgentSoftware/CustomW10UpgradeSplashScreen/HEAD/v2/bin/System.Windows.Interactivity.dll
--------------------------------------------------------------------------------
/v2/Show-OSUpgradeBackground.ps1:
--------------------------------------------------------------------------------
1 | # Create a new PS process to call the "Show-OSUpgradeBackground" script, to avoid blocking the continuation of task sequence
2 |
3 | $Process = New-Object System.Diagnostics.Process
4 | $Process.StartInfo.UseShellExecute = $false
5 | $Process.StartInfo.FileName = "PowerShell.exe"
6 | $Process.StartInfo.Arguments = " -File ""$PSScriptRoot\Create-Runspaces.ps1"""
7 | $Process.StartInfo.CreateNoWindow = $true
8 | $Process.Start()
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Custom Windows 10 Upgrade Splash Screen
2 | PowerShell scripts to create a custom Windows 10 Upgrade Splash Screen for use with a ConfigMgr In-Place Upgrade task sequence
3 |
4 | More info here:
5 |
6 | Version 1: https://smsagent.wordpress.com/2018/08/21/create-a-custom-splash-screen-for-a-windows-10-in-place-upgrade/
7 |
8 | Version 2: https://smsagent.blog/2019/08/01/windows-10-upgrade-splash-screen-take-2/
9 |
10 | Splash screen demo:
11 |
12 |
14 |
--------------------------------------------------------------------------------
/v1/Show-OSUpgradeBackground.ps1:
--------------------------------------------------------------------------------
1 | # Calls the script that creates the OS upgrade background into a runspace, one per detected screen
2 |
3 | # Add required assemblies
4 | Add-Type -AssemblyName System.Windows.Forms
5 |
6 | # Get active screens
7 | $Screens = [System.Windows.Forms.Screen]::AllScreens
8 |
9 | # Create a runspace to initiate powershell for each screen and call the main script (otherwise each window will only open when the first closes due to the .ShowDialog() method)
10 | Foreach ($Screen in $screens) {
11 | $PowerShell = [Powershell]::Create()
12 | [void]$PowerShell.AddScript({Param($ScriptLocation, $DeviceName); powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "$ScriptLocation\Create-FullScreenBackground.ps1" -DeviceName $DeviceName})
13 | [void]$PowerShell.AddArgument($PSScriptRoot)
14 | [void]$PowerShell.AddArgument($Screen.DeviceName)
15 | [void]$PowerShell.BeginInvoke()
16 | }
17 |
18 | # Wait for runspace execution
19 | Start-Sleep -Seconds 10
20 |
--------------------------------------------------------------------------------
/v2/Create-Runspaces.ps1:
--------------------------------------------------------------------------------
1 | # Calls the script that creates the OS upgrade background into a runspace, one per detected screen
2 |
3 | Add-Type -AssemblyName System.Windows.Forms
4 | $Screens = [System.Windows.Forms.Screen]::AllScreens
5 | $PSInstances = New-Object System.Collections.ArrayList
6 | Foreach ($Screen in $screens) {
7 | $PowerShell = [Powershell]::Create()
8 | [void]$PowerShell.AddScript({Param($ScriptLocation, $DeviceName); powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "$ScriptLocation\Create-FullScreenBackground.ps1" -DeviceName $DeviceName})
9 | [void]$PowerShell.AddArgument($PSScriptRoot)
10 | [void]$PowerShell.AddArgument($Screen.DeviceName)
11 | [void]$PSInstances.Add($PowerShell)
12 | [void]$PowerShell.BeginInvoke()
13 | }
14 | # Wait for runspace execution
15 | Start-Sleep -Seconds 10
16 |
17 | # Keep the process alive until each splash screen is closed
18 | Do {
19 | Start-Sleep -Seconds 5
20 | }
21 | Until ($PSInstances.InvocationStateInfo.State -notcontains "Running")
--------------------------------------------------------------------------------
/v1/bin/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License (MIT)
2 |
3 | Copyright (c) 2016 MahApps
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/v2/bin/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License (MIT)
2 |
3 | Copyright (c) 2016 MahApps
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/v2/Xaml/SplashScreen.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/v1/bin/LICENSE+:
--------------------------------------------------------------------------------
1 | Unless indicated otherwise on a per-file basis all source and documentation herein
2 | is licensed under the MIT license. Some included code is licensed under MS-PL which
3 | is compatible with the terms of MIT.
4 |
5 | Original code from RangeSlider (AvalonControlsLibrary), ToggleSwitch (Microsoft's Silverlight "Cosmopolitan"),
6 | Callisto (@timheuer), WindowChrome (@Microsoft, @joecastro) and TransitioningContentControl from the
7 | Silverlight Toolkit 5 are licensed under MS-PL which is compatible with the terms of MIT.
8 |
9 | -----
10 |
11 | Microsoft Public License (MS-PL)
12 |
13 | This license governs use of the accompanying software. If you use the software, you
14 | accept this license. If you do not accept the license, do not use the software.
15 |
16 | 1. Definitions
17 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
18 | same meaning here as under U.S. copyright law.
19 | A "contribution" is the original software, or any additions or changes to the software.
20 | A "contributor" is any person that distributes its contribution under this license.
21 | "Licensed patents" are a contributor's patent claims that read directly on its contribution.
22 |
23 | 2. Grant of Rights
24 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
25 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
26 |
27 | 3. Conditions and Limitations
28 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
29 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
30 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
31 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
32 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
33 |
--------------------------------------------------------------------------------
/v2/bin/LICENSE+:
--------------------------------------------------------------------------------
1 | Unless indicated otherwise on a per-file basis all source and documentation herein
2 | is licensed under the MIT license. Some included code is licensed under MS-PL which
3 | is compatible with the terms of MIT.
4 |
5 | Original code from RangeSlider (AvalonControlsLibrary), ToggleSwitch (Microsoft's Silverlight "Cosmopolitan"),
6 | Callisto (@timheuer), WindowChrome (@Microsoft, @joecastro) and TransitioningContentControl from the
7 | Silverlight Toolkit 5 are licensed under MS-PL which is compatible with the terms of MIT.
8 |
9 | -----
10 |
11 | Microsoft Public License (MS-PL)
12 |
13 | This license governs use of the accompanying software. If you use the software, you
14 | accept this license. If you do not accept the license, do not use the software.
15 |
16 | 1. Definitions
17 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
18 | same meaning here as under U.S. copyright law.
19 | A "contribution" is the original software, or any additions or changes to the software.
20 | A "contributor" is any person that distributes its contribution under this license.
21 | "Licensed patents" are a contributor's patent claims that read directly on its contribution.
22 |
23 | 2. Grant of Rights
24 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
25 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
26 |
27 | 3. Conditions and Limitations
28 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
29 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
30 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
31 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
32 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
33 |
--------------------------------------------------------------------------------
/v1/Create-FullScreenBackground.ps1:
--------------------------------------------------------------------------------
1 | # Creates a full screen 'background' styled for a Windows 10 upgrade, and hides the task bar
2 | # Called by the "Show-OSUpgradeBackground" script
3 |
4 | Param($DeviceName)
5 |
6 | # Add required assemblies
7 | Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase,System.Windows.Forms,System.Drawing
8 | Add-Type -AssemblyName System.DirectoryServices.AccountManagement
9 | Add-Type -Path "$PSSCriptRoot\bin\MahApps.Metro.dll"
10 | Add-Type -Path "$PSSCriptRoot\bin\System.Windows.Interactivity.dll"
11 |
12 | # Find screen by DeviceName
13 | $Screens = [System.Windows.Forms.Screen]::AllScreens
14 | $Screen = $Screens | Where {$_.DeviceName -eq $DeviceName}
15 |
16 | # Add custom type to hide the taskbar
17 | # Thanks to https://stackoverflow.com/questions/25499393/make-my-wpf-application-full-screen-cover-taskbar-and-title-bar-of-window
18 | $Source = @"
19 | using System;
20 | using System.Runtime.InteropServices;
21 |
22 | public class Taskbar
23 | {
24 | [DllImport("user32.dll")]
25 | private static extern int FindWindow(string className, string windowText);
26 | [DllImport("user32.dll")]
27 | private static extern int ShowWindow(int hwnd, int command);
28 |
29 | private const int SW_HIDE = 0;
30 | private const int SW_SHOW = 1;
31 |
32 | protected static int Handle
33 | {
34 | get
35 | {
36 | return FindWindow("Shell_TrayWnd", "");
37 | }
38 | }
39 |
40 | private Taskbar()
41 | {
42 | // hide ctor
43 | }
44 |
45 | public static void Show()
46 | {
47 | ShowWindow(Handle, SW_SHOW);
48 | }
49 |
50 | public static void Hide()
51 | {
52 | ShowWindow(Handle, SW_HIDE);
53 | }
54 | }
55 | "@
56 | Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition $Source -Language CSharp
57 |
58 | # Find the user identity from the domain if possible
59 | Try
60 | {
61 | $PrincipalContext = [System.DirectoryServices.AccountManagement.PrincipalContext]::new([System.DirectoryServices.AccountManagement.ContextType]::Domain, [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain())
62 | $GivenName = ([System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($PrincipalContext,[System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName,[Environment]::UserName)).GivenName
63 | $PrincipalContext.Dispose()
64 | }
65 | Catch {}
66 |
67 | # Create a WPF window
68 | $Window = New-Object System.Windows.Window
69 | $window.Background = "#012a47"
70 | $Window.WindowStyle = [System.Windows.WindowStyle]::None
71 | $Window.ResizeMode = [System.Windows.ResizeMode]::NoResize
72 | $Window.Foreground = [System.Windows.Media.Brushes]::White
73 | $window.Topmost = $True
74 |
75 | # Get the bounds of the primary screen
76 | $Bounds = $Screen.Bounds
77 |
78 | # Assemble a grid
79 | $Grid = New-object System.Windows.Controls.Grid
80 | $Grid.Width = "NaN"
81 | $Grid.Height = "NaN"
82 | $Grid.HorizontalAlignment = "Stretch"
83 | $Grid.VerticalAlignment = "Stretch"
84 |
85 | # Add a column
86 | $Column = New-Object System.Windows.Controls.ColumnDefinition
87 | $Grid.ColumnDefinitions.Add($Column)
88 |
89 | # Add rows
90 | $Row = New-Object System.Windows.Controls.RowDefinition
91 | $Row.Height = "1*"
92 | $Grid.RowDefinitions.Add($Row)
93 | $Row = New-Object System.Windows.Controls.RowDefinition
94 | $Row.Height = [System.Windows.GridLength]::Auto
95 | $Grid.RowDefinitions.Add($Row)
96 | $Row = New-Object System.Windows.Controls.RowDefinition
97 | $Row.Height = [System.Windows.GridLength]::Auto
98 | $Grid.RowDefinitions.Add($Row)
99 | $Row = New-Object System.Windows.Controls.RowDefinition
100 | $Row.Height = "1*"
101 | $Grid.RowDefinitions.Add($Row)
102 |
103 | # Add a progress ring
104 | $ProgressRing = [MahApps.Metro.Controls.ProgressRing]::new()
105 | $ProgressRing.Opacity = 0
106 | $ProgressRing.IsActive = $false
107 | $ProgressRing.Margin = "0,0,0,60"
108 | $Grid.AddChild($ProgressRing)
109 | $ProgressRing.SetValue([System.Windows.Controls.Grid]::RowProperty,1)
110 |
111 | # Add a textblock
112 | $TextBlock = New-Object System.Windows.Controls.TextBlock
113 | If ($GivenName)
114 | {
115 | $TextBlock.Text = "Hi $GivenName"
116 | }
117 | Else
118 | {
119 | $TextBlock.Text = "Hi there"
120 | }
121 | $TextBlock.TextWrapping = [System.Windows.TextWrapping]::Wrap
122 | $TextBlock.MaxWidth = $Bounds.Width
123 | $TextBlock.Margin = "0,0,0,120"
124 | $TextBlock.FontSize = 50
125 | $TextBlock.FontWeight = [System.Windows.FontWeights]::Light
126 | $TextBlock.VerticalAlignment = "Top"
127 | $TextBlock.HorizontalAlignment = "Center"
128 | $TextBlock.Opacity = 0
129 | $Grid.AddChild($TextBlock)
130 | $TextBlock.SetValue([System.Windows.Controls.Grid]::RowProperty,2)
131 |
132 | # Add a textblock
133 | $TextBlock2 = New-Object System.Windows.Controls.TextBlock
134 | $TextBlock2.Margin = "0,0,0,60"
135 | $TextBlock2.Text = "Don't turn off your pc"
136 | $TextBlock2.TextWrapping = [System.Windows.TextWrapping]::Wrap
137 | $TextBlock2.MaxWidth = $Bounds.Width
138 | $TextBlock2.FontSize = 25
139 | $TextBlock2.FontWeight = [System.Windows.FontWeights]::Light
140 | $TextBlock2.VerticalAlignment = "Bottom"
141 | $TextBlock2.HorizontalAlignment = "Center"
142 | $TextBlock2.Opacity = 0
143 | $Grid.AddChild($TextBlock2)
144 | $TextBlock2.SetValue([System.Windows.Controls.Grid]::RowProperty,3)
145 |
146 | # Add to window
147 | $Window.AddChild($Grid)
148 |
149 | # Create some animations
150 | $FadeinAnimation = [System.Windows.Media.Animation.DoubleAnimation]::new(0,1,[System.Windows.Duration]::new([Timespan]::FromSeconds(3)))
151 | $FadeOutAnimation = [System.Windows.Media.Animation.DoubleAnimation]::new(1,0,[System.Windows.Duration]::new([Timespan]::FromSeconds(3)))
152 | $ColourBrighterAnimation = [System.Windows.Media.Animation.ColorAnimation]::new("#012a47","#1271b5",[System.Windows.Duration]::new([Timespan]::FromSeconds(5)))
153 | $ColourDarkerAnimation = [System.Windows.Media.Animation.ColorAnimation]::new("#1271b5","#012a47",[System.Windows.Duration]::new([Timespan]::FromSeconds(5)))
154 |
155 | # An array of sentences to display, in order. Leave the first one blank as the 0 index gets skipped.
156 | $TextArray = @(
157 | ""
158 | "We're upgrading you to Windows 10 1803"
159 | "It may take 30-60 minutes"
160 | "Your pc will restart a few times"
161 | "Should anything go wrong (we hope it won't)..."
162 | "...please give the Helpdesk a call"
163 | "Now might be a good time to get a coffee :)"
164 | "We'll have you up and running again in no time"
165 | )
166 |
167 | # Start a dispatcher timer. This is used to control when the sentences are changed.
168 | $TimerCode = {
169 |
170 | # The IF statement number should equal the number of sentences in the TextArray
171 | If ($i -lt 7)
172 | {
173 | $FadeoutAnimation.Add_Completed({
174 | $TextBlock.Opacity = 0
175 | $TextBlock.Text = $TextArray[$i]
176 | $TextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
177 |
178 | })
179 | $TextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeoutAnimation)
180 | }
181 | # The final sentence to display ongoing
182 | ElseIf ($i -eq 7)
183 | {
184 |
185 | $FadeoutAnimation.Add_Completed({
186 | $TextBlock.Opacity = 0
187 | $TextBlock.Text = "Windows 10 Upgrade in Progress"
188 | $TextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
189 | $ProgressRing.IsActive = $True
190 |
191 | })
192 | $TextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeoutAnimation)
193 | }
194 | Else
195 | {}
196 |
197 | $ColourBrighterAnimation.Add_Completed({
198 | $Window.Background.BeginAnimation([System.Windows.Media.SolidColorBrush]::ColorProperty,$ColourDarkerAnimation)
199 | })
200 | $Window.Background.BeginAnimation([System.Windows.Media.SolidColorBrush]::ColorProperty,$ColourBrighterAnimation)
201 |
202 | $Script:i++
203 |
204 | }
205 | $DispatcherTimer = New-Object -TypeName System.Windows.Threading.DispatcherTimer
206 | $DispatcherTimer.Interval = [TimeSpan]::FromSeconds(10)
207 | $DispatcherTimer.Add_Tick($TimerCode)
208 |
209 |
210 | # Event: Window loaded
211 | $Window.Add_Loaded({
212 |
213 | # Activate the window to bring it to the fore
214 | $This.Activate()
215 |
216 | # Fill the screen
217 | $Bounds = $screen.Bounds
218 | $Window.Left = $Bounds.Left
219 | $Window.Top = $Bounds.Top
220 | $Window.Height = $Bounds.Height
221 | $Window.Width = $Bounds.Width
222 |
223 | # Hide the taskbar
224 | [TaskBar]::Hide()
225 |
226 | # Hide the mouse cursor
227 | [System.Windows.Forms.Cursor]::Hide()
228 |
229 | # Begin animations
230 | $TextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
231 | $TextBlock2.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
232 | $ProgressRing.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
233 | $ColourBrighterAnimation.Add_Completed({
234 | $Window.Background.BeginAnimation([System.Windows.Media.SolidColorBrush]::ColorProperty,$ColourDarkerAnimation)
235 | })
236 | $Window.Background.BeginAnimation([System.Windows.Media.SolidColorBrush]::ColorProperty,$ColourBrighterAnimation)
237 |
238 | })
239 |
240 | # Event: Window closing
241 | $Window.Add_Closing({
242 |
243 | # Restore the taskbar
244 | [Taskbar]::Show()
245 |
246 | # Restore the mouse cursor
247 | [System.Windows.Forms.Cursor]::Show()
248 |
249 | $DispatcherTimer.Stop()
250 |
251 | })
252 |
253 | # Event: Allows to close the window on right-click (uncomment for testing)
254 | <#
255 | $Window.Add_MouseRightButtonDown({
256 |
257 | $This.Close()
258 |
259 | })
260 | #>
261 |
262 | # Display the window
263 | $DispatcherTimer.Start()
264 | $Window.ShowDialog()
265 |
--------------------------------------------------------------------------------
/v2/Create-FullScreenBackground.ps1:
--------------------------------------------------------------------------------
1 | # Creates a full screen 'background' styled for a Windows 10 upgrade, and hides the task bar
2 | # Called by the "Show-OSUpgradeBackground" script
3 |
4 | Param($DeviceName)
5 |
6 | # Set the location we are running from
7 | $Source = $PSScriptRoot
8 |
9 | Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase,System.Windows.Forms,System.Drawing,System.DirectoryServices.AccountManagement
10 | Add-Type -Path "$Source\bin\System.Windows.Interactivity.dll"
11 | Add-Type -Path "$Source\bin\ControlzEx.dll"
12 | Add-Type -Path "$Source\bin\MahApps.Metro.dll"
13 |
14 | # Add custom type to hide the taskbar
15 | # Thanks to https://stackoverflow.com/questions/25499393/make-my-wpf-application-full-screen-cover-taskbar-and-title-bar-of-window
16 | $CSharpSource = @"
17 | using System;
18 | using System.Runtime.InteropServices;
19 |
20 | public class Taskbar
21 | {
22 | [DllImport("user32.dll")]
23 | private static extern int FindWindow(string className, string windowText);
24 | [DllImport("user32.dll")]
25 | private static extern int ShowWindow(int hwnd, int command);
26 |
27 | private const int SW_HIDE = 0;
28 | private const int SW_SHOW = 1;
29 |
30 | protected static int Handle
31 | {
32 | get
33 | {
34 | return FindWindow("Shell_TrayWnd", "");
35 | }
36 | }
37 |
38 | private Taskbar()
39 | {
40 | // hide ctor
41 | }
42 |
43 | public static void Show()
44 | {
45 | ShowWindow(Handle, SW_SHOW);
46 | }
47 |
48 | public static void Hide()
49 | {
50 | ShowWindow(Handle, SW_HIDE);
51 | }
52 | }
53 | "@
54 | Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition $CSharpSource -Language CSharp
55 |
56 | # Add custom type to prevent the screen from sleeping
57 | $code=@'
58 | using System;
59 | using System.Runtime.InteropServices;
60 |
61 | public class DisplayState
62 | {
63 | [DllImport("kernel32.dll", CharSet = CharSet.Auto,SetLastError = true)]
64 | public static extern void SetThreadExecutionState(uint esFlags);
65 |
66 | public static void KeepDisplayAwake()
67 | {
68 | SetThreadExecutionState(
69 | 0x00000002 | 0x80000000);
70 | }
71 |
72 | public static void Cancel()
73 | {
74 | SetThreadExecutionState(0x80000000);
75 | }
76 | }
77 | '@
78 | Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition $code -Language CSharp
79 |
80 | # Load the main window XAML code
81 | [XML]$Xaml = [System.IO.File]::ReadAllLines("$Source\Xaml\SplashScreen.xaml")
82 |
83 | # Create a synchronized hash table and add the WPF window and its named elements to it
84 | $UI = [System.Collections.Hashtable]::Synchronized(@{})
85 | $UI.Window = [Windows.Markup.XamlReader]::Load((New-Object -TypeName System.Xml.XmlNodeReader -ArgumentList $xaml))
86 | $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") |
87 | ForEach-Object -Process {
88 | $UI.$($_.Name) = $UI.Window.FindName($_.Name)
89 | }
90 |
91 | # Find screen by DeviceName
92 | $Screens = [System.Windows.Forms.Screen]::AllScreens
93 | $Screen = $Screens | Where {$_.DeviceName -eq $DeviceName}
94 | #$Screen = [System.Windows.Forms.Screen]::PrimaryScreen
95 | # Get the bounds of the primary screen
96 | $script:Bounds = $Screen.Bounds
97 |
98 | # Set some initial values
99 | $UI.MainTextBlock.MaxWidth = $Bounds.Width
100 | $UI.TextBlock2.MaxWidth = $Bounds.Width
101 | $UI.TextBlock3.MaxWidth = $Bounds.Width
102 | $UI.TextBlock4.MaxWidth = $Bounds.Width
103 | $UI.TextBlock2.Text = "Windows Setup Progress 0%"
104 | $UI.TextBlock3.Text = "00:00:00"
105 | $UI.TextBlock4.Text = "This will take a while...don't turn off your pc"
106 |
107 |
108 | # Find the user identity from the registry
109 | $LoggedOnSID = Get-WmiObject -Namespace ROOT\CCM -Class CCM_UserLogonEvents -Filter "LogoffTime=null" | Select -ExpandProperty UserSID
110 | If ($LoggedOnSID.GetType().IsArray)
111 | {
112 | # Multiple values returned
113 | $GivenName = "there"
114 | }
115 | Else
116 | {
117 | $RegKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\SessionData"
118 | $DisplayName = (Get-ChildItem -Path $RegKey | Where {$_.GetValue('LoggedOnUserSID') -eq $LoggedOnSID}).GetValue('LoggedOnDisplayName')
119 | If ($DisplayName)
120 | {
121 | $GivenName = $DisplayName.Split(',')[1].Trim()
122 | }
123 | Else
124 | {
125 | $GivenName = "there"
126 | }
127 | }
128 | $UI.MainTextBlock.Text = "Hi $GivenName"
129 |
130 | # Create some animations
131 | $FadeinAnimation = [System.Windows.Media.Animation.DoubleAnimation]::new(0,1,[System.Windows.Duration]::new([Timespan]::FromSeconds(3)))
132 | $FadeOutAnimation = [System.Windows.Media.Animation.DoubleAnimation]::new(1,0,[System.Windows.Duration]::new([Timespan]::FromSeconds(3)))
133 | $ColourBrighterAnimation = [System.Windows.Media.Animation.ColorAnimation]::new("#012a47","#1271b5",[System.Windows.Duration]::new([Timespan]::FromSeconds(5)))
134 | $ColourDarkerAnimation = [System.Windows.Media.Animation.ColorAnimation]::new("#1271b5","#012a47",[System.Windows.Duration]::new([Timespan]::FromSeconds(5)))
135 |
136 | # Create TSEnvironment COM object
137 | $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
138 | $WindowsVersion = $tsenv.Value('WindowsVersion')
139 |
140 | # An array of sentences to display, in order. Leave the first one blank as the 0 index gets skipped.
141 | $TextArray = @(
142 | ""
143 | "We're upgrading you to Windows 10 $WindowsVersion"
144 | "It may take 30-90 minutes"
145 | "Your pc will restart a few times"
146 | "Should anything go wrong (unlikely)..."
147 | "...please contact the Service Desk"
148 | "Now might be a good time to get a coffee :)"
149 | "We'll have you up and running again in no time"
150 | )
151 |
152 |
153 |
154 | # Start a dispatcher timer. This is used to control when the sentences are changed.
155 | $TimerCode = {
156 |
157 | If ($tsenv.Value('QuitSplashing') -eq "True")
158 | {
159 | $UI.Window.Close()
160 | }
161 |
162 | # The IF statement number should equal the number of sentences in the TextArray
163 | If ($i -lt 7)
164 | {
165 | $FadeoutAnimation.Add_Completed({
166 | $UI.MaintextBlock.Opacity = 0
167 | $UI.MaintextBlock.Text = $TextArray[$i]
168 | $UI.MaintextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
169 |
170 | })
171 | $UI.MaintextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeoutAnimation)
172 | }
173 | # The final sentence to display ongoing
174 | ElseIf ($i -eq 7)
175 | {
176 |
177 | $FadeoutAnimation.Add_Completed({
178 | $UI.MaintextBlock.Opacity = 0
179 | $UI.MaintextBlock.Text = "Windows 10 Upgrade in Progress"
180 | $UI.MaintextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
181 | $UI.ProgressRing.IsActive = $True
182 |
183 | })
184 | $UI.MaintextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeoutAnimation)
185 | }
186 | Else
187 | {}
188 |
189 | $ColourBrighterAnimation.Add_Completed({
190 | $UI.Window.Background.BeginAnimation([System.Windows.Media.SolidColorBrush]::ColorProperty,$ColourDarkerAnimation)
191 | })
192 | $UI.Window.Background.BeginAnimation([System.Windows.Media.SolidColorBrush]::ColorProperty,$ColourBrighterAnimation)
193 |
194 | $Script:i++
195 |
196 | }
197 | $DispatcherTimer = New-Object -TypeName System.Windows.Threading.DispatcherTimer
198 | $DispatcherTimer.Interval = [TimeSpan]::FromSeconds(10)
199 | $DispatcherTimer.Add_Tick($TimerCode)
200 |
201 |
202 | $Stopwatch = New-Object System.Diagnostics.Stopwatch
203 | $Stopwatch.Start()
204 | $TimerCode2 = {
205 | $ProgressValue = Get-ItemProperty -Path HKLM:\SYSTEM\Setup\MoSetup\Volatile -Name SetupProgress | Select -ExpandProperty SetupProgress -ErrorAction SilentlyContinue
206 | $UI.TextBlock3.Text = "$($Stopwatch.Elapsed.Hours.ToString('00')):$($Stopwatch.Elapsed.Minutes.ToString('00')):$($Stopwatch.Elapsed.Seconds.ToString('00'))"
207 | $UI.ProgressBar.Value = $ProgressValue
208 | $UI.TextBlock2.Text = "Windows Setup Progress $ProgressValue%"
209 | }
210 | $DispatcherTimer2 = New-Object -TypeName System.Windows.Threading.DispatcherTimer
211 | $DispatcherTimer2.Interval = [TimeSpan]::FromSeconds(1)
212 | $DispatcherTimer2.Add_Tick($TimerCode2)
213 |
214 | # Event: Window loaded
215 | $UI.Window.Add_Loaded({
216 |
217 | # Activate the window to bring it to the fore
218 | $This.Activate()
219 |
220 | # Fill the screen
221 | $This.Left = $Bounds.Left
222 | $This.Top = $Bounds.Top
223 | $This.Height = $Bounds.Height
224 | $This.Width = $Bounds.Width
225 |
226 | # Hide the taskbar
227 | [TaskBar]::Hide()
228 |
229 | # Hide the mouse cursor
230 | [System.Windows.Forms.Cursor]::Hide()
231 |
232 | # Keep Display awake
233 | [DisplayState]::KeepDisplayAwake()
234 |
235 | # Begin animations
236 | $UI.MaintextBlock.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
237 | $UI.TextBlock2.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
238 | $UI.TextBlock3.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
239 | $UI.TextBlock4.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
240 | $UI.ProgressRing.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
241 | $UI.ProgressBar.BeginAnimation([System.Windows.Controls.TextBlock]::OpacityProperty,$FadeinAnimation)
242 | $ColourBrighterAnimation.Add_Completed({
243 | $UI.Window.Background.BeginAnimation([System.Windows.Media.SolidColorBrush]::ColorProperty,$ColourDarkerAnimation)
244 | })
245 | $UI.Window.Background.BeginAnimation([System.Windows.Media.SolidColorBrush]::ColorProperty,$ColourBrighterAnimation)
246 |
247 | })
248 |
249 |
250 |
251 | # Event: Window closing (for testing)
252 | $UI.Window.Add_Closing({
253 |
254 | # Restore the taskbar
255 | [Taskbar]::Show()
256 |
257 | # Restore the mouse cursor
258 | [System.Windows.Forms.Cursor]::Show()
259 |
260 | # Cancel keeping the display awake
261 | [DisplayState]::Cancel()
262 |
263 | $Stopwatch.Stop()
264 | $DispatcherTimer.Stop()
265 | $DispatcherTimer2.Stop()
266 |
267 | })
268 |
269 | # Event: Close the window on right-click (for testing)
270 | #$UI.Window.Add_MouseRightButtonDown({
271 | #
272 | # $This.Close()
273 | #
274 | #})
275 |
276 | # Display the window
277 | $DispatcherTimer.Start()
278 | $DispatcherTimer2.Start()
279 | $UI.Window.ShowDialog()
280 |
--------------------------------------------------------------------------------
/v1/Invoke-PSScriptAsUser.ps1:
--------------------------------------------------------------------------------
1 | # Executes a PowerShell script in the context of the currently active user
2 |
3 | Param($File)
4 |
5 | # CSharp code for creating a process in the user context
6 | # Thanks to http://rzander.azurewebsites.net/create-a-process-as-loggedon-user/
7 | # and https://github.com/murrayju/CreateProcessAsUser
8 | $Source = @"
9 | using System;
10 | using System.Runtime.InteropServices;
11 |
12 | namespace Runasuser
13 | {
14 | public static class ProcessExtensions
15 | {
16 | #region Win32 Constants
17 |
18 | private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
19 | private const int CREATE_NO_WINDOW = 0x08000000;
20 |
21 | private const int CREATE_NEW_CONSOLE = 0x00000010;
22 |
23 | private const uint INVALID_SESSION_ID = 0xFFFFFFFF;
24 | private static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
25 |
26 | #endregion
27 |
28 | #region DllImports
29 |
30 | [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
31 | private static extern bool CreateProcessAsUser(
32 | IntPtr hToken,
33 | String lpApplicationName,
34 | String lpCommandLine,
35 | IntPtr lpProcessAttributes,
36 | IntPtr lpThreadAttributes,
37 | bool bInheritHandle,
38 | uint dwCreationFlags,
39 | IntPtr lpEnvironment,
40 | String lpCurrentDirectory,
41 | ref STARTUPINFO lpStartupInfo,
42 | out PROCESS_INFORMATION lpProcessInformation);
43 |
44 | [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
45 | private static extern bool DuplicateTokenEx(
46 | IntPtr ExistingTokenHandle,
47 | uint dwDesiredAccess,
48 | IntPtr lpThreadAttributes,
49 | int TokenType,
50 | int ImpersonationLevel,
51 | ref IntPtr DuplicateTokenHandle);
52 |
53 | [DllImport("userenv.dll", SetLastError = true)]
54 | private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
55 |
56 | [DllImport("userenv.dll", SetLastError = true)]
57 | [return: MarshalAs(UnmanagedType.Bool)]
58 | private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
59 |
60 | [DllImport("kernel32.dll", SetLastError = true)]
61 | private static extern bool CloseHandle(IntPtr hSnapshot);
62 |
63 | [DllImport("kernel32.dll")]
64 | private static extern uint WTSGetActiveConsoleSessionId();
65 |
66 | [DllImport("Wtsapi32.dll")]
67 | private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
68 |
69 | [DllImport("wtsapi32.dll", SetLastError = true)]
70 | private static extern int WTSEnumerateSessions(
71 | IntPtr hServer,
72 | int Reserved,
73 | int Version,
74 | ref IntPtr ppSessionInfo,
75 | ref int pCount);
76 |
77 | #endregion
78 |
79 | #region Win32 Structs
80 |
81 | private enum SW
82 | {
83 | SW_HIDE = 0,
84 | SW_SHOWNORMAL = 1,
85 | SW_NORMAL = 1,
86 | SW_SHOWMINIMIZED = 2,
87 | SW_SHOWMAXIMIZED = 3,
88 | SW_MAXIMIZE = 3,
89 | SW_SHOWNOACTIVATE = 4,
90 | SW_SHOW = 5,
91 | SW_MINIMIZE = 6,
92 | SW_SHOWMINNOACTIVE = 7,
93 | SW_SHOWNA = 8,
94 | SW_RESTORE = 9,
95 | SW_SHOWDEFAULT = 10,
96 | SW_MAX = 10
97 | }
98 |
99 | private enum WTS_CONNECTSTATE_CLASS
100 | {
101 | WTSActive,
102 | WTSConnected,
103 | WTSConnectQuery,
104 | WTSShadow,
105 | WTSDisconnected,
106 | WTSIdle,
107 | WTSListen,
108 | WTSReset,
109 | WTSDown,
110 | WTSInit
111 | }
112 |
113 | [StructLayout(LayoutKind.Sequential)]
114 | private struct PROCESS_INFORMATION
115 | {
116 | public IntPtr hProcess;
117 | public IntPtr hThread;
118 | public uint dwProcessId;
119 | public uint dwThreadId;
120 | }
121 |
122 | private enum SECURITY_IMPERSONATION_LEVEL
123 | {
124 | SecurityAnonymous = 0,
125 | SecurityIdentification = 1,
126 | SecurityImpersonation = 2,
127 | SecurityDelegation = 3,
128 | }
129 |
130 | [StructLayout(LayoutKind.Sequential)]
131 | private struct STARTUPINFO
132 | {
133 | public int cb;
134 | public String lpReserved;
135 | public String lpDesktop;
136 | public String lpTitle;
137 | public uint dwX;
138 | public uint dwY;
139 | public uint dwXSize;
140 | public uint dwYSize;
141 | public uint dwXCountChars;
142 | public uint dwYCountChars;
143 | public uint dwFillAttribute;
144 | public uint dwFlags;
145 | public short wShowWindow;
146 | public short cbReserved2;
147 | public IntPtr lpReserved2;
148 | public IntPtr hStdInput;
149 | public IntPtr hStdOutput;
150 | public IntPtr hStdError;
151 | }
152 |
153 | private enum TOKEN_TYPE
154 | {
155 | TokenPrimary = 1,
156 | TokenImpersonation = 2
157 | }
158 |
159 | [StructLayout(LayoutKind.Sequential)]
160 | private struct WTS_SESSION_INFO
161 | {
162 | public readonly UInt32 SessionID;
163 |
164 | [MarshalAs(UnmanagedType.LPStr)]
165 | public readonly String pWinStationName;
166 |
167 | public readonly WTS_CONNECTSTATE_CLASS State;
168 | }
169 |
170 | #endregion
171 |
172 | // Gets the user token from the currently active session
173 | private static bool GetSessionUserToken(ref IntPtr phUserToken)
174 | {
175 | var bResult = false;
176 | var hImpersonationToken = IntPtr.Zero;
177 | var activeSessionId = INVALID_SESSION_ID;
178 | var pSessionInfo = IntPtr.Zero;
179 | var sessionCount = 0;
180 |
181 | // Get a handle to the user access token for the current active session.
182 | if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref sessionCount) != 0)
183 | {
184 | var arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
185 | var current = pSessionInfo;
186 |
187 | for (var i = 0; i < sessionCount; i++)
188 | {
189 | var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
190 | current += arrayElementSize;
191 |
192 | if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
193 | {
194 | activeSessionId = si.SessionID;
195 | }
196 | }
197 | }
198 |
199 | // If enumerating did not work, fall back to the old method
200 | if (activeSessionId == INVALID_SESSION_ID)
201 | {
202 | activeSessionId = WTSGetActiveConsoleSessionId();
203 | }
204 |
205 | if (WTSQueryUserToken(activeSessionId, ref hImpersonationToken) != 0)
206 | {
207 | // Convert the impersonation token to a primary token
208 | bResult = DuplicateTokenEx(hImpersonationToken, 0, IntPtr.Zero,
209 | (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
210 | ref phUserToken);
211 |
212 | CloseHandle(hImpersonationToken);
213 | }
214 |
215 | return bResult;
216 | }
217 |
218 | public static bool StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true)
219 | {
220 | var hUserToken = IntPtr.Zero;
221 | var startInfo = new STARTUPINFO();
222 | var procInfo = new PROCESS_INFORMATION();
223 | var pEnv = IntPtr.Zero;
224 | int iResultOfCreateProcessAsUser;
225 |
226 | startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
227 |
228 | try
229 | {
230 | if (!GetSessionUserToken(ref hUserToken))
231 | {
232 | throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");
233 | }
234 |
235 | uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
236 | startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
237 | startInfo.lpDesktop = "winsta0\\default";
238 |
239 | if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
240 | {
241 | throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");
242 | }
243 |
244 | if (!CreateProcessAsUser(hUserToken,
245 | appPath, // Application Name
246 | cmdLine, // Command Line
247 | IntPtr.Zero,
248 | IntPtr.Zero,
249 | false,
250 | dwCreationFlags,
251 | pEnv,
252 | workDir, // Working directory
253 | ref startInfo,
254 | out procInfo))
255 | {
256 | iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
257 | throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed. Error Code -" + iResultOfCreateProcessAsUser);
258 | }
259 |
260 | iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
261 | }
262 | finally
263 | {
264 | CloseHandle(hUserToken);
265 | if (pEnv != IntPtr.Zero)
266 | {
267 | DestroyEnvironmentBlock(pEnv);
268 | }
269 | CloseHandle(procInfo.hThread);
270 | CloseHandle(procInfo.hProcess);
271 | }
272 |
273 | return true;
274 | }
275 |
276 | }
277 | }
278 |
279 |
280 | "@
281 |
282 | # Load the custom type
283 | Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition $Source -Language CSharp -ErrorAction Stop
284 |
285 | # Run PS as user to display the message box
286 | [Runasuser.ProcessExtensions]::StartProcessAsCurrentUser("$env:windir\System32\WindowsPowerShell\v1.0\Powershell.exe"," -ExecutionPolicy Bypass -WindowStyle Hidden -File $PSScriptRoot\$File")
--------------------------------------------------------------------------------