Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Вызов консольной команды из Powershell и получение результата. Проблема с кириллицей. (http://forum.oszone.net/showthread.php?t=341946)

densan 26-08-2019 10:35 2885460

Вызов консольной команды из Powershell и получение результата. Проблема с кириллицей.
 
Здравствуйте.
В одном скрипте есть функция, которая должна делать определение пользователя работающего на удаленном ПК.
Нужно чтобы определялись пользователи залогиненные с консоли, через RDP, через инструмент Подключение к виртуальной машине (Hyper-V).
Все эти данные показывает утилита qwinsta, которая присутствует и в W10 и в W7. Но есть проблема: в сети присутствуют ПК как с En так и Ru локализацией.
При запуске на кириллических системах через ISE

Код:

$Results = qwinsta /server:$env:COMPUTERNAME
или
Код:

Start-Process -filepath 'qwinsta.exe' -argumentlist "/server:$env:COMPUTERNAME" -RedirectStandardOutput "C:\temp\StandardOutput.txt"
$Result = get-content "C:\temp\StandardOutput.txt"

в результате получаю крякозябры.

При запуске в консоли PS - все красиво, но уверен что часть сотрудников для кого пишется скрипт будут его запускать через ISE.

Подскажите есть какое-то решение по получению вывода от консольных приложений в читаемом варианте или корректная перекодировка на лету?

Как вариант можно через
Код:

$result = Invoke-Command -computername ИМЯ ПК -ScriptBlock {
 здесь будут команды по получении данных из qwinsta, их парсингу и возврат
}

Хочется сделать универсальное решение, чтобы в дальнейшем его использовать.

Charg 26-08-2019 12:15 2885489

Идеальное решение - не использовать старые утилиты, которые в результате выдают текст.
Powershell - штука объектно-ориентированная, так что работать нужно со свойствами объектов а не с текстом.

Объясни еще раз что конкретно делает эта qwinsta, наверняка в powershell есть аналог.

Я например недавно писал скрипт который коннектится к пользовательскому компьютеру, нюхает текущего залогиненного пользователя, а потом завершает рдп сеанс на rds-ферме и чистит кэш 1с. Конкретно часть "дай логин залогиненного пользователя" выглядит так:
Цитата:

$activeUsername = Invoke-Command -ComputerName $pcname -ScriptBlock {(Get-WMIObject -class Win32_ComputerSystem).UserName.Split('\')[1]}
(Get-WMIObject -class Win32_ComputerSystem).UserName выводит логин в виде OFFICE\username (OFFICE это название моего домена), мне надо было убрать офис потому там еще сплит и прочая муть.

Ageron 26-08-2019 12:23 2885492

ммм, старая проблема ISE :)

добавьте строчку в код
[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding("cp866")

Charg 26-08-2019 12:26 2885495

Ageron, так придется каждый раз используя старые утилиты вспоминать про наличие этого нюанса и синтаксис решения и добавлять к скрипту. Не то чтобы это часто встречалось, но всё-таки "рассово-верное" решение - переходить на современные инструменты, тем более если они существуют и отлично работают, согласен?


Сразу же предвосхищая вопрос "а почему тогда get-wmiobject а не get-ciminstance - а вот потому что быстрее:
Скрытый текст

Iska 26-08-2019 12:41 2885500

Цитата:

Цитата densan
но уверен что часть сотрудников для кого пишется скрипт будут его запускать через ISE. »

Проверяйте при запуске имя хоста, и для ISE выводите красивое сообщение, что скрипт не рассчитан на работу под ним (ISE — это, вообще-то, среда для редактирования и отладки скриптов, не должно быть скриптов в продакшене, предназначенных для исполнения в ISE).

densan 26-08-2019 13:55 2885509

Использую qwinsta, т.к.

Код:

Get-WMIObject -Class Win32_ComputerSystem -ComputerName |Select-Object name, Username |ft -wrap
показывает пользователей, которые вошли с консоли (работают за самим компьютером), она не показывает пользователей вошедших на ПК через RDP или через Подключение к виртуальной машине (Hyper-V), т.к. часть компьютеров виртуальные.

Это можно обойти, если получить все запущенные explorer.exe и вывести пользователей под которыми они запущены, но это не даст имя активного пользователя - того, чей сеанс активен в данный момент.

Если подскажите как в PS получить имя пользователя, чей сеанс на ПК активен в данный момент - буду благодарен.

YuS_2 26-08-2019 13:55 2885510

Цитата:

Цитата Charg
Сразу же предвосхищая вопрос "а почему тогда get-wmiobject а не get-ciminstance - а вот потому что быстрее »

не показатель, это измерение, при каждом запуске, будет выводить различные результаты... тут требуется статистически набранное среднее значение...
И ещё: а результат из PS -v 7.0, можно глянуть?

DJ Mogarych 26-08-2019 16:52 2885535

Цитата:

Цитата Charg
Invoke-Command -ComputerName $pcname -ScriptBlock {(Get-WMIObject -class Win32_ComputerSystem).UserName.Split('\')[1]} »

Есть параметр -Computername:
Код:

gwmi Win32_ComputerSystem -ComputerName $pcname

densan 26-08-2019 17:21 2885539

в общем через ...., но решил

Код:

            $LogonUser = Invoke-Command -Session $session -ScriptBlock {(Get-WMIObject -Class Win32_ComputerSystem).Username}
            # про параметр -Computername знаю, но я ранее создаю сессию к ПК, проверяю её на доступность, поэтому мне удобнее/быстрее так.
            if ( [string]::IsNullOrEmpty($LogonUser) ) {
                # не получили username залогиненого пользователя
                # возможно пользователь работает по RDP или сессия не активна
                $Username = Invoke-Command -Session $session -ScriptBlock {
                    cmd /c "qwinsta /server:$env:COMPUTERNAME" |Out-File c:\temp\1.txt -Encoding default
                    $queryResults = Get-Content c:\temp\1.txt -Encoding oem |  foreach { (($_.trim() -replace "\s+",","))} | ConvertFrom-Csv
                    ForEach ($queryResult in $queryResults) {
                        if ($queryResult.СТАТУС -eq 'Активно') {
                            $RDPUser = $queryResult.ПОЛЬЗОВАТЕЛЬ
                        }
                    }
                    Return $RDPUser
                }
               
            } else {
                $Username = $LogonUser.Split("\")[1]
            }

У меня возник вопрос: результаты я помещаю в
Код:

$Report += New-Object PSObject -Property @{Computername = $Computername; UserName = $Username; FIO = $ADUser.Name; ipPhone = $ADUser.ipPhone; mobile = $ADUser.mobile; telephoneNumber = $ADUser.telephoneNumber;}
При выводе $Report как можно указать порядок столбцов, который мне нужен: Computername, UserName, FIO ...

YuS_2 26-08-2019 17:39 2885541

Цитата:

Цитата densan
При выводе $Report как можно указать порядок столбцов, который мне нужен »

Код:

$report|select Computername, UserName, FIO ...

Iska 26-08-2019 17:53 2885543

densan, а зачем Вам вообще промежуточный текстовый файл:
Код:

cmd /c "qwinsta /server:$env:COMPUTERNAME" |Out-File c:\temp\1.txt -Encoding default
$queryResults = Get-Content c:\temp\1.txt …

?! Можно же просто запуск-чтение стандартного потока вывода, например, пользовать. Наподобие:
Скрытый текст
Код:

$oProcess = New-Object -TypeName 'System.Diagnostics.Process'

$oProcess.StartInfo.FileName              = 'qwinsta.exe'
$oProcess.StartInfo.Arguments              = "/server:$env:COMPUTERNAME"
$oProcess.StartInfo.CreateNoWindow        = $true
$oProcess.StartInfo.UseShellExecute        = $false
$oProcess.StartInfo.RedirectStandardOutput = $true

if($oProcess.Start()) {
    $oProcess.WaitForExit()
    Write-Host $($oProcess.StandardOutput.ReadToEnd()) -ForegroundColor Cyan

    if($oProcess.ExitCode -eq 0) {
        Write-Host "OK." -ForegroundColor Green
    } else {
        Write-Host "Error. ExitCode: $($oProcess.ExitCode)" -ForegroundColor Red
    }
}


Не?

densan 27-08-2019 09:32 2885581

В сети безопасники включили для PS режим CLM, часть функционала PS заблокирована.
Код:

New-Object : Не удается создать тип. В этом языковом режиме поддерживаются только основные типы.
Чтобы не проверять наличие каталога и права на запись скорректировал скрипт на
Код:

                    $tmp = New-TemporaryFile
                    cmd /c "qwinsta /server:$env:COMPUTERNAME" |Out-File $tmp.FullName -Encoding default
                    $queryResults = Get-Content $tmp.FullName -Encoding oem |  foreach { (($_.trim() -replace "\s+",","))} | ConvertFrom-Csv


Iska 27-08-2019 16:06 2885636

densan, в любом случае — зачем Вам вызов cmd /c? Мне кажется, что он тут лишний, не?

densan 27-08-2019 16:44 2885650

Спасибо, действительно конструкция без cmd /c работает:
Код:

$tmp = New-TemporaryFile
$(qwinsta /server:$env:COMPUTERNAME) |Out-File $tmp.FullName -Encoding default
$queryResults = Get-Content $tmp.FullName -Encoding oem |  foreach { (($_.trim() -replace "\s+",","))} | ConvertFrom-Csv

Сейчас уже не припомню, но был случай, после которого я стал использовать cmd /c, возможно это было на древних версиях PS.


Время: 23:24.

Время: 23:24.
© OSzone.net 2001-