Remote ipconfig /release issue with powershell - powershell

I have a powershell script that does an ipconfig /release and /flushdns then a shutdown command for my VMs. I do this before creating a snapshot. The script works but it doesn't work for multiple computers in a CSV because as soon as the ipconfig /release occurs it gets stuck on the same machine and waits for it to reconnect. Is there a way to break the script so that it forces to go to the next machine? It's doing the shutdown as well just not moving onto next machine. Code:
$Machines | foreach-object {
write-host $_.MachineName
Get-Service -Computer $_.MachineName -Name CcmExec | Stop-Service
Get-Service -Computer $_.MachineName -Name CcmExec | Set-Service -StartupType Disabled
Get-Service -Computer $_.MachineName -Name CcmExec
Invoke-Command -Computer $_.MachineName -ScriptBlock {
Add-LocalGroupMember -Group "Administrators" -Member $Using:Username
Get-ScheduledTask -TaskPath "\Microsoft\Configuration Manager\" | Disable-ScheduledTask
cmd.exe /c ipconfig /flushdns
cmd.exe /c ipconfig /release
cmd.exe /c shutdown -f -s -t 25
}
}

Just as I was laying down to go to sleep last night, this popped into my head. Why, how, I don't know!
What happens if you change
cmd.exe /c ipconfig /flushdns
cmd.exe /c ipconfig /release
cmd.exe /c shutdown -f -s -t 25
to
cmd.exe /c shutdown -f -s -t 300
cmd.exe /c ipconfig /flushdns
cmd.exe /c ipconfig /release
?
I would think any termination of the remote ran scriptblock would result in the caller continuing on to do other work.

Related

Switch service running state using powershell (using UAC prompts)

$serviceName = "wsearch"
$isRunning = Get-Service | Where-Object {$_.Status -eq "Running" -and $_.Name -eq $serviceName}
$isStopped = Get-Service | Where-Object {$_.Status -eq "Stopped" -and $_.Name -eq $serviceName}
if ($isStopped) {
Start-Service -InputObject $isStopped
Start-Sleep -s 10
}
if ($isRunning) {
Stop-Service -InputObject $isRunning
Start-Sleep -s 10
}
I want to run this script, but I don't want to set Administrator execution policy (which is set to max restrictive), while regular user policy is lax.
I want to run the script as a regular user and trigger the UAC prompt for each command (akin to -Verb RunAs), however, Start-Service does not accept this parameter.
I guess I can run a Start-Process "sc" but that defeats the purpose of powershell.
The ultimate goal of the script is to swtich the state of a service based on the current running state.
There is no way to run one-off commands elevated (as admin) in a non-elevated powershell session. This would be similar to 'sudo' in Linux which just doesn't exist in the Windows world. Instead you could use something like the following to start a powershell session as administrator and run the commands there. You are not limited to calling 'sc'
Start-Process -Verb RunAs -FilePath 'powershell' -Arguments '-Command <your commands>'
To run a powershell script with elevated privileges you could substitute -Command for -File (but -Command <path to file> will also work)
Start-Process -Verb RunAs -FilePath 'powershell' -Arguments '-File <path to script>'

using cmd in powershell properly

at the moment i install a programm to a remote machine with batch. thats already working fine.
but how can i use or "convert" the batch command below in powershell using the specific command for the prgramm to install it silent on the remote machine?
this is my batch code.
set /p target=hostname
echo.
copy /z "\\server1\tool.exe" "\\%target%\C$\temp"
echo.
PsExec.exe \\%target% cmd /c "\\%target%\C$\temp\tool.exe" /verysilent
$target=hostname
Copy-Item -Path "\\server1\tool.exe" -Destination "\\$target\C$\temp"
Invoke-Command -ScriptBlock \\%target%\C$\temp\tool.exe -ComputerName $target -credential (USERNAME)
for the Invoke-Command -Scriptblock is the command you want to run, -ComputerName is the computer you want to start a process on, -Credential is the username to use to run the command. You will automatically be prompted to enter your password.
Thanky guys for your answers.
i did like that
$target = Read-Host "hostname"
Copy-Item -Path "\\server1\tool.exe" -Destination "\\$target\C$\temp"
PsExec.exe \\$target -s winrm.cmd quickconfig -q
Invoke-Command -ComputerName $target -ScriptBlock {
cmd /c "C:\temp\tool.exe" /verysilent
}

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

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

