I'm trying to put in place some monitoring for Windows Task Scheduler, I have a Powershell script that runs the following:
$serverName = hostname
$schedule = new-object -com("Schedule.Service")
$schedule.connect($serverName)
$tasks = $schedule.getfolder("\").gettasks(0)
$tasks |select name, lasttaskresult, lastruntime
This returns a list of scheduled tasks on the server it is run on, the last task result and last run time. The purpose for this is to return a dataset to our monitoring solution (Geneos) which we can use for alerting.
We have a large Win2008 estate, so I want the script centralised allowing any of the Geneos probes to call it and return a dataset for their host. To do this I wrapped the powershell in a .bat file which does the following:
\\fileserverhk\psexec.exe -accepteula -u admin -p "pwd" powershell.exe cpi \\fileserverhk\scripts\TaskSchedulerMonitor.ps1 -Destination C:\Monitor\TaskSchedulerMonitor.ps1
\\fileserverhk\psexec.exe -accepteula -u admin -p "pwd" powershell.exe -ExecutionPolicy Bypass -File C:\Monitor\TaskSchedulerMonitor.ps1
The First step copies the .ps1 file locally to get around Powershell not trusting UNC paths and the second part runs the script.
If I run the .bat file manually from a test server it executes fine (this is logged in under an admin account). However, when I fire the .bat file via Geneos (which runs under the SYSTEM account) I get:
Access is denied.
PsExec could not start powershell.exe:
So basically my question is, how do I get PsExec to switch user when it is run under the SYSTEM account? Even though PsExec has the credentials set for another account, there is obviously something preventing it from changing when run under system.
I read to try running it with the -h switch but I get the below error:
The handle is invalid.
Connecting to local system...
Starting PsExec service on local system...
Connecting with PsExec service on <server>...
Starting powershell.exe on <server>...
Error communicating with PsExec service on <server>:
In addition to the above error, I end up with the PSExec and powershell processes hung on the remote machine. The interesting part is I can see the PSExec and PSEXEC.SVC running under SYSTEM and the powershell running under admin, so it's almost there, but something isn't quite right there.
We managed to get there using a powershell wrapper on the Windows schtasks command (link here). Schtasks can be run under the SYSTEM account and will return all the necessary task information, so we no longer needed to faff about with permissions, and no more clear text passwords on the environment (bonus).
We wrapped:
schtasks.exe Query /FO CSV
in a powershell script, and used PS to format the output into the csv style expected by Geneos.
Related
I've created numerous scripts in PowerShell that are working as intended if I execute them directly, however, when I try and setup a schedule to run these in Task Scheduler (to run with highest privileges) it doesn't seem to be running anything at all.
I'm running the following in my actions:
powershell.exe -ExecutionPolicy Bypass -File C:\PS\Mailboxes\CheckForwardingList.ps1
I'm getting a "Last Run Result" of 0x0 and the particular purpose of the above script is to generate a TXT file from EXO which it then mails out via SMTP and I've yet to receive any emails and I also don't see any TXT being generated in the folder where the script is located.
I do have two additional scripts setup which aren't running but once I've addressed the issue on the above this should quickly rectify the problems.
I like to test my PowerShell scripts from a command prompt first.
For example a script called C:\Tests\Test-PowerShellScriptsRunning.ps1 that only contains the following one liner helps me to test if scripts can run successfully on a machine
Write-Host -ForegroundColor Yellow "If you see this, then your script is running"
Next, I run this script from a command prompt, to get the syntax right in my scheduled task:
powershell.exe -nologo -file c:\Tests\Test-PowerShellScriptsRunning.ps1
Of course, you can add the -Executionpolicy bypass parameter, but I prefer to test the execution policy first.
However, as you are running a script that connects to ExchangeOnline, I suspect it has to do with the user you are running this task under. Does the script run if you run this task under your credentials or are the credentials stored on the system or in the script?
You might want to check this article to see how you can register an app and authenticate without storing your credentials on the machine to run the script unattended: App-only authentication for unattended scripts in the EXO V2 module
Let's say for example, I have a domain controller and a client that is joined to the domain.
If I wanted to remotely lock out the client I would supposedly run
Invoke-Command -ComputerName [workstation name] -ScriptBlock {rundll32.exe user32.dll, LockWorkStation}
However this does not work. I'm assuming this is because the Invoke-Command cmdlet runs the code in the scriptblock but returns anything back to the local terminal. What I'm trying to accomplish is to have the code or powershell script run locally on the remote computer.
My question is first of all if this is the correct approach and second why the command I'm running does not work.
Download PsExec from https://learn.microsoft.com/en-us/sysinternals/downloads/psexec and run following command.& "C:\PSTools\PsExec.exe" -s -i \\COMPNAME rundll32.exe user32.dll,LockWorkStation
As per my comment when using PSExec... So, stuff like this ---
PsExec.exe \\ -d -u \Administrator -i cmd.exe /c "C:\windows\system32\rundll32.exe user32.dll, LockWorkStation"
Or using PowerShell with quer.exe ...
(it's a tool in every modern Windows version)
quser | Microsoft Docs
...in a PowerShell remoting script, like described here:
How To Log Off Windows Users Remotely With PowerShell
Again the work is being done by quser.exe, not PowerShell specifically. PowerShell is just being used to run quser.exe remotely. You could do the same, by copying PSExec to the remote host and do a similar operation.
I am learning how to interact with PowerShell and PsTools, and I have a problem with psexec.
I got a ps1 script named test.ps1 and inside it I have Get-Service which gives me the all services in my computer. Now I am going into PowerShell and go to c:\pstools. Then I type
psexec.exe C:\test\test.ps1
and it fails and returns me this error:
%1 is not a valid Win32 application
What could be the problem?
PsExec launches an executable. You need to specify the executable for PowerShell and associated arguments:
psexec.exe -accepteula -nobanner -s -h -d powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "C:\test\test.ps1"
The immediate answer to your question is:
psexec requires a (binary) executable as its first argument and cannot execute scripts directly.
Therefore, you must pass the Windows PowerShell executable name to psexec and in turn pass the desired script to the latter as an argument, via the -File parameter:
psexec powershell -File C:\test\test.ps1
That said, this particular use of psexec is pointless, as it would execute the script locally, as the current user, in which case use of psexec is a needless complication:
If you already know that, and the psexec command at hand is just a simplified example, never mind.
Otherwise, read on below.
The ps in psexec and PsTools has nothing to with PowerShell; PsTools is a collection of CLIs for managing Windows machines remotely, including processes, a common abbreviation of which is "ps", inspired by the standard ps Unix utility, which in turn inspired the initial tool in the collection, pslist; the primary purpose of psexec is to invoke arbitrary command lines on remote machines[1]
.
To invoke a PowerShell script locally:
From inside PowerShell itself, simply invoke the file path directly:
PS> c:\test\test.ps1
PS> & "c:\test\test.ps1", if the file path is / must be quoted or is provided via a variable or expression.
From outside of PowerShell, such as cmd.exe ("Command Prompt") or bash, you must invoke the PowerShell executable explicitly and pass it the script file path via the -File parameter:
Windows PowerShell: C:\> powershell -file c:\test\test.ps1
PowerShell Core: C:\> pwsh -file c:\test\test.ps1
In other words: the PowerShell's executable name is
powershell.exe for Windows PowerShell,
vs. pwsh for the cross-platform PowerShell Core edition (with extension .exe on Windows).
If you do need remote execution:
Pass \\-prefixed machine name(s) or IP address(es) to psexec; e.g., the following command executes the hostname utility on machine somemachine:
psexec \\somemachine hostname
There is no benefit to using psexec without targeting a different machine.[1]
However, psexec is normally not needed, because PowerShell has built-in support for remoting (i.e., the ability to execute commands on other machines; remoting requires setup, however - run Get-Help about_Remote_FAQ for more information); e.g., the equivalent of the above command is:
Invoke-Command -ComputerName somemachine { hostname }
[1] As TheIncorrigible1 points out, psexec can also be used for local execution as the system account (NT AUTHORITY\SYSTEM, the account that represents the computer as a whole) with the -s option.
Additionally, you can also run locally as another user, using the -u parameter - which, however, the standard runas utility can do as well (the latter doesn't offer passing the target user's password as a parameter for security reasons, but does offer to securely save a password for later reuse).
Run psexec -h for help.
I am trying to execute a powershell script remotely using psexec like this:
.\psexec.exe \\remotecomputer -u domain\remoteuser -p password powershell.exe -c:\myscript.ps1
But the script does get executed remotely, but I see a 'security warning' when it get executed. On the remote machine, I already set 'Set-ExecutionPolicy bypass' in powershell. And when I executed the script 'c:\myscript.ps1 on that remote machine, I don't get any security warning. What can I do to get the powershell script executed remotely without security warning.
I am trying to use the Invoke-Command powershell cmdlet to install a MSI installer. From within powershell on the local machine and from the proper directory, the following works:
./setup /quiet
The following does not seem to work:
$script =
{
param($path)
cd "$path"
& ./setup /quiet
return pwd
}
return Invoke-Command -ComputerName $product.IPs -ScriptBlock $script -Args $sourcePath
For test purposes I am working on the local machine passing in "." for the -ComputerName argument. The paths have been verified correct before passing in to Invoke-Command, and errors generated on different versions of this code indicate the paths are correct. I have also tried with and without the "& " on the remote call to setup. Other Invoke-Command calls are working, so I doubt it is a permissions issue. I have verified that the return from the pwd call is the expected directory.
How do I get the install to work?
What error (if any) are you receiving? Unfortunately, you must run the shell as admin on your local machine to be able to connect to your local machine with invoke-command or any WINRM based command that requires administrative privilege (this is not a requirement when connecting remotely).
When connecting to loopback, I believe it is unable (for some security reason) to enumerate groups and determine if you are in an admin enabled AD or local group, which is how it auto elevates when invoking on a remote machine. The only solution may be to have a conditional which checks for localhost and if so, don't use the -ComputerName parameter.
This GitHub Issue covers it
You might try using Start-Process in your script block:
cd $path
start-process setup.exe -arg "/quiet"
Not sure if you will want or need to wait. Look at help for Start-Process.
I have had weird issues when trying to remotely execute a script on a local machine. In other words, remote powershell to the local machine. It comes back with an error that seems to say that PowerShell remoting is not enabled on the machine, but it was. I can run the script remotely from another machine to the target, but when using remoting to the same box, the issue crops up.
Verify that the WinRM service is running.
Verify powershell remoting has been enabled as in Enable-PSRemoting -force.
Verify your powershell execution policy is loose enough as in Set-ExecutionPolicy Unrestricted, for example. If the policy was set to RemoteSigned, this might be the problem.
You might also want to verify the user you are running the script as (locally, but using remoting) has privileges to "log on as a service" or as a batch job. Just guessing there, if the above list doesn't solve anything.