Screenshot PowerShell while remote server is minimized - powershell

I'm currently using the PowerShellscript below to take a screenshot of a file and save it to a local drive. This works fine on my desktop when the excel file is open. However, I'm trying to take the screenshot on a remote server that I have minimized, as I'm running this script there overnight. When the screenshot gets saved to the local drive on the remote server, it's just blank. IF I have the remote server screen open, it works fine. I'm looking for assistance to see if this is even possible. Any assistance would be appreciated.
$app = New-Object -comobject Excel.Application
$app.windowstate= "xlMaximized"
$app.Visible = $True
$app.displayAlerts = $False
$wb = $app.Workbooks.Open("C:\TakeAScreenshotPlease.xlsm")
$wb.Name
$wb.RefreshAll()
Start-Sleep -s 460
[Reflection.Assembly]::LoadWithPartialName("System.Drawing")
function screenshot([Drawing.Rectangle]$bounds, $path) {
$bmp = New-Object Drawing.Bitmap $bounds.width, $bounds.height
$graphics = [Drawing.Graphics]::FromImage($bmp)
$graphics.CopyFromScreen($bounds.Location, [Drawing.Point]::Empty, $bounds.size)
$bmp.Save($path)
$graphics.Dispose()
$bmp.Dispose()
}
$bounds = [Drawing.Rectangle]::FromLTRB(0, 271, 1541, 950)
screenshot $bounds "C:\TakeAScreenshotPlease\FakeFolder.png"

Related

Powershell Admin rights dont work in Windows Forms

