WMI Query Script as a Job - powershell

I have two scripts. One calls the other with a list of servers as parameters. The second query is designed to execute a WMI query. When I run it manually, it does this perfectly. When I try to run it as a job it hangs forever and I have to remove it.
For the sake of space here is the relevant part of the calling script:
ProcessServers.ps1
Start-Job -FilePath .\GetServerDetailsLight.ps1 -ArgumentList $sqlsrv,$destdb,$server,$instance
GetServerDetailsLight.ps1
param($sqlsrv,$destdb,$server,$instance)
$password = get-content C:\SQLPS\auth.txt | convertto-securestring
$credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist "DOMAIN\MYUSER",$password
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO')
$box_id = 0;
if ($sqlsrv.length -eq 0) {
write-output "No data passed"
break
}
function getinfo {
param(
[string]$svr,
[string]$inst
)
"Entered GetInfo with: $svr,$inst"
$cs = get-wmiobject win32_operatingsystem -computername $svr -credential $credentials -authentication 6 -Verbose -Debug |
select Name, Model, Manufacturer, Description, DNSHostName, Domain, DomainRole, PartOfDomain,
NumberOfProcessors, SystemType, TotalPhysicalMemory, UserName, Workgroup
write-output "WMI Results: $cs"
}
getinfo $server $instance
write-output "Complete"
Executed as a job it will show as 'running' forever:
PS C:\sqlps> Start-Job -FilePath .\GetServerDetailsLight.ps1 -ArgumentList DBSERVER,LOGDB,SERVER01,SERVER01
Id Name State HasMoreData Location Command
-- ---- ----- ----------- -------- -------
21 Job21 Running True localhost param($sqlsrv,$destdb,...
GAC Version Location
--- ------- --------
True v2.0.50727 C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.Smo\10.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.Smo.dll
getinfo MSDCHR01 MSDCHR01
Entered GetInfo with: SERVER01,SERVER01
The last output I ever get is the 'Entered GetInfo with: SERVER01,SERVER01'. If I run it manually like so: PS C:\sqlps> .\GetServerDetailsLight.ps1 DBSERVER LOGDB SERVER01 SERVER01
The WMI query executes just as expected.
I am trying to determine why this is, or at least a useful way to trap errors from within jobs.
Thanks!

This is one instance I could find. http://social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/a6c816dd-2c2c-47bc-a2d0-238fbb9d66a6
There are many other discussions I have seen around the same.
Anyway, to make sure your WMI respository isn't corrupt, just try re-compiling it. Put the following lines in a batch file and run:
net stop winmgmt
c:
cd c:\windows\system32\wbem
rd /S /Q repository
regsvr32 /s %systemroot%\system32\scecli.dll
regsvr32 /s %systemroot%\system32\userenv.dll
mofcomp cimwin32.mof
mofcomp cimwin32.mfl
mofcomp rsop.mof
mofcomp rsop.mfl
for /f %%s in ('dir /b /s *.dll') do regsvr32 /s %%s
for /f %%s in ('dir /b *.mof') do mofcomp %%s
for /f %%s in ('dir /b *.mfl') do mofcomp %%s
mofcomp exwmi.mof
mofcomp -n:root\cimv2\applications\exchange wbemcons.mof
mofcomp -n:root\cimv2\applications\exchange smtpcons.mof
mofcomp exmgmt.mof

Do yourself a favor and check WinRM. If remoting is turned off, you'll experience this exact set of symptoms.
Can *.ps1 scripts run as background jobs themselves execute *.ps1 scripts?
How do I debug a PowerShell background job?

Your script worked fine for me with the write credentials, but blocked when the credentials were wrong.

Related

PowerShell Script launching a batch file on remote systems locally

I have a simple batch file I need to run via PowerShell as a POC. I need the batch file to run concurrently with the other batch files.
Batch file on each server at c:\pathtofile\file.bat:
cd /d c:\
ping 127.0.0.1 -n 5 > null
ECHO test > c:\temp\echo.txt
time /t >> c:\temp\echo.txt
PowerShell script:
$servers = #(
"Server02",
"Server03",
"Server04",
"Server05",
"Server06")
$creds = Get-Credential
foreach ($server in $servers){
Invoke-Command -ComputerName "$Server" -Verbose -ScriptBlock {'cmd.exe c:\pathtofile\file.bat'} -Credential $creds
}
I've tried a million different things and I can't get the dang script to run. Help would be greatly appreciated.

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

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