Remote Schedule Windows Update and Shutdown with Powershell - powershell

I am currently trying to create an automation script with powershell.
The script I'm using is Force Install Updates on Remote Computer The script allows a remote computer to creates a scheduled task to perform a windows update on a host computer.
Question
How can I modify this script to shut down the remote computer after the scheduled task has updated the operating system?

Just add a new action to the scheduled task.
Action: Start a program
Program/script: shutdown
Add arguments: /p /f (to switch off)
Add arguments: /r /f /t 01 (to reboot)
Start in: <leave it empty>
A remote solution would be to start "shutdown.exe" with Powershell
Start-Process "shutdown.exe" -ArgumentList (" /s /f /t 01 /m \\{0}" -f $RemoteComputer) -NoNewWindow -Wait
Another one to use WMI, see Microsoft MSDN.
(Get-WmiObject -Class Win32_OperatingSystem -ComputerName $RemoteComputer -EnableAllPrivileges).Win32Shutdown(12)
Until Powershell 3 "Stop-Computer" is available, see Microsoft TechNet.
Stop-Computer -ComputerName $RemoteComputer

Related

Remotely running Acrobat Distller via powershell command line

I have a task to remotely run Acrobat Distller (AD) remotely.
I was able to locally run AD in the command prompt:
"C:\Program Files (x86)\Adobe\Acrobat DC\Acrobat\acrodist.exe" /O $OutputFolder $InputFolder\test.ps
I tried invoking the same command using powershell:
powershell.exe -NoExit -Command Invoke-Command -ComputerName $server -ScriptBlock {'"C:\Program Files (x86)\Adobe\Acrobat DC\Acrobat\acrodist.exe" /O $OutputFolder $InputFolder\test.ps'}
When ran, the powershell command did prompt any error BUT it did not generate the expected PDF output as well.
Can I get some assistance on what I am doing wrong here?
Thanks
You probably need to use $using:OutputFolder and $using:InputFolder.
Normally, powershell variables are only set for your session and don't carry over to remote servers. The $Using: format allows you to do this with Invoke-Command.

Executing CMD command remotely

I need to execute some commands remotely on computers and receive back input, to prevent calling every user and remote desktop to use CMD.
What I need to do:
Run CMD as admin, and run the two lines below and review the results. (On 30+ computers)
cd "c:\Program Files\Tenable\Nessus Agent"
nessuscli agent status --local
I tried:
wmic /node:COMPUTERNAME process call create "cmd.exe /c start"
It worked on my computer, but I think it opened the command prompt on the other persons computer when I tried this.
winrs -r:COMPUTERNAME CMD
WINRM apparently isn't enabled and I don't want to enable it if it's not already enabled.
$PC = (Read-Host "Enter Computer Name").ToUpper()
$PC cmd.exe --% /k cd "c:\Program Files\Tenable\Nessus Agent" & nessuscli agent status --local
write-host -f WHITE "Operation Complete."
I couldn't figure out how to make it work with a Powershell script in ISE.
I was able to run the below one from Powershell x86 as admin on my computer, but not sure how I would replicate to run it on an external computer.
cmd.exe --% /k cd "c:\Program Files\Tenable\Nessus Agent"
nessuscli agent status
EDIT
I created a .bat file and was able to launch it as admin, but it still requires input from the user to accept the cmd runas admin. Then I cannot see the results of the CMD on my end.
$PC = (Read-Host "Enter Computer Name").ToUpper()
#Change $xWare to your folder
[string]$RemoteStagingPath = '\\' + $PC + '\C$\Intel'
$xWare = "C:\Users\NAME\Desktop\"
$password= convertto-securestring $passwordTextBox.Text -asplaintext –force
$credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $userTextBox.Text,$password
$script = "C:\intel\cmd.bat"
#Runs Nessus
CP $xWare\cmd.bat $RemoteStagingPath
Start-Process powershell -Credential $credential -ArgumentList "-noprofile -command &{Start-Process $script -verb runas}"
write-host -f WHITE "Operation Complete."

Using PSRemoting to Install Dell Updates using dcu-cli.exe

