Start-Process, set focus (?) and press key on virtual machine disconnected from RDP - powershell

I have a situation which I need some help with.
I'm running an Azure build pipeline on microsoft hosted private VM with quite a old build program/IDE which does not have any CLI.
So I have to start the program and then press a key (F10) to start the build, right now i'm using Powershell for this.
I have issues though to get this to work on the VM when I have disconnected RDP, almost always (not 100%) when I have rdp open my script works and set focus to the program and presses the key. But sometimes it doesn´t work, and it seems to always fail when the rdp is disconnected. My build fails and when I connect with RDP the window is just grey:d out and it hasn't registered any keypress.
I have found some similar threads which seems to touch upon the issue, but not any solution for Powershell.
Setting focus to window in a virtual machine
Sendkeys On Disconnected RDP Session
One solution seems to be to redirect standard input to the started program which means we don't have to care about focusing the window, but how do I redirect a keypress to a started process with Powershell? (Any other scripting language available in azure pipelines yaml is also ok)
The best solution so far has been
param
(
[string]$appName,
[string]$key
)
$objShell = New-Object -ComObject wscript.shell
$proc = Get-Process $appName
$objShell.AppActivate($proc.Id)
Start-Sleep -Seconds 1
$keyString = "'{" + $key + "}'"
$objShell.SendKeys($keyString)
But as stated, this seems to only work when I have an active RDP connection (and not 100% of the time). I have also tried using SetForegroundWindow which works fine when I run the script on my own computer but not on the VM.
Many thanks
Carl

Related

Powershell Startup Script GPO Not Applying

Pretty basic script used to create a web shortcut on the PC's desktop, but it's not applying for some reason. I have it set in the gpo under
Computer Configuration->Policies-> Windows Settings-> Scripts-> Startup->
Added the powershell script-> And set it to run the powershell script first.
I also know the script works because I have tried running it manually on the machine without admin privileges or anything and it appears just fine.
$DesktopPath = [Environment]::GetFolderPath("Desktop") + "\Prophet21.url"
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($DesktopPath)
$Shortcut.TargetPath = "https://p21.gallagherseals.com/prophet21/#/login" $Shortcut.Save()
You're running the code in the wrong context, to run as a user and affect a user, you need to deploy this as a User Configuration.
When you run a Startup Script for a Computer, this happens when the PC is Domain Joined and will process shortly after displaying the initial login screen silently in the background.
But because there is no user logged in yet, some items aren't available.
To fix this, just deploy it as a User Configuration, the full path to the setting would be:
User Configuration -> Policies -> Windows Settings -> Scripts (Logon / Logoff);
The better approach
However, GPO also natively supports creating Desktop Icons with a nice and easy to use wizard. Just follow this short guide by Praj Dasai. I used to manage GPO and I would always prefer a native solution to running a script.

PowerShell - showing a message on remote computer screen

