Background jobs stops after a few minutes - powershell

See below a simplified version of my PowerShell code.
$cred = Import-Clixml d:\cred.xml
Invoke-Command -ComputerName $computer -Authentication Credssp -Credential $cred -InDisconnectedSession -SessionOption #{OutputBufferingMode="Drop";IdleTimeout=2147483647} -Scriptblock {
$start_job = Start-Job -Scriptblock {
foreach ($user in $list) {
$a = Get-ChildItem -LiteralPath $user -Recurse -Force
Write-Output "$a.Count" | Out-File c:\test.log -Append
} -ArgumentList $list
}
I would send a list of maybe 30 names but after a few minutes of scanning the operations would stop without any error reported, it seems as if the Start-Job is blocked or suspended as the Invoke-Command is still running.
any idea on how to check or bypass this limitation?

Related

Invoke-Command only running on the last node in an array

I have a total of 3 servers with 2 folders on each server that have an .exe I need to execute from their respective locations. Below is my current code. What is happening is the output is showing the code gets run but when I log into those servers, the .exe is not running. However, every time the last node works perfectly fine. I'm lost.
Here is my current code:
Foreach ($server in $NodeArray) {
# $NodeArray consists of server1, server2 and server3
$Session = New-PSSession -ComputerName $server -Authentication Negotiate -Credential $HPCSlaveCreds -ErrorAction Stop
$Scriptblock = {
param ($MasterNode, $ControlFile)
$FolderName = (Get-ChildItem 'C:\HPC' | select -last 1).name
$Path = (Get-ChildItem "C:\HPC\$FolderName" -Recurse -Filter "Agent*").Name
foreach ($agent in $Path) {
$PestArguments = "$ControlFile /H ${MasterNode}:4004"
Write-Host "Starting Beopest on $env:COMPUTERNAME - $PestArguments"
Start-Process -FilePath "pestpp-ies.exe" -WorkingDirectory "C:\HPC\$FolderName\$agent" -ArgumentList $PestArguments
}
}
Invoke-Command -Session $Session -ScriptBlock $ScriptBlock -ArgumentList $MasterNode, $ControlFile
}
Any help would be greatly appreciated!

Run Remote Command via Powershell

I'm trying to invoke discrete CLI commands on a series of remote systems via a script, and I can't get any PowerShell commands to accept them. Rather than try to explain the specifics of the issue, I'll provide some pseudocode of what I'm trying to do below.
Please note that this is just a simple example. Using the stop-service command is not an option. These are explicit commands used via CLI with via the Splunk program that I need to run in this order.
In short, I just can not figure out how to tell PowerShell to run a CLI command verbatim on a remote machine.
foreach ($server in $list)
cd C:\Program Files\SplunkUniversalForwarder\bin
splunk stop
splunk clone-prep-clear-config
splunk start
Bunch of ways you can do this. Using WMI c/o Powershell:
Starting,Stopping and Restarting Remote Services with PowerShell
You can also use Windows remoting, but I'd start here.
You could try...
Foreach($server in $list)
{
Invoke-command -computername $server -scripblock {
$splunkpath = 'c:\program files\splunkuniversalforwarder\bin\splunk.exe'
Start-process -filepath $splunkpath -argumentlist 'stop' -wait -nonewwindow
Start-process -filepath $splunkpath -argumentlist 'clone-prep-clear-config' -wait -nonewwindow
Start-process -filepath $splunkpath -argumentlist 'start' -wait -nonewwindow
}
}
Note: you may need to remove the -wait and/or -nonewwindow from the commands depending on how your process behaves.
There are also output redirection parameters checkout the docs below for more.
Invoke-command
Start-process
I literally just did this this morning. This is the main part I came up with.
foreach($server in $servers){
Write-Host "From " -nonewline; Write-Host "$server" -ForegroundColor Yellow
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe stop } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe clone-prep-clear-config } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe start } -Credential $cred
}
my full code is below:
#Author: Christopher Boillot
#Clear config of Splunk Forwarder
[CmdletBinding()]
Param ([Parameter(Mandatory=$False,Position=0)]
[String[]]$servers = (Get-Content C:\ClearConfig.txt))
Set-Location $PSScriptRoot
#User login
$User = "user.txt"
$FileExists = Test-Path $User
If ($FileExists -eq $False) {
Write-Host "Enter your user name. This will be saved as $User"
read-host | out-file $User
}
$Pass = "securepass.txt"
$FileExists = Test-Path $Pass
If ($FileExists -eq $False) {
Write-Host "Enter your password. This will be saved as an encrypted sting as $Pass"
read-host -assecurestring | convertfrom-securestring | out-file $Pass
}
$username = cat $User
$password = cat $Pass | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
#go through each server in list
foreach($server in $servers){
Write-Host "From " -nonewline; Write-Host "$server" -ForegroundColor Yellow
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe stop } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe clone-prep-clear-config } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe start } -Credential $cred
}

Enter PSSession with Variable for ComputerName