Powershell process 'hanging' when running remote batch file

I'm trying to run a batch file on a remote server via a drive mapping as follows, but the process hangs...
Enable-WSManCredSSP -Role Client -DelegateComputer someserver -Force
$credential = Get-Credential -Credential domain\user (then I supply the password in the popup)
$RemoteSession = New-PSSession -ComputerName someserver -Credential $credential -Authentication Credssp
Invoke-Command -Session $RemoteSession -ScriptBlock { Enable-WSManCredSSP -Role Server -Force }
Invoke-Command -Session $RemoteSession -ScriptBlock { New-PSDrive -Name I -PSProvider FileSystem -Root \\server\share$ }
Everything seems fine up to this point and I can 'dir' the I drive and see the expected content.
When I execute the following, the process hangs -
Invoke-Command -Session $RemoteSession -ScriptBlock { Start-Process I:\temp.bat }
The temp.bat file executes the following command and I've verified manually that it works
echo Scott was here > C:\temp.txt
However, the command runs for over 5 minutes without any response.
Can anyone help? What have I done wrong?
Although this is not a direct solution to your question, my suggestion from many weeks of banging my head against my keyboard is to just take a different path.
$taskName = whocares
$command = I:\Temp.bat
$serverName = theServer
$userName = domain\user
$pass = pl4inT3xtPassword
$date = (Get-Date).addMinutes(1)
$formats = $date.getDateTimeFormats()
$startTime = $formats[113]
schtasks.exe /create /sc ONCE /tn $taskName /tr $command /s $serverName /u $userName /p $pass /ru $userName /rp $pass /st $startTime
This will create a task, start the process in the next minute, and then remove itself from the scheduler. There is also a /z flag in there to remove after it runs, but if your like me and on XP then this probably won't be available to you. If you notice your task isnt being removed after it runs you can always wait a minute and then kill it... or you can get a little bit more fancy with it:
while(($timer -lt 60) -and (!$running)) {
schtasks.exe /query /S $serverName /FO CSV /v /u $userName /p $pass | ConvertFrom-CSV | `
% {if($_.Status -eq "Running") {
Write-Host "IT WORKED!"
Write-host $_
$running = $true
}
}
if(!$running) {
$timer++
}
sleep 1
}
schtasks.exe /delete /s $serverName /u $userName /p $pass /tn $taskName /f
This bit just queries the task every second to check if its running... once it is it will delete the old scheduled task and your process will continue to run (until its finished).
The task scheduler is the only clean way I have found to start processes remotely with PowerShell. Instead of being a child process of your PSremote.exe, it will be under System. Also, unlike remote-session, if you X out of your powershell session, the process will persist on the remote computer.
I know it is a lot more than just your one liner, but I hope it is useful, and if you parameterize it or even build a windows forms application on top it will save you a lot of time and headache.
more on schtasks Here
Thanks for your suggestions.
Due to other issues (with the process that we're ultimately trying to run), we've put this down for the minute, without finding a solution
Thanks for your help and suggestions. Will hopefully pick this back up in a few weeks
Scott
Try putting an -AsJob at the end of your Invoke-Command lines?
As an FYI if Invoke-Command always hangs it may be the service or firewall:
Try a simple command to system :
Invoke-Command -ComputerName XXXXX -ScriptBlock { Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion }
Start the Windows Remote Management Service (on that system)
Check for the listening port:
netstat -aon | findstr "5985"
TCP 0.0.0.0:5985 0.0.0.0:0 LISTENING 4
TCP [::]:5985 [::]:0 LISTENING 4