I want to add and remove user from the lokal Administrator group. Problem is that even I elevate rights in first place It still Access Denies me when I try to add them.
In a similar code It works this way... only thing I changed it that I created a GUI for it.
Here is the code:
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
if (!$myWindowsPrincipal.IsInRole($adminRole)){
start-process "powershell" -Verb "runas" -ArgumentList "-File",$MyInvocation.MyCommand.Definition
}
[VOID] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[Void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$objForm = New-Object System.Windows.Forms.Form
$objForm.BackgroundImageLayout = 0
$objForm.BackgroundImage =[System.Drawing.Image]::FromFile('xx')
$objForm.StartPosition = "CenterScreen"
$objForm.Icon="xx"
$objForm.Size = New-Object System.Drawing.Size(400,200)
$objForm.Text = "Lokal Admin Adder v.01"
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(75,30)
$objLabel.Size = New-Object System.Drawing.Size(240,20)
$objLabel.Text = "Nutzernamen eingeben(m_mustermann)"
$objForm.Controls.Add($objLabel)
$objLabel2 = New-Object System.Windows.Forms.Label
$objLabel2.Location = New-Object System.Drawing.Size(280,140)
$objLabel2.Size = New-Object System.Drawing.Size(300,20)
$objLabel2.Text = "by Lucas Klarner"
$objForm.Controls.Add($objLabel2)
$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(85,50)
$objTextBox.Size = New-Object System.Drawing.Size(200,20)
$objForm.Controls.Add($objTextBox)
$FinishButton = New-Object System.Windows.Forms.Button
$FinishButton.Location = New-Object System.Drawing.Size (20,80)
$FinishButton.Size = New-Object System.Drawing.Size (150,20)
$FinishButton.Text = "Nutzer hinzufügen"
$FinishButton.Name = "Nutzer hinzufügen"
$FinishButton.Add_Click({
$Usr = $objTextBox.Text; Add-LocalGroupMember -Group Administratoren -Member $Usr })
$objForm.Controls.Add($FinishButton)
$DeleteButton = New-Object System.Windows.Forms.Button
$DeleteButton.Location = New-Object System.Drawing.Size (210,80)
$DeleteButton.Size = New-Object System.Drawing.Size (150,20)
$DeleteButton.Text = "Nutzer entfernen"
$DeleteButton.Name = "Nutzer entfernen"
$DeleteButton.DialogResult = "OK"
$DeleteButton.Add_Click({
$Usr = $objTextBox.Text;Remove-LocalGroupMember -Group Administratoren -Member $Usr -Verbose })
$objForm.Controls.Add($DeleteButton)
[void] $objForm.ShowDialog()
Thanks a lot!!
FIXED:
Somehow my elevation code was not running correctly and I made a new one out of some internet posts:
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
Here's how it works:
The first line checks to see if the script is already running in an elevated environment. This would occur if PowerShell is running as Administrator or UAC is disabled. If it is, the script will continue to run normally in that process.
The second line checks to see if the Windows operating system build number is 6000 (Windows Vista) or greater. Earlier builds did not support Run As elevation.
The third line retrieves the command line used to run the original script, including any arguments.
Finally, the fourth line starts a new elevated PowerShell process where the script runs again. Once the script terminates, the elevated PowerShell window closes.
https://blog.expta.com/2017/03/how-to-self-elevate-powershell-script.html

Why does my Screenshot Function not work as a Job

I have a function inside a Job which takes a Screenshot. The Script itself gets executed by Taskscheduler as a domain admin. I also checked "Run with highest privileges".
The Job should do a Screenshot and then send an E-Mail, but both of those thing don't happen. I also don't see an error message (maybe because it's a background job?). Maybe the E-Mail doesn't get sent because it wants to attach the screenshot to the e-mail, but can't because the screenshot wasn't created.
Why does my function not Take the Screenshot? The domain admin has privileges to write to the destination. The screenshot gets created when I run the function outside the start-job. if i have the function inside start-job it doesn't get created, doesn't matter if the script is started via Taskscheduler or manually.
What am I missing?
The following Code starts the Job and takes the screenshot:
Start-Job -Name LogikWebserverWatch {
function Take-Screenshot([string]$outfile)
{
[int]$PrtScrnWidth = (gwmi Win32_VideoController).CurrentHorizontalResolution
[int]$PrtScrnHeight = (gwmi Win32_VideoController).CurrentVerticalResolution
$bounds = [Drawing.Rectangle]::FromLTRB(0, 0, $PrtScrnWidth, $PrtScrnHeight)
$bmp = New-Object Drawing.Bitmap $bounds.width, $bounds.height
$graphics = [Drawing.Graphics]::FromImage($bmp)
$graphics.CopyFromScreen($bounds.Location, [Drawing.Point]::Empty, $bounds.size)
$bmp.Save($outfile)
$graphics.Dispose()
$bmp.Dispose()
}
while ((Get-Process LogikWebserver).Responding) {sleep -Milliseconds 50}
if (!(Get-Process LogikWebserver).Responding) {
Try{
$utf8 = New-Object System.Text.utf8encoding
$datetime = (get-date).ToString('yyyyMMdd-HHmmss')
Take-Screenshot -outfile C:\Install\LogikWebserverErrorReporting\Screenshot-$datetime.png
# some more code [...]
} Catch { some more code [...] }
}}
The documentations says that:
A Windows PowerShell background job runs a command without interacting with the current session.
So you may have to load the required assemblies inside your job before it will work.
When I tried your code above, it only created a screenshot when run outside of a job (as you mentioned), however adding this line to the top of the Start-Job ScriptBlock caused it to work from inside the job as well:
[Reflection.Assembly]::LoadWithPartialName("System.Drawing")
Or, as the above is now depracated:
[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Drawing.dll")
Or
Add-Type "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Drawing.dll"
Note that I have not tested this when running from a schedued task.
dont use function . just write your function code in script block like this :
Start-Job -Name LogikWebserverWatch {
Add-Type -AssemblyName "System.Drawing"
[int]$PrtScrnWidth = (gwmi Win32_VideoController).CurrentHorizontalResolution
[int]$PrtScrnHeight = (gwmi Win32_VideoController).CurrentVerticalResolution
$bounds = [Drawing.Rectangle]::FromLTRB(0, 0, $PrtScrnWidth, $PrtScrnHeight)
$bmp = New-Object Drawing.Bitmap $bounds.width, $bounds.height
$graphics = [Drawing.Graphics]::FromImage($bmp)
$graphics.CopyFromScreen($bounds.Location, [Drawing.Point]::Empty, $bounds.size)
$bmp.Save($outfile)
$graphics.Dispose()
$bmp.Dispose()
}
while ((Get-Process LogikWebserver).Responding) {sleep -Milliseconds 50}
if (!(Get-Process LogikWebserver).Responding) {
Try{
$utf8 = New-Object System.Text.utf8encoding
$datetime = (get-date).ToString('yyyyMMdd-HHmmss')
Take-Screenshot -outfile C:\Install\LogikWebserverErrorReporting\Screenshot-$datetime.png
# some more code [...]
} Catch { some more code [...] }
}

Add Button to NotifyIcon

I want to see a little notification icon to indicate that the script I wrote is still active (both the script and displying the icon works). But I need a button within the context menu of the icon to stop the script immediately. And that's the part where my problem is:
$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$objContextMenu = New-Object System.Windows.Forms.ContextMenu
$ExitMenuItem = New-Object System.Windows.Forms.MenuItem
$ExitMenuItem.add_Click({
echo stoped
$continue = $False
$objNotifyIcon.visible = $False
})
$objContextMenu.MenuItems.Add($ExitMenuItem) | Out-Null
$objNotifyIcon.ContextMenu = $objContextMenu
$objNotifyIcon.Visible = $True
The script itself is longer, this is just the relevant part. If I run it from PowerShell ISE it works just fine. When I run it from a .bat file with
powershell .\myscript.ps1
the context menu is not working anymore.
This is just a wild guess, but try running the script in Single Thread Apartment mode:
powershell -STA -File .\myscript.ps1

Remote desktop powershell indication

I'm trying to automate the remote desktop process (from windows client to windows server) for a service I'm working on.
To do so, I'm using the following Powershell script:
$ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
$Process = New-Object System.Diagnostics.Process
$ProcessInfo.FileName = "$($env:SystemRoot)\system32\cmdkey.exe"
$ProcessInfo.Arguments = "/generic:TERMSRV/$ComputerCmdkey /user:$User /pass:$Password"
$ProcessInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$Process.StartInfo = $ProcessInfo
if ($PSCmdlet.ShouldProcess($ComputerCmdkey,'Adding credentials to store')) {
[void]$Process.Start()
}
$ProcessInfo.FileName = "$($env:SystemRoot)\system32\mstsc.exe"
$ProcessInfo.Arguments = "$MstscArguments /v $Computer"
$ProcessInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Normal
$Process.StartInfo = $ProcessInfo
if ($PSCmdlet.ShouldProcess($Computer,'Connecting mstsc')) {
[void]$Process.Start()
}
This script works perfectly fine. What i'm missing is an indication on the client side (other than the UI window - some return value or event log) that can tell me whether the connection was successful or did it fail.
Can anyone here help with it?
Thanks

PowerShell - Disable Win+D Desktop-View for my Script/Form only

I want to know if it´s possible to disable Win+D Windows-Shortkey?
And the "view Desktop"-Button in the bottom right corner must be disabled, too.
Only for my Script and I´ve got the approach to catch this two processes and after completely minimizing all running programms, THAN open up the Script (only) again. So the Script is everytime viewable on the desktop.
The Script owns a Form without a Controlbox.
Suggest it like a Windows-Sidebar-Element that is allways viewable on the Desktop.
To Save the $PID in a extra LOCAL-File (Script running on each PC from a Server) is necessary, because an other Script in the background run the Script again, if a worker would kill the Task.
Here is my Script Code:
#Clear Sessions
Get-PSSession | Remove-PSSession
#Save current used Process-ID in a TextFile
$PID > C:\Users\Public\Documents\PID.txt
#Imports
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
#$Icon = New-Object System.Drawing.Icon ("Icon-Path here")
#Get NetworkData
$hostname = $env:computername
$IPAdress = (gwmi Win32_NetworkAdapterConfiguration | ? { $_.IPAddress -ne $null }).ipaddress[0]
#Create a Form
$myForm = New-Object System.Windows.Forms.Form
$myForm.DataBindings.DefaultDataSourceUpdateMode = 0
$myForm.Size = New-Object System.Drawing.Size(190,70)
$myForm.Text ="Nutzerdaten"
#Optic-Settings
$myForm.FormBorderStyle = "FixedDialog"
$myForm.MaximizeBox = $false
$myForm.MinimizeBox = $false
$myForm.ControlBox = $false
$myForm.StartPosition = "CenterScreen"
$myForm.ShowInTaskbar = $false #Close-Window-Button unlocked
$myForm.Opacity = 0.6 #0.1 - 1 for transparancy
#$myForm.Icon = $Icon
#Disable Win+D
$myForm.Add_KeyDown({
if( $_.KeyCode -eq "LWin" )
{
Start-Sleep -Seconds 5
[System.Windows.Forms.MessageBox]::Show( "Später wird das Fenster wieder sichtbar gemacht, wenn man Win+D gedrückt hat." )
}
})
#Disable normal closeing (only by crash Script or end PwerShell in Task-Manager)
$myForm.add_FormClosing({$_.Cancel = $true})
#Label with Hostname Data
$lblHost = New-Object System.Windows.Forms.Label
$lblHost.Size = New-Object System.Drawing.Size(180,15)
$lblHost.Top = "5"
$lblHost.Left = "5"
$lblHost.Text = "Hostname : " + $hostname #View Hostname in transparancy mode
$myForm.Controls.Add($lblHost)
#on Click open MessageBox and show closeable Dialog with the IP-Adress and Hostname)
$lblHost.Add_Click({
[System.Windows.Forms.MessageBox]::Show("Hostname = "+$hostname+" | IP-Adress = "+$IPAdress )
})
#Label with IP-Adress (v4 only)
$lblIP = New-Object System.Windows.Forms.Label
$lblIP.Size = New-Object System.Drawing.Size(180,15)
$lblIP.Top = "20"
$lblIP.Left = "5"
$lblIP.Text = "IP-Adress : " + $IPAdress #View Ip-Adress in transparancy mode
$myForm.Controls.Add($lblIP)
#on Click open MessageBox and show closeable Dialog with the IP-Adress and Hostname)
$lblIP.Add_Click({
[System.Windows.Forms.MessageBox]::Show("Hostname = "+$hostname+" | IP-Adress = "+$IPAdress )
})
#View Form/GUI
$myForm.ShowDialog()
Thank you for reading this and I hope that some got any idear how to clear this problem.
Kind regards,
M. Lengl