I am trying to enter a PSSession using -Computername $Server which was previously defined, but I can't seem to get this to work.
I have tried single, double, and no quotes around the variable at all. What am I doing wrong?
$Servers = Import-Csv "C:\Users\username\Desktop\DNS.csv"
$secpass = ConvertTo-SecureString 'mypassword' -AsPlainText -Force
$myCred = New-Object System.Management.Automation.PSCredential("username", $secpass)
foreach ($Object in $Servers) {
$Server = $Object.Name
Enter-PSSession -ComputerName "$Server" -Credential $myCred
sl HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters
Invoke-Command -ScriptBlock {Get-Item -Path HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters}
Exit-PSSession
}
We use enter pssession for creating an interactive session with the remote computer.
In your case, you do not need to have an interaction with the remote system. You just need to fetch the details from the remote systems which are present in the csv file.
So, Instead of this:
foreach($Object in $Servers) {
$Server = $Object.Name
Enter-PSSession -ComputerName "$Server" -Credential $myCred
sl HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters
Invoke-Command -ScriptBlock {Get-Item -Path HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters}
Exit-PSSession
}
Do This:
foreach($Object in $Servers)
{
$Server = $Object.Name
Invoke-Command -ComputerName $Server -ScriptBlock {Get-Item -Path HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters} -Credential $myCred
}
Note: I believe you have enabled PSRemoting and have edited trusted hosts.
The ComputerName param of Invoke-Command will accept an array of servers so you can do away with the foreach loop entirely and simplify your code to:
$Servers = Import-Csv "C:\Users\username\Desktop\DNS.csv" | Select-Object -ExpandProperty Name
$secpass = ConvertTo-SecureString 'mypassword' -AsPlainText -Force
$myCred = New-Object System.Management.Automation.PSCredential("username", $secpass)
Invoke-Command -ComputerName $Servers -ScriptBlock {Get-Item -Path HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters} -Credential $myCred

Remote management with powershell

I'm trying to get some information from several machines on the network but I get loads of entries of the local machine.. for each entry in the text file I get an entry from the local machine.
Any idea where I'm going wrong.. winrm is configured on the remote machines and running.
$Username = Read-Host "Please enter Username"
$Password = read-host "please enter Password"
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
$computers = gc c:\test\file.txt
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computers -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
cls
Thanks in advance :)
Invoke-Command will take an array for the ComputerName param so you can use $computers instead of using a foreach loop (assuming that you have one computer name per-line in the file).
I've also used Get-Credential to prompt for the full credential in one go rather than asking for username and password individually.
$Cred = Get-Credential
$computers = Get-Content c:\test\file.txt
Invoke-Command -ComputerName $computers -Credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | Out-File c:\test\output.txt -Append}
The reason you are only seeing a single computers info in c:\test\output.txt is because the output of the the ipconfig command is being saved to the remote computer... so you will have a c:\test\output.txt file on each computer you run the command against.
EDIT:
To take the output of each remote command and save it to your local computer just move the Out-File outside the Invoke-Command like this:
$Cred = Get-Credential
$computers = Get-Content c:\test\file.txt
Invoke-Command -ComputerName $computers -Credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'"} | Out-File c:\test\output.txt -Append
The issue is you are iterating one by one but you are not passing one by one to the invoke-command, $computer will have each value at a time in the foreach loop.
Instead of this:
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computers -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
Do this:
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computer -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
Further improvement:
You do not have to give Invoke-Expression -Command:"cmd.exe /c 'ipconfig'"
Instead of this,you can directly use ipconfig inside the scriptblock.

Remote Registry using Enter-PSSession

I am trying to read strings in a remote registry. When I run the script I am working on, it connects to the workstation in the list, but it only reads the local computer when running, not the remote. any Ideas?
#create open dialog box
Function Get-FileName($initialDirectory)
{
[void] [Reflection.Assembly]::LoadWithPartialName( 'System.Windows.Forms' );
$d = New-Object Windows.Forms.OpenFileDialog;
$d.ShowHelp = $True;
$d.filter = "Comma Separated Value (*.csv)| *.csv";
$d.ShowDialog( ) | Out-Null;
$d.filename;
}
# Set Variables with arguments
$strFile = Get-FileName;
$strComputer = Get-Content $strFile;
$date = Get-Date -Format "MM-dd-yyyy";
$outputFile = "C:\PowerShell\Reports";
$cred = Get-Credential
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
..
..
}
The above code won't work. Enter-PSSession is not for using in a script. Anything written after that in a script won't run.
Instead, use Invoke-Command and pass rest of the script block as a parameter value. For example,
foreach ($computer in $strComputer) {
Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
}
As the comments already explained, Enter-PSSession is for interactive use. To read remote registry entries, there are several ways.
Use plain reg.exe, it works well enough. Like so,
foreach($computer in $strComputers) {
reg query \\$computer\hklm\software\Microsoft\Windows\CurrentVersion\Reliability /v LastComputerName
}
Use PSSessions. Create a session and Invoke-Command to read registry. Like so,
function GetRegistryValues {
param($rpath, $ivalue)
Set-Location $rpath
$systemInfo = (Get-ItemProperty .).$ivalue
Write-Host $systemInfo
}
$session = New-PSSession -ComputerName $computer
Invoke-Command -Session $session -Scriptblock ${function:GetRegistryValues} `
-argumentlist "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability",`
"LastComputerName"
Remove-PSSession $session
Use .Net classes, Microsoft.Win32.RegistryKey. Like so,
$sk = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $server)
$k = $sk.opensubkey("SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability", $false)
write-host $k.getvalue("LastComputerName")