When I am running commands or installing software remotely using PowerShell - Invoke-Command etc I would like sometimes to be able to show a message on the remote screen so the user knows something is happening, or when work done etc.
I would like to if possible make this message look as professional as possible, e.g. better than just a standard winform message box if it can be done? perhaps more the style of the Windows 10 ones with coloured background and use of image if possible.
Spent a while googling but most seem to relate to using obsolete methods such as net-send or using msg.exe.
Thanks
https://michlstechblog.info/blog/powershell-show-a-messagebox/
So the issue really isnt creating the messagebox itself, its having it show on the users session.
So when you run a command against a system, youre using your creds to run the command therefore it wont show in the users session. You can get around this by running it in the users context using a task scheduler. I have a script that does all this for you but, id hate to recreate the wheel and will have to wait till monday (when im at work) to post it here.
It accepts user input in your sessions that outputs it to a vbs, which then copies it over the message to the users machine, and a task schedule is set to run immediately for the user thats logged in.
edit: The script is this without the task scheduler. I just invoke gwmi win32_computersystem | Select -ExpandProperty username to get the current user logged in and add it to the task.
#Prompt for messge
$strMSG = Read-Host -Prompt "Enter message"
#deleting vbs if it exists
del C:\brief\test.vbs
#creating vbs from scratch so it doesnt override
New-Item C:\brief\test.vbs
#Appending each the values to a seperate line
Add-Content C:\brief\test.vbs 'Set objShell = Wscript.CreateObject("WScript.Shell")'
Add-Content C:\brief\test.vbs "strText = `"$strMSG`""
Add-Content C:\brief\test.vbs 'intButton = objShell.Popup(strText,0,"Computer Support",48)'
#calling on the script
& cscript C:\brief\test.vbs
Found a great solution here which appears on quick testing to work well for displaying a toast notification on a remote machine
https://smsagent.blog/2019/06/11/just-for-fun-send-a-remote-toast-notification/

Remote execution of powershell script with autosys - to interact with IE _ComObject

I have a Powershell script designed to automate the testing of some URLs. The script invokes an Internet Explorer session as such:
$IEProcess = Start-Process -FilePAth 'C:\Program Files (x86)\Internet Explorer\iexplore.exe' -ArgumentList "-private $url"
$Shell = New-Object -ComObject Shell.Application
$IE = $Shell.Windows()
It then proceeds to use the $IE object to navigate to different URLs, perform various checks against the pages HTML document bodies and take screenshots of the resulting web pages. Ultimately, the IE session is ended and the screenshots are distributed via email as attatchments.
The script works perfectly when logged onto the virtual host-machine with a service account, that has the necessary permissions for single-sign-on to the various URLs. However, the requirement is for the script to run remotely as a scheduled task, on a daily basis. There should be no interaction by a user other than opening the resulting email.
I have had a job set up in AutoSys to execute the script remotely, once a day, with highest privileges; but the script fails to complete as expected. Specifically, the .Windows() method fails passing the following error message:
Exception calling "Windows" with "0" argument(s): "The server process could not
be started because the configured identity is incorrect. Check the username an
d password. (Exception from HRESULT: 0x8000401A)"
I have to give the job of scheduling the task in autosys to someone else (for security reasons) but I trust that they have configured the job with the appropriate username/password for the necessary service account.
Some online sources suggest to me that the issue might lie with trying to use _ComObjects remotely, and that instances of Internet Explorer require an interactive user session with a UI - which isn't standard config for an autosys batch job.
I have had my autosys-guy add a flag to the job description which should make the user session "interactive", but the script still doesn't execute correctly.
I'm looking for some general insight on the topic and hopefully a solution to get the job running. If anyone cares to help me out I would greatly appreciate it! :)
I also have a more focussed question:
Even if I managed to get a handle on the IE session, should I expect the screenshots that the script takes to fail since the screen buffer for the VM has no monitor to render to? - The images are bitmap and refer to the IE shell objects "position", "width" and "height" for capture placement/dimensions; which presumably mean nothing without a screen resolution??
Thank you for taking the time to read my issue!

Posh-SSH and Cisco Gear

I've been working on doing some scripting with Powershell and the Posh-SSH module. I'm connecting to mainly Cisco gear, but have some other network gear as well. My issue seems to be that I can connect to the gear just fine, but my commands don't seem to run. I've attempted Invoke-SSHCommand as well as creating New-SSHShellStream. What is odd is if I open Powershell and step through each command manually, it appears to work just fine, but for some reason running in a script doesn't produce the results I'm looking for.
I have found that plink.exe works just fine, but I'd really rather code all this from Powershell if possible. Is there something I'm missing with these network devices that might be different than a Linux server?
Code:
New-SSHSession -ComputerName $fw-ip -Credential (Get-Credential) -Verbose<br/>
$session = Get-SSHSession -Index 0<br/>
$stream = $session.Session.CreateShellStream("dumb", 0, 0, 0, 0, 1000)<br/>
$stream.Write("show ver")<br/>
$stream.Read()
What I get back:
Type help or '?' for a list of available commands.<br/>
FW/Admin>
So after working with you in the comments it looks like there were two problems, the first being that the SSH shell supported by the SSH.NET library does not seem to support partial commands, swapping "Show Ver" to "Show Version" corrected that. In addition the command was taking a bit longer to run than the script was waiting before calling its read() on the stream, which can be fixed by adding a start-sleep -seconds 5 between the write() and the read(). If you are planning to use this with commands that may take longer or where you are not sure how long they will take you may want to look into some additional handling that checks to see if the command is done by checking the dataavailable property or creating a listener for the DataReceived event but if your keeping things simple a basic timer will work great for you.

Script to get Windows 7 backup status of multiple client computers and send email if one fails

I have looked around and not found anything about remotely checking Windows 7 backup status.
We have Windows 2008 R2 SBS running our domain with 5 Windows 7 client computers. Each client computer is backing up to a NAS (some programs we have are a huge pain to re-install if a hard drive dies, so we have a system image of each). I would like to run a PowerShell script that checks each client computer for a successful backup and if one has failed, send an email.
What I need help with the most is the part to query each computer for backup status.
There are so many way you can approach this problem. Here is one way:
You can schedule a job on each computer that runs a script which checks the status code of the backup job and if it detects failure send an email.
Now? How do you get the task results? You might use something like this (not tested)
$s = New-Object -com Schedule.Service
$s.connect
$au = $s.getfolder('').gettasks(0) | where {$_.name -match 'automaticbackup'}
if ( $au.LastTaskResult -ne 0) {
##send email
}
Depending on the version of the PowerShell you can, for example, use 'send-email' cmdlet.
Hope this helps get you started.