Показать полную графическую версию : [решено] Вызов консольной команды из 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, их парсингу и возврат
}
Хочется сделать универсальное решение, чтобы в дальнейшем его использовать.
Идеальное решение - не использовать старые утилиты, которые в результате выдают текст.
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 это название моего домена), мне надо было убрать офис потому там еще сплит и прочая муть.
ммм, старая проблема ISE :)
добавьте строчку в код
[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding("cp866")
Ageron, так придется каждый раз используя старые утилиты вспоминать про наличие этого нюанса и синтаксис решения и добавлять к скрипту. Не то чтобы это часто встречалось, но всё-таки "рассово-верное" решение - переходить на современные инструменты, тем более если они существуют и отлично работают, согласен?
Сразу же предвосхищая вопрос "а почему тогда get-wmiobject а не get-ciminstance - а вот потому что быстрее:
https://i.imgur.com/KeiYYyu.png
но уверен что часть сотрудников для кого пишется скрипт будут его запускать через ISE. »
Проверяйте при запуске имя хоста, и для ISE выводите красивое сообщение, что скрипт не рассчитан на работу под ним (ISE — это, вообще-то, среда для редактирования и отладки скриптов, не должно быть скриптов в продакшене, предназначенных для исполнения в ISE).
Использую qwinsta, т.к.
Get-WMIObject -Class Win32_ComputerSystem -ComputerName |Select-Object name, Username |ft -wrap
показывает пользователей, которые вошли с консоли (работают за самим компьютером), она не показывает пользователей вошедших на ПК через RDP или через Подключение к виртуальной машине (Hyper-V), т.к. часть компьютеров виртуальные.
Это можно обойти, если получить все запущенные explorer.exe и вывести пользователей под которыми они запущены, но это не даст имя активного пользователя - того, чей сеанс активен в данный момент.
Если подскажите как в PS получить имя пользователя, чей сеанс на ПК активен в данный момент - буду благодарен.
Сразу же предвосхищая вопрос "а почему тогда get-wmiobject а не get-ciminstance - а вот потому что быстрее »
не показатель, это измерение, при каждом запуске, будет выводить различные результаты... тут требуется статистически набранное среднее значение...
И ещё: а результат из PS -v 7.0, можно глянуть?
DJ Mogarych
26-08-2019, 16:52
Invoke-Command -ComputerName $pcname -ScriptBlock {(Get-WMIObject -class Win32_ComputerSystem).UserName.Split('\')[1]} »
Есть параметр -Computername:
gwmi Win32_ComputerSystem -ComputerName $pcname
в общем через ...., но решил
$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 ...
При выводе $Report как можно указать порядок столбцов, который мне нужен »
$report|select Computername, UserName, FIO ...
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
}
}
Не?
В сети безопасники включили для 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
densan, в любом случае — зачем Вам вызов cmd /c? Мне кажется, что он тут лишний, не?
Спасибо, действительно конструкция без 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.
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.