First, this is not the same question as this question.
I am trying to use PSRemoting to run dcu-cli.exe on a remote system first to gather the version number and later to actually install the updates. PSEXEC is not an option for me. The version of dcu-cli.exe I am using is 3.1. For right now I just want to capture the output of the /version parameter.
Running the following command from PowerShell on my local machine produces the following output:
& "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" /version
Output:
Version information displayed: Dell Command | Update v3.1 Program exited with return code: 0
Here is what I've tried so far. Unless otherwise specified, the output is as follows. Sometimes the output is in a log file (depending on the command line):
An unexpected fatal error occurredProgram exited with return code: 2
From watching Process Explorer, it is actually running, but something somewhere is going wrong and I'm baffled as to what. Explicit credentials are not supplied as I am running the script as an administrator account and that account exists and is an administrator on the remote machine.
Any help would be appreciated.
Attempts:
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock {& "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" /version}
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock {& cmd.exe /c '"C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" /version'}
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock {& cmd.exe /c 'start "" /Wait "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" /version'}
No output
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock {& cmd.exe /c 'start "" /B /Wait "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" /version'}
$ScriptBlock={Start-Process -FilePath "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/version" -Wait -Verb "RunAs"}
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock $ScriptBlock
No output
$ScriptBlock={Start-Process -FilePath "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/version" -Wait -RedirectStandardOutput C:\temp\version.log}
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock $ScriptBlock
$ScriptBlock={Start-Process -FilePath "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/version" -Wait -PassThru -RedirectStandardOutput C:\temp\version.log}
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock $ScriptBlock
Process information is returned in addition to the normal erroneous output.
$ScriptText=#'
$ProcessInfo=[System.Diagnostics.ProcessStartInfo]::new("C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe")
$ProcessInfo.RedirectStandardError=$true
$ProcessInfo.RedirectStandardOutput=$true
$ProcessInfo.UseShellExecute=$false
$ProcessInfo.Arguments="/version"
$Process=[System.Diagnostics.Process]::new()
$Process.StartInfo=$ProcessInfo
$Process.Start() > $null
$Version=$Process.StandardOutput.ReadToEnd()
$Process.WaitForExit()
$Version
'#
$ScriptBlock=[System.Management.Automation.ScriptBlock]::Create($ScriptText)
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock $ScriptBlock
$ScriptText=#'
$ProcessInfo=[System.Diagnostics.ProcessStartInfo]::new("C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe")
$ProcessInfo.RedirectStandardError=$true
$ProcessInfo.RedirectStandardOutput=$true
$ProcessInfo.UseShellExecute=$false
$ProcessInfo.Arguments="/version"
$ProcessInfo.Verb="RunAs"
$Process=[System.Diagnostics.Process]::new()
$Process.StartInfo=$ProcessInfo
$Process.Start() > $null
$Version=$Process.StandardOutput.ReadToEnd()
$Process.WaitForExit()
$Version
'#
$ScriptBlock=[System.Management.Automation.ScriptBlock]::Create($ScriptText)
Invoke-Command -ComputerName $Destinations[0] -EnableNetworkAccess -ScriptBlock $ScriptBlock
(late answer... I know...)
You can run dcu-cli.exe remotely using either powershell or psexec
Powershell
the problem I had was figuring out how to pass "/applyUpdates" to dcu-cli instead of having it interpreted by powershell
Breaking the dcu-cli invocation into two separate steps works (cd ..., then .\dcu-cli)
I am logged in to my workstation as a user with local admin rights on the remote computer.
$pcname="ss-frontdesk"
$exePath="\program files\dell\commandupdate"
invoke-command -computername $pcname {cd "$using:exePath"; .\dcu-cli /applyUpdates -reboot=enable}
 
PSEXEC
now being blocked by sophos endpoint -- hence my research into powershell...
again, my local windows user is an admin on the remote workstation
set pcname=ss-frontdesk
set EXE=dcu-cli.exe
set DIR=C:\Program Files\Dell\CommandUpdate
set ARGS=/applyUpdates -reboot=enable
psexec \\%pcname% -s "%DIR%\%EXE%" %ARGS%
 
Notes
I've been using a batch file w/ psexec to update the bios on my dell workstations for 2 - 3 years
about 15% of the time, the bios will not update using dcu-cli. Sometimes it can then be updated by running Dell Command|Update manually over RDP, sometimes that doesn't work but running Dell Command|Update directly on the system works, and sometimes that doesn't work and I have to update the bios from a USB drive
You can get the bios version (if that's all you're looking for) using:
set pcname=ss-frontdesk
wmic /node:"%pcname%" bios get smbiosbiosversion |findstr /v "SMBIOSBIOSVersion" |findstr /r /v "^$"
wmic needs quotes around %pcname% if the name contains a dash as in the example
The "findstr" commands eliminate everything from the output except the bios version
Some of my systems have dcu-cli in "\Program Files (x86)" instead of in "\Program Files"...
[edit]
You can also use "sigcheck" from sysinternals to check the version of Dell Command|Update on remote systems if you have SMB access to C:\
#echo off
: F:\software\sysinternals contains sigcheck.exe...
set PATH=F:\software\sysinternals;%PATH%
setlocal enabledelayedexpansion
set PATHTOCHECK32=Program Files (x86)\Dell\CommandUpdate
set PATHTOCHECK64=Program Files\Dell\CommandUpdate
set FILETOCHECK=dcu-cli.exe
: Loop through all pc names included on the command line...
:start
if "%1"=="" goto :eof
call :checkit %1
shift
goto :start
:checkit
: note: PCNAME ends in 20 spaces (plus "x") for output formatting
ping -n 1 -w 1 %1 >nul 2>&1
if ERRORLEVEL 1 goto :noping
if exist "\\%1\c$\!PATHTOCHECK64!\!FILETOCHECK!" (
set PCNAME=%1 x
echo |set /p=!PCNAME:~0,20!
sigcheck -nobanner -n "\\%1\c$\!PATHTOCHECK64!\!FILETOCHECK!"
goto :eof
)
if exist "\\%1\c$\!PATHTOCHECK32!\!FILETOCHECK!" (
set PCNAME=%1 ^(x86^) x
echo |set /p=!PCNAME:~0,20!
sigcheck -nobanner -n "\\%1\c$\!PATHTOCHECK32!\!FILETOCHECK!"
goto :eof
)
set PCNAME=%1 x
echo |set /p=!PCNAME:~0,20!
echo dcu-cli.exe not found
goto :eof
:noping
set PCNAME=%1 x
echo |set /p=!PCNAME:~0,20!
echo not responding to PING
goto :eof
:eof

