Сотрудники службы техподдержки пользователей попросили написать PowerShell скрипт, позволяющий быстро получить скриншот рабочего стола пользователя с удаленного компьютера. При этом сотрудник HelpDesk не должен подключаться к компьютеру пользователя через графические средства удаленной поддержки (SCCM, Remote Assistance, Shadow сессию и т.д.).
Создаем скриншот средствами PowerShell
Сначала разберемся, как из PowerShell сделать скриншот текущего экрана на локальном компьютере. Для получения изображения рабочего стола мы воспользуемся встроенным классом .NET — System.Windows.Forms. У меня получился такой PowerShell скрипт:
$Path = "C:\ps\screenshots"
# Проверяем, что каталог для хранения скриншотов создан, если нет - создаем его
If (!(test-path $path)) {
New-Item -ItemType Directory -Force -Path $path
}
Add-Type -AssemblyName System.Windows.Forms
$screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
# Получаем разрешение экрана
$image = New-Object System.Drawing.Bitmap($screen.Width, $screen.Height)
# Создаем графический объект
$graphic = [System.Drawing.Graphics]::FromImage($image)
$point = New-Object System.Drawing.Point(0, 0)
$graphic.CopyFromScreen($point, $point, $image.Size);
$cursorBounds = New-Object System.Drawing.Rectangle([System.Windows.Forms.Cursor]::Position, [System.Windows.Forms.Cursor]::Current.Size)
# Получаем скриншот экрана
[System.Windows.Forms.Cursors]::Default.Draw($graphic, $cursorBounds)
$screen_file = "$Path\" + $env:computername + "_" + $env:username + "_" + "$((get-date).tostring('yyyy.MM.dd-HH.mm.ss')).png"
# Сохранить скриншот в png файл
$image.Save($screen_file, [System.Drawing.Imaging.ImageFormat]::Png)
Данный скрипт создает каталог для хранения скриншотов, получает текущее разрешение экрана, получает изображения рабочей области и сохраняет его в png файл.
Запустите указанный PowerShell скрипт и проверьте, что в указанном каталоге (можно укажать UNC путь к сетевой папке) появился png файл со скриншотом вашего рабочего стола в момент запуска скрипта. Для удобства имя png файла содержит имя компьютера, пользователя, текущую дату и время.
Если вы хотите использовать вызов данного PS скрипт из сценариев, используйте такую команду (в этом случае вам не придется изменять настройки PowerShell ExecutionPolicy):
powershell.exe -executionpolicy bypass -file c:\ps\PS-Capture-Local-Screen.ps1
Ярлык на данный PowerShell скрипт можно через GPO поместить на рабочие столы всех пользователей домена и привязать горячие клавиши для его вызова. Теперь при появлении какой-то проблемы или ошибки в любом приложении пользователю достаточно нажать назначенную комбинацию клавиш. В результате в сетевой папке HelpDesk появляется скриншот рабочего стола пользователя.
Как получить скриншот рабочего стола с удаленного компьютера из PowerShell?
Следующая задача – нужно через PowerShell получить скриншот рабочего стола пользователя на удаленном компьютере/сервере. Это может быть как отдельный компьютер с Windows 10, так и RDS сервер.
Если вы хотите получить скриншот рабочего стола с RDS сервера (или десктопной Windows , на которой разрешены множественные RDP подключения), сначала нужно получить ID сессии пользователя на удаленном компьютере. В следующем скрипте нужно указать имя удаленного сервера и учетную запись пользователя.
$ComputerName = "msk-rds1"
$RDUserName = "avivanov"
$quser = (((query user /server:$ComputerName) -replace '^>', '') -replace '\s{2,}', ',' | ConvertFrom-Csv)
$usersess=$quser | where {$_.USERNAME -like $RDUserName -and $_.STATE -eq "Active"}
$usersessID=$usersess.ID
$usersessID = 1
.Для удобства нужно сохранить файл с PowerShell скриптом получения скриншота в сетевой каталог. Для этого отредактируйте скрипт PS-Capture-Local-Screen.ps1, измените путь на:
$Path = \\server1\Screen\Log
В этот каталог будут сохранятся скриншоты пользователей. Предоставьте права на запись в этот каталог для доменной группы Authenticated Users.
После того, как вы получили ID сессии пользователя, можно удаленно подключиться в его сессию через PsExec и запустить скрипт:
.\PsExec.exe -s -i $usersessID \\$ComputerName powershell.exe -executionpolicy bypass -WindowStyle Hidden -file "\\server1\Screen\PS-Capture-Local-Screen.ps1"
Теперь, сотрудник HelpDesk может запустить этот скрипт со своего компьютера, и в указанном каталоге появится скриншот текущего изображения рабочего стола пользователя удаленного компьютера.
powershell.exe exited on comp with error code -196608.
Понимание пришло после этой статьи — https://www.briantist.com/errors/scheduled-task-powershell-0xfffd0000/
Ключ -s у psexec — Run the remote process in the System account.
Мне так «нравится» PowerShell.. Целая простыня не интуитивно понятного кода, только для того чтобы сделать скриншот экрана 🙂 Синтаксис PowerShell — боль системного администратора..
Есть альтернатива под Windows «из корбки»?
В PowerShell возможности впечатляют, но синтаксис вымораживает. Жаль, что не сделали что-нибудь C# или Java — подобное в плане синтаксиса. Теперь уж точно менять не будут, ибо «так исторически сложилось», ИМХО.
Теневые сессии с отключены одобрением пользвателя( в статье есть ссылки).
Не пойму почем вы так не долюбливаете posh. На мой взгляд именно для администрирования вполне нормальный язык.
Да и не нужно вам в нем разбираться. В статье готовые рецепты, бери и пользуйся…
Попробовал на нескольких машинах (все с двумя мониторами). Скриншотит только основной монитор. Жаль.
$screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
замени на:
$screen = [Windows.Forms.SystemInformation]::VirtualScreen
добрый день.
подскажите как победить «powershell.exe exited on pcuser with error code -196608. » при выполнении скрипта?
Код ошибки мне не знаком. Пробовали руками выполнить скрипт в сесии пользователя?
Может в консоли будет более понятная ошибка…
Как допилить скрипт для запуска через планировщик? Работает, но так как запуск происходит не от активного пользователя, скриншот черный( Желательно без PsExec.
Сам как-то мучался с подобным пару лет назад. Через SCCM задача решалась элементарно. Там есть возможность запуска чего-угодно из-под текущего пользователя.
С PowerShell сложнее. Как вариант :
1) Разрешить пользователю создавать задания (добавить его в Backup Operators)
2) некий логон скрипт, который запускается при входе пользователя и создает новое задание от имени пользователя :-UserId $env:UserName
$Action= New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-windowstyle hidden -ExecutionPolicy Bypass -file c:\ps\Screen.ps1"
$Trigger= New-ScheduledTaskTrigger -AtLogon -RepetitionDuration (New-TimeSpan -Days 1) -RepetitionInterval (New-TimeSpan -Minutes 5)
$Principal=New-ScheduledTaskPrincipal -UserId $env:UserName -LogonType Interactive
$Task=New-ScheduledTask -Action $Action -Trigger $Trigger -Principal $Principal
Register-ScheduledTask -TaskName "GetScreen" -InputObject $Task
Все очень сырое, не тестировал сразу скажу. Но как костяк можно взять, дополнительно нужно добавить проверку на наличие таска. Если на компе несколько пользователей, создавать таски с именами пользователей и т.д.
Подскажите пожалуйста, как допилить скрипт так, чтобы скринил определённое окно / определённые окна, по названию может быть как то или что-то в этом роде
Как скринить только одно окно не знаю. Нужен был весь рабочий стол.
В теории можно проверять запущен ли определенный процесс по имени или по заголовку окна (windows tilte):
Get-Process | Where-Object { $_.MainWindowTitle -like ‘*myapp*’ }
Если процесс запущен, сохраняем картинку.
Тут есть ответ на этот вопрос и вполне не сложный — https://devblogs.microsoft.com/scripting/weekend-scripter-manage-window-placement-by-using-pinvoke/
Статья полезная, но в ней не учтено два момента:
1) и [System.Windows.Forms.Screen]::PrimaryScreen.Bounds и [Windows.Forms.SystemInformation]::VirtualScreen возвращают масштабируемый размер, а CopyFromScreen($point, $point, $image.Size) работает с абсолютным. В результате изображение будет обрезаться на мониторах с масштабом изображения больше 100%.
2) Нет очистки памяти, так как после выполнения скрина картинка в памяти сама не уйдёт и останется висеть вечно.