Avvio di un processo nella sessione dell’utente da un servizio

In Windows Vista / 7/2008 / 2008R2, è ansible avviare un processo nella sessione di un utente da un servizio? Nello specifico, la sessione locale sarebbe molto utile.

Tutto quello che ho letto sembra dire che non è ansible, ma ho pensato di chiedere qui prima di rinunciare completamente.

Sto codificando in VB.NET, ma prenderò suggerimenti in qualsiasi cosa.

È davvero ansible Il problema principale che si ha è che Windows dovrebbe essere visto come un server terminal e una sessione utente come una sessione remota. Il servizio dovrebbe essere in grado di avviare un processo eseguito nella sessione remota che appartiene all’utente.

A proposito, se si scrive un servizio che gira sotto Windows XP che non viene aggiunto a un dominio e si triggers la commutazione rapida dell’utente, è ansible avere gli stessi problemi per avviare un processo in esecuzione sul secondo (terzo e così via) desktop degli utenti registrati.

Spero che tu abbia un token utente, che ricevi ad esempio per quanto riguarda la rappresentazione o hai un dwSessionId di sessione. Se non ce l’hai puoi provare a utilizzare qualche funzione WTS (API dei servizi Desktop remoto http://msdn.microsoft.com/en-us/library/aa383464.aspx , ad esempio WTSEnumerateProcesses o WTSGetActiveConsoleSessionId ) o LSA-API per trovare la sessione utenti corrispondente ( LsaEnumerateLogonSessions vedere http://msdn.microsoft.com/en-us/library/aa378275.aspx e LsaGetLogonSessionData vedere http://msdn.microsoft.com/en-us/library/aa378290. aspx ) o ProcessIdToSessionId (consultare http://msdn.microsoft.com/en-us/library/aa382990.aspx ).

È ansible utilizzare la funzione GetTokenInformation con il parametro TokenSessionId (consultare http://msdn.microsoft.com/en-us/library/aa446671.aspx ) per ricevere l’id di sessione dwSessionId della sessione degli utenti se si conosce il token utente hClient .

 BOOL bSuccess; HANDLE hProcessToken = NULL, hNewProcessToken = NULL; DWORD dwSessionId, cbReturnLength; bSuccess = GetTokenInformation (hClient, TokenSessionId, &dwSessionId, sizeof(DWORD), &cbReturnLength); bSuccess = OpenProcessToken (GetCurrentProcess(), MAXIMUM_ALLOWED, &hProcessToken); bSuccess = DuplicateTokenEx (hProcessToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hNewProcessToken); EnablePrivilege (SE_TCB_NAME); bSuccess = SetTokenInformation (hNewProcessToken, TokenSessionId, &dwSessionId, sizeof(DWORD)); bSuccess = CreateProcessAsUser (hNewProcessToken, NULL, szCommandToExecute, ...); 

Questo codice solo uno schema. EnablePrivilege è una funzione semplice utilizzata AdjustTokenPrivileges per abilitare il privilegio SE_TCB_NAME (consultare http://msdn.microsoft.com/en-us/library/aa446619.aspx come modello). È importante che il processo da cui si avvia un processo disponga del privilegio TCB, ma se il servizio viene eseguito con il Sistema locale si dispone di autorizzazioni sufficienti. A proposito, il frammento di codice seguente funziona non solo con l’account di sistema locale, ma l’account deve avere il privilegio SE_TCB_NAME per poter cambiare la sessione corrente del server terminal.

Un’altra osservazione. Nel codice sopra iniziamo un nuovo processo con lo stesso account del processo corrente (ad esempio Sistema locale). Si modifica la modifica di un codice per utilizzare un altro account, ad esempio il token utente hClient . È importante avere solo un primary token . Se si dispone di un token di rappresentazione, è ansible convertirlo nel token principale esattamente come nel codice sopra.

Nella struttura STARTUPINFO utilizzata in CreateProcessAsUser dovresti usare lpDesktop = WinSta0 \ Default “.

A seconda delle tue esigenze, potrebbe essere anche necessario utilizzare CreateEnvironmentBlock per creare un nuovo blocco di ambiente che passerai al nuovo processo.

Vi consiglio anche di leggere Come garantire che la finestra del processo avviata da Process.Start (ProcessStartInfo) abbia il focus su tutti i moduli? dove descrivo come forzare che il processo venga avviato in primo piano sul desktop degli utenti.

Se aiuta, mi trovavo di fronte a un problema simile, ma volevo una soluzione puramente PowerShell.

Ho messo insieme pezzi di altri siti e ho trovato questo:

 function Invoke-CommandInSession { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ScriptBlock] $expression ) $commandLine = “powershell“ ## Convert the command into an encoded command for PowerShell $commandBytes = [System.Text.Encoding]::Unicode.GetBytes($expression) $encodedCommand = [Convert]::ToBase64String($commandBytes) $args = “-Output XML -EncodedCommand $encodedCommand” $action = New-ScheduledTaskAction -Execute $commandLine -Argument $args $setting = New-ScheduledTaskSettingsSet -DeleteExpiredTaskAfter ([Timespan]::Zero) $trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date) + ([Timespan]::FromSeconds(5))) $task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $setting Register-ScheduledTask "Invoke-CommandInSession - $([Guid]::NewGuid())" -InputObject $task } 

Sì, è un po ‘strano, ma funziona – e soprattutto è ansible chiamarlo da ps remoting

Può essere fatto, ma non è considerato una buona pratica per i servizi di interagire direttamente con le sessioni degli utenti in quanto può creare seri problemi di sicurezza.

http://support.microsoft.com/kb/327618

Un approccio migliore consiste nel creare 2 programmi, un servizio di backend e un programma di interfaccia utente del client front-end. Il backend del servizio viene eseguito sempre ed espone le sue operazioni utilizzando WCF (ad esempio). Il programma client può essere eseguito all’avvio della sessione di un utente.

Sì, utilizzando CreateProcessAsUser puoi farlo. MSDN ha articoli di esempio e ci sono alcuni avvertimenti.

Subverting Vista UAC in entrambe le architetture a 32 e 64 bit

Il codice fornito è destinato a Vista, ma funziona anche su Win7 e Win10