Сотрудники службы техподдержки пользователей попросили написать PowerShell скрипт, позволяющий быстро получить скриншот рабочего стола пользователя с удаленного компьютера. При этом сотрудник HelpDesk не должен подключаться к компьютеру пользователя через графические средства удаленной поддержки (SCCM, Remote Assistance, теневую RDP сессию и т.д.).
Получить скриншот экрана пользователя в скрипте PowerShell
Для получения текущего изображения экрана пользователя можно использовать встроенный .NET класс System.Windows.Forms. Следующий PowerShell скрипт создаст локальную папку для хранения снимков экрана, определит текущее разрешение графической среды и сохранит содержимое экрана в PNG файл.
$Path = "C:\ps\screenshots"
# Проверяем, что каталог для хранения скриншотов создан, если нет - создаем его
If (!(test-path $path)) {
New-Item -ItemType Directory -Force -Path $path
}
Add-Type -AssemblyName System.Windows.Forms
$screen = [Windows.Forms.SystemInformation]::VirtualScreen
# Получаем разрешение экрана
$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)
# Очистка памяти
$graphic.Dispose()
$image.Dispose()
Запустите PowerShell скрипт и проверьте, что в указанном каталоге (можно указать UNC путь к сетевой папке) появился PNG файл со снимком вашего рабочего стола в момент запуска скрипта. Для удобства имя PNG файла содержит имя компьютера, пользователя, текущую дату и время.
Скрипт захватит на скриншоте в том числе положение курсора мыши.
Чтобы создавать скриншоты экрана каждые несколько секунд, нужно поместить код скрипта в цикл while:
while($true){
{ SCRIPT }
sleep(60) # Пауза 60 секунд
}
Для вызова этого PowerShell скрипта из планировщика задач или BAT файла сценария, используйте такую команду (в этом случае не придется изменять настройки PowerShell ExecutionPolicy):
powershell.exe -executionpolicy bypass -file c:\ps\PS-Capture-Local-Screen.ps1
С помощью GPO можно поместить ярлык на этот PowerShell скрипт на рабочие столы пользователей и назначить горячие клавиши для его вызова. Теперь при появлении какой-то проблемы или ошибки в любом приложении пользователю достаточно нажать назначенную комбинацию клавиш. В результате в сетевой папке HelpDesk появится скриншот рабочего стола пользователя.
Как получить скриншот рабочего стола с удаленного компьютера из PowerShell?
Этот PowerShell скрипт можно использовать для получения скриншот рабочего стола пользователя на удаленном рабочей станции или сервере.
Если нужно получить скриншот рабочего стола с RDS сервера (или десктопной Windows , на которой разрешены множественные RDP подключения), сначала нужно получить ID сессии пользователя на удаленном компьютере.
Чтобы получить список сессий пользователей на удаленном компьютере, выполните команду:
qwinsta /server:msk-rds1
В данном случае пользователь выполнил вход на консоль (сессия 1).
Скопируйте файл PS-Capture-Local-Screen.ps1 в сетевой каталог и отредактируйте в нем путь, чтобы он сохранял скриншоты в сетевую папку (предоставьте права записи в эту папку для пользователей):
$Path = \\server1\Screen\Log
Теперь с помощью утилиты
PsExec
можно выполнить PowerShell скрипт получения скриншота для пользователя по ID его сессии (
1
в нашем примере).
.\PsExec.exe -s -i 1 \\wks333 powershell.exe -executionpolicy bypass -WindowStyle Hidden -file "\\s-fs01\scripts\PS-Capture-Local-Screen.ps1"
Строка powershell.exe exited on wks333 with error code 0 указывает, что скрипт был выполнен успешно.
Теперь, сотрудники HelpDesk могут запустить эту команду со своего компьютера, и в указанном сетевом каталоге появится скриншот изображения рабочего стола пользователя удаленного компьютера.
PowerShell: сделать скриншот окна активного приложения
Рассмотренный выше скрипт помещает в PNG файл содержимое всех мониторов пользователя. Можно делать снимок только открытого окна приложения, с котороым работает пользователь в данный момент.
В GitHub также загружен обновленный скрипт PS-Capture-Current-App-Screen.ps1, позволяющий сделать в сесии пользователя скриншот только содержимого окна активного приложения.
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) Нет очистки памяти, так как после выполнения скрина картинка в памяти сама не уйдёт и останется висеть вечно.
Это решение проблемы обрезания изображения. Работает также при подключении к виртуальной машине через RDP. В коде используется последний найденный видеоадаптер.
$Screen = (Get-CimInstance -ClassName Win32_VideoController)[-1]
$Image = New-Object System.Drawing.Bitmap([int]$Screen.CurrentHorizontalResolution, [int]$Screen.CurrentVerticalResolution)
Здравствуйте, подскажите в чем может быть проблема, не одном комьютере где 6 мониторов все работает как надо (поменял [System.Windows.Forms.Screen]::PrimaryScreen.Bounds на [Windows.Forms.SystemInformation]::VirtualScreen как тут в комментах советовали)
Но на другом почему то делает скриншот только двух мониторов из шести. При чем конфигурация железа и системы абсолютно одинаковы.
Даже не знаю в какую сторону копать. может посоветуете что-то?