I am limited to only using native windows tools, and I need to automate opening a browser, going to a website, and then closing the browser. I'm going to use task scheduler to run the script.
I created this PowerShell script which successfully opens a browser, and closes it.
How would I go about having this open a specific webpage? Start Arguments or something else?
$browser = [Diagnostics.Process]::Start("chrome.exe")
$id = $browser.Id
Start-Sleep -Seconds 5
try {
Stop-Process -Id $id -ErrorAction stop
} catch {
Write-Host "Failed to kill"
}
You can start the process with the appropriate Chromium command line argument(s):
$browser = [Diagnostics.Process]::Start("chrome.exe", "https://stackoverflow.com/ --new-window")
$id = $browser.Id
Start-Sleep -Seconds 5
try {
Stop-Process -Id $id -ErrorAction stop
}
catch {
Write-Host "Failed to kill"
}
Process.Start Method
Run Chromium with flags
List of Chromium Command Line Switches
Related
As part of a Powershell script I need to perform a task that is typically quick, but can sometimes take a long amount of time. I want to execute the task, then wait either for it fo finish or for set time to pass, whichever happens first. When either condition happens, I need the Powershell script to return back to the command prompt.
Here is the closest I've come up with (using ping as an example)
$x = Start-Process -Filepath "ping" -ArgumentList 'google.com -n 100' -NoNewWindow -PassThru;
Start-Sleep -Seconds 5;
try { Stop-Process -Id $x.Id -ErrorAction stop } catch {};
This will kill the process after the timoeout is reached (if it is still running) and return back to the prompt. However, it won't return to the prompt if the command successfully completes before timeout. This results in the script always taking however long is specified in the timeout value.
The desired semantics are similar or identical to Linux's timeout command.
Requirements:
If the task completes within timeout window, control returns to the script (a prompt is displayed)
If the timeout is reached and the task is stil running, the task is killed and control returns to the script (a prompt is displayed)
Output from the task must be printed/displayed to stdout
Works over an SSH connection
Edited to use ping instead of notepad. I'm combining wait-process and "$?" into one statement with "$( )", because powershell "if" looks at the output, not the exit status.
start ping 'google.com -n 100'
if (-not $(wait-process ping 10; $?)) {
stop-process -name ping }
I think some of the requirement can be met by using a Stopwatch, you'll have to test the SSH connection.
$timeOut = New-TimeSpan -Seconds 5
$stopWatch = [System.Diagnostics.Stopwatch]::StartNew()
do {
try {
Test-Connection -ComputerName google.ca -Count 1 -ErrorAction Stop
$timeOut = New-TimeSpan -Seconds 0 #Stop the stopWatch, we got a response
}
catch { #Write-Host "No response" }
}
While ($stopWatch.elaspsed -lt $timeOut)
I have a program foo.exe
foo.exe sometxtfile -arg0 10 -arg1 "cats" -arg3 666
It currently crashes with an exception. I have the project in visual studio and could put that command line into the visual studio debug startup but I'd like to be more flexible and be able to start this from powershell.
I am aware of Debug-Process but that only debugs a currently running process. Would it be possible to use this to launch and debug?
The trick is to wait for the process to start the job as a background process and then call Debug-Process on it.
start-job {
foo.exe sometxtfile -arg0 10 -arg1 "cats" -arg3 666
}
$process="foo"
Write-Host "Waiting for $process to start"
Do {
$status = Get-Process $process -ErrorAction SilentlyContinue
If (!($status)) {
Write-Host -NoNewline '.'
}
Else {
Write-Host ""
Write-Host "$process has started"
$started = $true
}
}
Until ( $started )
debug-process -Name ${process}
debug-process -Name ${process}
Thanks to Abbas, the following code enable us to call a cmd process and pass command to it using PowerShell script.
$psi = New-Object System.Diagnostics.ProcessStartInfo;
$psi.FileName = "cmd.exe"; #process file
$psi.UseShellExecute = $false; #start the process from it's own executable file
$psi.RedirectStandardInput = $true; #enable the process to read from standard input
$p = [System.Diagnostics.Process]::Start($psi);
Start-Sleep -s 2 #wait 2 seconds so that the process can be up and running
$p.StandardInput.WriteLine("dir"); #StandardInput property of the Process is a .NET StreamWriter object
Now, How can I use a CMD process that already exists.
In better words, I want to use the PID of a cmd.exe process that is running and pass the command to it.
Based on #Falcon's comment:
I want to be sure that the CMD is running as SYSTEM
I think the code should work, which checks for a command shell running as SYSTEM. It will return true for each matching shell that's running as SYSTEM, with title=TEST:
Get-CimInstance Win32_Process -Filter "name = 'cmd.exe'" | ForEach-Object {
if ((Get-Process -Id $_.ProcessId).MainWindowTitle -eq 'TEST') {
(Invoke-CimMethod -InputObject $_ -MethodName GetOwner).User -eq 'SYSTEM'
}
}
The above code needs running in an elevated shell
The code based on this article checks for the command prompt being elevated:
$p = Get-Process -Name cmd | where {$_.MainWindowTitle -eq 'TEST'} |
Select Name, #{Name="Elevated"; Expression={ if ($this.Name -notin #('Idle','System')) {-not $this.Path -and -not $this.Handle} } }
The code above needs running in a non-elevated PowerShell instance. It is testing for the absence of a path & handle - which the non-elevated shell can't see for an elevated command prompt. Change the eq 'TEST' condition to match your window.
I'm working on a large script where I run a Foreach loop, define variables in that loop and afterwards check if the $Server variable is pingable and if it is remotely accessible.
For this I use the following functions coming from the PowerShell help:
# Function to check if $Server is online
Function CanPing ($Server) {
$error.clear()
$tmp = Test-Connection $Server -ErrorAction SilentlyContinue
if ($?) {
Write-Host "Ping succeeded: $Server"; Return $true
}
else {
Write-Host "Ping failed: $Server."; Return $false
}
}
# Function to check if $Server is remotely accessible
Function CanRemote ($Server) {
$s = New-PSSession $Server -Authentication Credssp -Credential $Credentials -Name "Test" -ErrorAction SilentlyContinue
if ($s -is [System.Management.Automation.Runspaces.PSSession]) {
Enter-PSSession -Session $s
Exit-PSSession
Write-Host "Remote test succeeded: $Server."; Return $true
}
else {
Write-Host "Remote test failed: $Server."; Return $false
}
}
# Execute functions to check $Server
if ($Server -ne "UNC") {
if (CanPing $Server) {
if (-Not (CanRemote $Server)) {
Write-Host "Exit loop REMOTE" -ForegroundColor Yellow
continue
}
}
else {
Write-Host "Exit loop PING" -ForegroundColor Yellow
continue # 'continue' to the next object and don't execute the rest of the code, 'break' exits the foreach loop completely
}
}
Every time when I run this code, there is a process created on the remote server called wsmprovhost.exe. This process represents the PowerShell session, if the info I found on the web is correct. However, when doing Get-PSSession $Server there are no open sessions displayed in the PowerShell ISE, even though the processes are visible on the remote server and can only be killed with the Task Manager.
When I run this code often the limit of open sessions is reached because every time a new process wsmprovhost.exe is added to the $Server and the command errors out. I've tried to solve this by adding Exit-PSSessionto the code, but it doesn't close the session.
Any help or ideas are more than welcome.
The problem is that Enter-PSSession. Enter-PSSession can only be used interactively, you can't use it in a script. I'd suggest something more like this:
# Function to check if $Server is remotely accessible
Function CanRemote ($Server) {
Try {
$s = New-PSSession $Server -Authentication Credssp -Credential $Credentials -Name "Test" -ErrorAction Stop
Write-Host "Remote test succeeded: $Server."
$true
Remove-PSSession $s
}
Catch {
"Remote test failed: $Server."
$false
}
}
If I have understood correctly, Your remote ps-session are not getting closed.
To my understaning, Get-PSSession will show the session till your local session
is alive (I mean the session you created the remote ps-session) but once your local session
ends Get-PSSession will not show them cause they are no more live on your computer
rather on the remote system (or) they are no more in local session scope.
You can get the session using the command
Get-PSSession -ComputerName server_name
If you want to remove them you can do like
Get-PSSession -ComputerName server_name | Remove-PSSession
Even After executing the below command also, if you are not able to create session
Get-PSSession -ComputerName server_name | Remove-PSSession
Please, Restart the service Windows Remote Management (WS-Management) in the target machine.
When I run a program on PowerShell it opens a new window and before I can see the output, the window closes. How do I make it so PowerShell keeps this window open?
Try doing:
start-process your.exe -NoNewWindow
Add a -Wait too if needed.
The OP seemed satisfied with the answer, but it doesn't keep the new window open after executing the program, which is what he seemed to be asking (and the answer I was looking for). So, after some more research, I came up with:
Start-Process cmd "/c `"your.exe & pause `""
I was solving a similar problem few weeks ago. If you don't want to use & (& '.\program.exe') then you can use start process and read the output by start process (where you read the output explicitly).
Just put this as separate PS1 file - for example (or to macro):
param (
$name,
$params
)
$process = New-Object System.Diagnostics.Process
$proInfo = New-Object System.Diagnostics.ProcessStartInfo
$proInfo.CreateNoWindow = $true
$proInfo.RedirectStandardOutput = $true
$proInfo.RedirectStandardError = $true
$proInfo.UseShellExecute = $false
$proInfo.FileName = $name
$proInfo.Arguments = $params
$process.StartInfo = $proInfo
#Register an Action for Error Output Data Received Event
Register-ObjectEvent -InputObject $process -EventName ErrorDataReceived -action {
foreach ($s in $EventArgs.data) { Write-Host $s -ForegroundColor Red }
} | Out-Null
#Register an Action for Standard Output Data Received Event
Register-ObjectEvent -InputObject $process -EventName OutputDataReceived -action {
foreach ($s in $EventArgs.data) { Write-Host $s -ForegroundColor Blue }
} | Out-Null
$process.Start() | Out-Null
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()
$process.WaitForExit()
And then call it like:
.\startprocess.ps1 "c:\program.exe" "params"
You can also easily redirect output or implement some kind of timeout in case your application can freeze...
If the program is a batch file (.cmd or .bat extension) being launched with cmd /c foo.cmd command, simply change it to cmd /k foo.cmd and the program executes, but the prompt stays open.
If the program is not a batch file, wrap it in a batch file and add the pause command at the end of it. To wrap the program in a batch file, simply place the command in a text file and give it the .cmd extension. Then execute that instead of the exe.
With Startprocess and in the $arguments scriptblock, you can put a Read-Host
$arguments = {
"Get-process"
"Hello"
Read-Host "Wait for a key to be pressed"
}
Start-Process powershell -Verb runAs -ArgumentList $arguments
pwsh -noe -c "echo 1"