1
1
<#
2
+
3
+
4
+ I tried! I really tried. Sigh...
5
+
6
+ This mostly works but if your current user is a member of a group with elevated privileges
7
+ then the Command always starts elevated. Appears it's not possible to start a non-elevated
8
+ process from a privileged account on Windows!
9
+
10
+
11
+
2
12
. SYNOPSIS
3
13
Restart the named process. This can be used to restart applications such as Outlook on a nightly
4
14
basis. Apps such as this tend to have memory leaks or become unstable over time when dealing with
@@ -51,10 +61,10 @@ To run the task as a specific user: important when restarting Outlook as it mus
51
61
the current user, otherwise it will run as admin and you can't click toast notification
52
62
53
63
> $password = ConvertTo-SecureString -AsPlainText <plainTextPassword>
54
- > Restart-App -Name outlook -Register `
55
- -command 'C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.EXE' `
56
- -StartTime '2am' -Delay '02:00:00' `
57
- -User '<username> ' -Password $password
64
+ > Restart-App -Name outlook -Register -command 'C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.EXE' `
65
+ -User $env:username -Password $password -StartTime '2am' -Delay '02:00:00'
66
+
67
+ For quick testing, use: -Delay '00:00:05 ' -StartTime (get-date).addseconds(5)
58
68
#>
59
69
60
70
# CmdletBinding adds -Verbose functionality, SupportsShouldProcess adds -WhatIf
@@ -69,6 +79,7 @@ param (
69
79
[string ] $User ,
70
80
[System.Security.SecureString ] $Password ,
71
81
[switch ] $Register ,
82
+ [switch ] $Unregister ,
72
83
[switch ] $GetCommand
73
84
)
74
85
@@ -96,77 +107,146 @@ Begin
96
107
$process = (Get-Process $Name - ErrorAction:SilentlyContinue)
97
108
if ($process -ne $null )
98
109
{
99
- # get the commandline from the process, strip off quotes
100
- $script :cmd = (Get-CimInstance win32_process - filter (" ProcessID={0}" -f $process.id )).CommandLine.Replace(' "' , ' ' )
101
- Write-Host " ... found process $Name running $cmd "
110
+ try
111
+ {
112
+ # get the commandline from the process, strip off quotes
113
+ $script :cmdline = (Get-CimInstance win32_process `
114
+ - filter (" ProcessID={0}" -f $process.id )).CommandLine.Replace(' "' , ' ' )
102
115
103
- # terminating instead of graceful shutdown because can't connect using this:
104
- # something funny about 32/64 or elevated process or just whatever
105
- # $outlook = [Runtime.Interopservices.Marshal]::GetActiveObject('Outlook.Application')
116
+ Log " ... terminating process $Name running $cmdline "
106
117
107
- Write-Host " ... terminating process $Name "
108
- $process.Kill ()
109
- $process = $null
110
- Start-Sleep - s $delay
111
- }
118
+ # terminating instead of graceful shutdown because can't connect using this:
119
+ # GetActiveObject undefined in pwsh Core. Any other way to connect?
120
+ # $outlook = [Runtime.Interopservices.Marshal]::GetActiveObject('Outlook.Application')
121
+ # $outlook.Quit()
122
+
123
+ $process.Kill ()
124
+ $process = $null
125
+
126
+ Log " sleeping $ ( $delay.ToString ()) "
127
+ Start-Sleep - Duration $delay
128
+ }
129
+ catch
130
+ {
131
+ Log " *** error stopping $Name "
132
+ Log " *** $ ( $_ ) "
133
+ }
134
+ }
112
135
else
113
136
{
114
- Write-Host " ... $Name process not found"
137
+ Log " ... $Name process not found"
115
138
}
116
139
}
117
140
118
141
119
142
function Startup
120
143
{
121
- if (! $cmd ) { $cmd = $Command }
122
- if (! $cmd )
144
+ Log " ... starting $Name "
145
+
146
+ $credfile = " C:\Users\$User \$Name `.xml"
147
+ if (Test-Path $credfile )
123
148
{
124
- Write-Host " *** No command specified to start $Name " - ForegroundColor Yellow
125
- return
149
+ try
150
+ {
151
+ $credential = Import-Clixml $credfile
152
+
153
+ # TODO: Remove this line:
154
+ # Remove-Item -Path $credfile -Force
155
+
156
+ Log " ... running as $ ( $credential.Username ) with provided credentials"
157
+
158
+ if ($Arguments )
159
+ {
160
+ Log " ... starting -Command `" $Command `" -Arguments `" $Arguments `" "
161
+ Invoke-Command - Credential $credential - ComputerName $env: ComputerName `
162
+ - ScriptBlock { & $Command $Arguments }
163
+ }
164
+ else
165
+ {
166
+ Log " ... starting -Command `" $Command `" "
167
+
168
+ # runas /machine:x86 /trustlevel:0x20000 "C:\Windows\sysWOW64\cmd.exe /c `"$Command`""
169
+
170
+ # Invoke-Command -Credential $credential -ComputerName $env:ComputerName `
171
+ # -ScriptBlock { & $Command }
172
+
173
+ Log ' ... started? elevated?'
174
+ }
175
+ }
176
+ catch
177
+ {
178
+ Log " *** error starting $Name "
179
+ Log " *** $ ( $_ ) "
180
+ }
181
+ }
182
+ else
183
+ {
184
+ Log " ... could not file $credfile , aborting"
126
185
}
127
-
128
- Write-Host " ... starting $Name "
129
- Write-Host " ... $cmd $Arguments "
130
-
131
- Invoke-Command - ScriptBlock { & $cmd $Arguments }
132
186
}
133
187
134
188
135
189
function RegisterTask
136
190
{
137
191
$span = $delay.ToString ()
138
- $cmd = " Restart-App -Name '$Name ' -Command '$Command ' -Arguments '$Arguments ' -delay '$span ') "
192
+ $cmd = " Restart-App -Name '$Name ' -Command '$Command ' -Arguments '$cargs ' -User $User - delay '$span '"
139
193
140
- $trigger = New-ScheduledTaskTrigger - Daily - At 2am;
194
+ $trigger = New-ScheduledTaskTrigger - Daily - At $StartTime
141
195
$action = New-ScheduledTaskAction - Execute ' pwsh' - Argument " -Command "" $cmd "" "
142
196
143
197
$task = Get-ScheduledTask - TaskName " Restart $Name " - ErrorAction:SilentlyContinue
144
198
if ($task -eq $null )
145
199
{
146
200
Write-Host " ... creating scheduled task 'Restart $Name '"
147
201
148
- if ($User -and $Password )
149
- {
150
- $plainPwd = (New-Object System.Management.Automation.PSCredential `
151
- - ArgumentList $User , $Password ).GetNetworkCredential().Password
202
+ $credential = New-Object PSCredential($User , $Password )
203
+ $credential | Export-Clixml - Path " C:\Users\$User \$Name `.xml" - Force
152
204
153
- Register-ScheduledTask - Action $action - Trigger $trigger - TaskName " Restart $Name " ` `
154
- - User $User - Password $plainPwd ` | Out-Null
155
- }
156
- else
157
- {
158
- Register-ScheduledTask - Action $action - Trigger $trigger - TaskName " Restart $Name " `
159
- - RunLevel Highest | Out-Null
160
- }
205
+ # $credential = (New-Object System.Management.Automation.PSCredential `
206
+ # -ArgumentList $User, $Password).GetNetworkCredential()
207
+
208
+ $plainPwd = ($credential ).GetNetworkCredential().Password
209
+
210
+ Register-ScheduledTask - Action $action - Trigger $trigger - TaskName " Restart $Name " `
211
+ - User $User - Password $plainPwd | Out-Null
161
212
}
162
213
else
163
214
{
164
215
Write-Host " ... scheduled task 'Restart $Name ' is already registered"
165
216
}
166
217
}
218
+
219
+
220
+ function UnregisterTask
221
+ {
222
+ $taskname = " Restart $Name "
223
+ $info = get-scheduledtaskinfo - taskname $taskName - ErrorAction:SilentlyContinue
224
+ if ($info )
225
+ {
226
+ Write-Host " ... unregistering scheduled task '$taskName '"
227
+ Unregister-ScheduledTask - TaskName $taskName - Confirm:$false
228
+ }
229
+ else
230
+ {
231
+ Write-Host " ... scheduled task '$taskName ' is not found"
232
+ }
233
+ }
234
+
235
+
236
+ function Log
237
+ {
238
+ param ([string ] $text )
239
+ $text | Out-File - FilePath $LogFile - Append
240
+ }
167
241
}
168
242
Process
169
243
{
244
+ if ($Name -and $Unregister )
245
+ {
246
+ UnregisterTask
247
+ return
248
+ }
249
+
170
250
if ($GetCommand )
171
251
{
172
252
GetCommandLine
@@ -191,6 +271,12 @@ Process
191
271
return
192
272
}
193
273
274
+ $script :LogFile = Join-Path $env: TEMP ' restart-app.log'
275
+ # reset the log file
276
+ " starting at $ ( Get-Date ) " | Out-File - FilePath $LogFile
277
+
194
278
Shutdown
195
279
Startup
280
+
281
+ Log ' done'
196
282
}
0 commit comments