Installing an MSI file on a remote machine with PowerShell

I'm working on a utility to automate some processes and one task is to install a .msi file on a remote machine. The file is found in C:\Users\username on the remote machine and for simplicity's sake, the filename is file.msi. The command I'm using is:
Invoke-Command -ComputerName $remoteMachine -ScriptBlock{cmd /c start /wait msiexec /i $installPath /quiet}
When I execute this on my local dev machine, it doesn't show any errors, but doesn't install the file.
However, when I copy the exact command inside the brackets and run it in a PowerShell script on the remote machine, it installs successfully. I know my $remoteMachine is correct because I use it extensively throughout the rest of the script.
I know the $installPath variable also isn't the issue because for testing purposes I hardcoded the full path and it still doesn't install.
I also have proper permissions on the remote machine because earlier in the script I copy and paste the .msi from one machine to another without a problem.
I've tried a combination of commands and have been stuck here for a while, so any help would be greatly appreciated!
Ideally, this should work.
Invoke-Command -ComputerName $remoteMachine -ScriptBlock{msiexec /i $installPath /quiet}
The reason it is failing is coz you are not passing the $installPath as argumentlist. Modify it like this.
Invoke-Command -ComputerName $remoteMachine -ScriptBlock{
param(
[Parameter(Mandatory=$true,
Position=0)]
$installPath
)
cmd /c start /wait msiexec /i $installPath /quiet
} -ArgumentList $installPath
But if it isn't working, here is a workaround that I used a while ago.
Create a .bat file with the command msiexec /i $installPath /quiet and push it to the location just like you pushed the msi file.
Now from the invoke scriptblock, simply call the bat file instead.
Invoke-Command -ComputerName $remoteMachine -ScriptBlock{C:\Users\Username\Install.bat}
where Install.bat is the name of your bat file.
Note: You might want to use the /norestart switch as well if you are not looking to cause a reboot. Depends on what you are trying to install.
Beginning in PowerShell 3.0, you can use the Using scope modifier to identify a local variable in a remote command.
syntax of Using :- $Using:<VariableName>
In your case :
Invoke-Command -ComputerName $remoteMachine -ScriptBlock{cmd /c start /wait msiexec /i $Using:installPath /quiet}
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_variables?view=powershell-7.2#using-local-variables

Get PID on remote computer via service name

I need to kill a process behind a service on a remote computer with PowerShell for a program/script I am creating.
The problem is that the process doesn't always have the same PID and the name is not always the same either. The only thing that always is the same is the name.
I have found out that I can get the PID of the service with this command:
taskkill /s rasmuspc /u rasmus123 /p 12345 /PID (Get-WmiObject Win32_Service|where{$_.Name -eq 'Spooler'}).ProcessID /F
I use this command to skip tasklist, so I can make it automated instead of manually looking up and typing in the PID.
But that command will only get the PID from my own computer, and I can't see is there a way to to get the PID of a service on a remote PC, only knowing the name of the service?
Taskkill /s rasmuspc /u rasmus123 /p 12345 /PID (Get-WmiObject -CN $remotepcname -filter 'name="spooler"}).processID /F
Thanks to Mathias R. Jessen, this command worked.
tasklist /s Server name.
This can be used to get the list of tasks running on a remote server
try this
Get-Process -ComputerName "ServerName" -Name notepad | stop-Process
you need to have able in the remote machine to stop process
To kill a corresponding process in Powershell, one line:
Get-Process -PID (Get-WmiObject -CN $RemotePCName -filter 'name="spooler"' -Class Win32_service).processID | Stop-Process -Force