none
Не видно владельца процесса RRS feed

  • Вопрос

  • Добрый день, столкнулся с проблемой при получении информации о владельце запущенного процесса. 

    Есть задача написать скрипт, который при запуске проверяет наличие запущенного процесса "anyprocess.exe" и, если процесс уже запущен то пользователю сообщается имя пользователя под которым запущен данный процесс, в противном случае запускается программа "Anyprocess.exe".

    Был написан vbs скрипт следущего содержания:

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" _
        & strComputer & "\root\cimv2")
    
    Set colProcesses = objWMIService.ExecQuery( _
        "Select Name From Win32_Process " _
        & "Where Name = 'Anyprocess.exe'")
    
    
    
    If colProcesses.Count = 0 Then
      Set objShell = Wscript.CreateObject("Wscript.Shell")
      Set objEnv = objShell.Environment("Process")
      objShell.Run """" + objEnv("ProgramFiles (x86)") + "\Any\Anyprocess.exe"""
    Else
    For Each objProcess in colProcesses
    
        objProcess.GetOwner strUserName, strUserDomain
      Wscript.Echo "Process " & objProcess.Name & " is owned by "  & strUserDomain & "\" & strUserName & "."
    next
    End If

    При попытке пользователя повторно запустить приложение получаю сообщение

    Пользователь test не имеет административных прав, все работает нормально. НО!

    Если процесс запустил другой пользователь в своем сеансе, а пользователь test пытается запустить программу, то получается так:

    Если я правильно понимаю, то не хватает каких то прав.

    Подскажите куда смотреть.

    Права Администратора пользователю давать нельзя, система windows 2012R2.

    Не силен в powershell, если есть работающий вариант на powershell - подскажите.

    25 апреля 2019 г. 1:18

Ответы

  • Всем спасибо! Сделал так.

    $ErrorActionPreference = "SilentlyContinue"
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
    
    if ( -not (get-process | where {$_.ProcessName -eq 'elko'}))
    { 
       'not run. Start Running'
       Start-Process -FilePath 'C:\elco\elko.exe'
    
    }
    else
    {
    
    $UserNameIDArray = @()
    (qwinsta.exe) -split '\r\n' | foreach {
       $_ -match '(?''UserName''\w+)\s+(?''id''\d+)\s+' | Out-Null
       $obj = New-Object psobject
       $obj | Add-Member -MemberType NoteProperty -Name ID -Value $Matches['id']
       $obj | Add-Member -MemberType NoteProperty -Name UserName -Value $Matches['UserName']
       $UserNameIDArray += $obj
       #Clear-Variable obj
    } # End Foreach
    
    $user =(
    Get-Process -Name elko | Select Name,Id,SessionId,@{l='UserName';e={($UserNameIDArray | Where id -eq $_.SessionId).username}}).username
    #write-host "Process elko running from user(s) : $user"
    
    Add-Type -TypeDefinition @"
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    public static class User32
    {
        [DllImport("user32.dll", CharSet=CharSet.Auto)]
            public static extern int MessageBox(
                IntPtr hWnd,
                String lpText,
                String lpCaption,
                int uType);
    }
    "@
    
    $MB_OKCANCEL =    0x00000001L
    $MB_ICONERROR =   0x00000010L
    $MB_SYSTEMMODAL = 0x00001000L
    
    $UserResponse = [Enum]::ToObject([System.Windows.Forms.DialogResult],[User32]::MessageBox(0,"Программа уже запущена пользователем $user","Инфо",$MB_SYSTEMMODAL+$MB_ICONERROR+$MB_OKCANCEL))
    Remove-Variable UserNameIDArray}
    

    Все работает корректно.

    • Помечено в качестве ответа Kryuchkov Andrey 29 апреля 2019 г. 3:13
    29 апреля 2019 г. 3:13

Все ответы

  • посмотрите мой пример кода из этого обсуждения и если он окажется для вас полезен проголосуйте пожалуйста за него

    The opinion expressed by me is not an official position of Microsoft

    • Предложено в качестве ответа Vector BCOModerator 25 апреля 2019 г. 12:41
    25 апреля 2019 г. 4:12
    Модератор
  • Спасибо за совет, но...

    Я попробовал такой скрипт:

    $owners = @{}
    gwmi win32_process |% {$owners[$_.handle] = $_.getowner().user}
    
    get-process | select processname,Id,@{l="Owner";e={$owners[$_.id.tostring()]}}

    Из под пользователя без админских прав я получил следущий вывод:

    Как можно заметить, хозяев процессов запущенных не из под этого пользователя увидеть невозможно.

    От админа все ок:

    Видимо что-то с правами...

    Не знаю куда копать.

    25 апреля 2019 г. 6:27
  • прочтите пожалуйста комментарий целиком, следующие 2 кодблока как раз и описывают как найти конкретный процесс текущего пользователя (в моем сценарии мне нужно было кильнуть процесс конкретно этого пользователя), и список всех процессов со всеми пользователями

    The opinion expressed by me is not an official position of Microsoft

    25 апреля 2019 г. 6:58
    Модератор
  • Спасибо! сделал со скриптом:

    $UserNameIDArray = @()
    (qwinsta.exe) -split '\r\n' | foreach {
       $_ -match '(?''UserName''\w+)\s+(?''id''\d+)\s+' | Out-Null
       $obj = New-Object psobject
       $obj | Add-Member -MemberType NoteProperty -Name ID -Value $Matches['id']
       $obj | Add-Member -MemberType NoteProperty -Name UserName -Value $Matches['UserName']
       $UserNameIDArray += $obj
       Clear-Variable obj
    } # End Foreach
    
    Get-Process -Name elko | Select Name,Id,SessionId,@{l='UserName';e={($UserNameIDArray | Where id -eq $_.SessionId).username}}
    Получаю 

    Не могли бы Вы подсказать, как мне в переменную записать значение толбца username по процессу Elko? Сложноват скрипт для меня.


    25 апреля 2019 г. 9:24
  • перед началом последней строки напишите:

    $user =(

    вконце последней строки:

    ).username

    эта нехитрая конструкция запихнет значение параметра UserName в переменную $user

    Для того что бы убедиться что переменная не пустая можете добавить следующую строку:

    write-host "Process elko running from user(s) : $user"
    Учтите что переменная может содержать более одного значения если процесс запущен несколько раз (от одного или нескольких пользюков)


    The opinion expressed by me is not an official position of Microsoft

    25 апреля 2019 г. 12:36
    Модератор
  • Спасибо, что помогли разобраться!
    26 апреля 2019 г. 1:04
  • Дописал скрипт под свои нужды.

    if ( -not (get-process | where {$_.ProcessName -eq 'elko'}))
    { 
       'not run. Start Running'
       Start-Process -FilePath 'C:\elco\elko.exe'
    
    }
    else
    {
    
    $Global:UserNameIDArray = @()
    (qwinsta.exe) -split '\r\n' | foreach {
       $_ -match '(?''UserName''\w+)\s+(?''id''\d+)\s+' | Out-Null
       $obj = New-Object psobject
       $obj | Add-Member -MemberType NoteProperty -Name ID -Value $Matches['id']
       $obj | Add-Member -MemberType NoteProperty -Name UserName -Value $Matches['UserName']
       $UserNameIDArray += $obj
       Clear-Variable obj
    } # End Foreach
    $Global:user =(
    Get-Process -Name elko | Select Name,Id,SessionId,@{l='UserName';e={($UserNameIDArray | Where id -eq $_.SessionId).username}}).username
    #write-host "Process elko running from user(s) : $user"
    
    Add-Type -TypeDefinition @"
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    public static class User32
    {
        [DllImport("user32.dll", CharSet=CharSet.Auto)]
            public static extern int MessageBox(
                IntPtr hWnd,
                String lpText,
                String lpCaption,
                int uType);
    }
    "@
    
    $MB_OKCANCEL =    0x00000001L
    $MB_ICONERROR =   0x00000010L
    $MB_SYSTEMMODAL = 0x00001000L
    
    $UserResponse = [Enum]::ToObject([System.Windows.Forms.DialogResult],[User32]::MessageBox(0,"Программа уже запущена пользователем $user","Инфо",$MB_SYSTEMMODAL+$MB_ICONERROR+$MB_OKCANCEL))
    Remove-Variable UserNameIDArray}

    Сохранил скрипт run.ps1, написал батник следущего содержания:

    powershell -STA -File ./run.ps1
    
    

    В итоге, скрипт в среде powershell ISE Работает нормально, а через батник не работает корректно.

    если запустить скрипт через .bat 1 раз пока процесс elko.exe не существует, то запустится приложение elko.exe, повторный запуск, при работающем приложении elko выводит в консоль ошибку:

    В powershell ISE работает нормально.

    Замучился уже. Подскажите, пожалуйста, что не так-то?

    26 апреля 2019 г. 4:54
  • какая у вас версия powershell?

    по всей видимости qwinsta возвращает нечто странное или не возвращает вообще ничего, причин может быть несколько - кодировка что решается обновлением поша скажем до версии 5.1 или выполнение скрипта в поше х86 на х64 системе

    К слову, а зачем вам глобальные переменные?


    The opinion expressed by me is not an official position of Microsoft


    26 апреля 2019 г. 7:20
    Модератор
  • Обновил поша до 5.1, ситуация не изменилась. Запускал в режиме x86 - ничего.

    Странно, что работает в ISE... Может можно без массива выхватить имя сеанса пользователя под которым запускается процесс elko?

    Глобальная переменная была сделана в процессе попытки найти ошибку... от непонимания происходящего по-большому счету.

    26 апреля 2019 г. 10:13
  • создайте новый скрипт в ise в который скопируйте текст из этого обсуждения и пересохраните, если не заработает оставьте в скрипте только qwinsta.exe и покажите вывод

    при этом глобальные переменные не нужны и для отладки лучше оставьте только write-host без виндоформ


    The opinion expressed by me is not an official position of Microsoft

    26 апреля 2019 г. 13:17
    Модератор
  • Всем спасибо! Сделал так.

    $ErrorActionPreference = "SilentlyContinue"
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
    
    if ( -not (get-process | where {$_.ProcessName -eq 'elko'}))
    { 
       'not run. Start Running'
       Start-Process -FilePath 'C:\elco\elko.exe'
    
    }
    else
    {
    
    $UserNameIDArray = @()
    (qwinsta.exe) -split '\r\n' | foreach {
       $_ -match '(?''UserName''\w+)\s+(?''id''\d+)\s+' | Out-Null
       $obj = New-Object psobject
       $obj | Add-Member -MemberType NoteProperty -Name ID -Value $Matches['id']
       $obj | Add-Member -MemberType NoteProperty -Name UserName -Value $Matches['UserName']
       $UserNameIDArray += $obj
       #Clear-Variable obj
    } # End Foreach
    
    $user =(
    Get-Process -Name elko | Select Name,Id,SessionId,@{l='UserName';e={($UserNameIDArray | Where id -eq $_.SessionId).username}}).username
    #write-host "Process elko running from user(s) : $user"
    
    Add-Type -TypeDefinition @"
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    public static class User32
    {
        [DllImport("user32.dll", CharSet=CharSet.Auto)]
            public static extern int MessageBox(
                IntPtr hWnd,
                String lpText,
                String lpCaption,
                int uType);
    }
    "@
    
    $MB_OKCANCEL =    0x00000001L
    $MB_ICONERROR =   0x00000010L
    $MB_SYSTEMMODAL = 0x00001000L
    
    $UserResponse = [Enum]::ToObject([System.Windows.Forms.DialogResult],[User32]::MessageBox(0,"Программа уже запущена пользователем $user","Инфо",$MB_SYSTEMMODAL+$MB_ICONERROR+$MB_OKCANCEL))
    Remove-Variable UserNameIDArray}
    

    Все работает корректно.

    • Помечено в качестве ответа Kryuchkov Andrey 29 апреля 2019 г. 3:13
    29 апреля 2019 г. 3:13
  • закоментировав очистку переменной obj вы создали проблему если у вас первого пользователя распарсило а последующих нет то у вас появится масив одинаковых записей

    Выключив ошибки в первой строке вы получаете иллюзию что все работает корректно, хотя на самом деле вы просто не узнаете о том что, что-то не работает.

    Вообщем если вас устраивает, то ок, но я бы в прод среде этот скрипт не использовал


    The opinion expressed by me is not an official position of Microsoft

    30 апреля 2019 г. 3:19
    Модератор