PowerShell Invoke-Command -AsJob - powershell

The script I wrote is pretty long but works fine except for one problem. When I have more jobs for the same $Server it's only submitting one job and doesn't execute the second or third job for the same $Server.
The input comes from a CSV-file in this format:
\\domain\SHARE\Target3, 0
BELSFBRUS0131, E:\DEPARTMENTS\CBR\SHARE\Target2, 0
BELSFBRUS0131, E:\DEPARTMENTS\CBR\SHARE\Target4, 0
In the example above the script only starts 2 jobs, one for the UNC-path Target3 and one for Target2 on BELSFBRUS0131, these are executed fine. But there's no job launched for Target4to the same server... Is this maybe a restriction of Invoke-Command to only launch once to each server?
Thank you for your help guys.
Here is the important part of the script (due to max. 30.000 lines, I limited it):
Foreach ($_ in $File) {
# Starting jobs
if (($Server -eq "UNC") -or ($Server -eq "$env:COMPUTERNAME")) {
Write-Host "$(Get-TimeStamp) $env:COMPUTERNAME > Start job: local > $Server, $Target, $OlderThanDays, $LogFolder, $CleanFolders" -ForegroundColor Gray
$arrayAllJobs += Start-Job -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server, $LogFolder, $CleanFolders) -Name DelFiles
}
else {
Write-Host "$(Get-TimeStamp) $env:COMPUTERNAME > Start job: Remote > $Server, $Target, $OlderThanDays, $LogFolder, $CleanFolders" -ForegroundColor Gray
$arrayAllJobs += Invoke-Command -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server, $LogFolder, $CleanFolders) -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -AsJob -JobName DelFiles
}
}
#__________________________________________________________________________________________________________________________________
# Checking jobs
Write-Host "`n$(Get-TimeStamp) $env:COMPUTERNAME > Waiting for all jobs to finish.." -ForegroundColor Cyan; Wait-Job -Job $arrayAllJobs
Write-Host "`n$(Get-TimeStamp) $env:COMPUTERNAME > The targets were:" -ForegroundColor Cyan; $arrayAllPaths | Format-List
foreach ($Job in $arrayAllJobs) {
if ($job.State -ne 'Completed') {
# Write-Host ($Job.ChildJobs[0].JobStateInfo.Reason.Message) -ForegroundColor Red
$arrayJobError += $Job.ChildJobs[0].JobStateInfo.Reason.Message
$HTMLarrayJobError += $Job.ChildJobs[0].JobStateInfo.Reason.Message +"<br>"
}
#<# Reported success:
else {
Write-Host (Receive-Job $Job) -ForegroundColor Green
} #>
}

I suspect it related to the fact that all of your jobs are being created with the same JobName:
Invoke-Command -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server, $LogFolder, $CleanFolders) -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -AsJob -JobName DelFiles
so you're trying to create two jobs with the same name, on the same server.

I made a previous error in my script, that was the reason why the seconde server didn't arrive in the loop. I'm sorry everyone, my bad.

Related

Powershell | get a value from 2 nested invoke commands

i want to transfer the values from the invoke commands to local. I have problems to get the values from the second invoke command. I want $computers and $tasks in the textbox. Any Ideas? I have tried with return but then i can only get the values from first invoke command.
EDITED:
$session = New-PSSession -ComputerName $remote -Credential $cred
Invoke-Command -Session $session -ScriptBlock {
### get all computers in Domain ###
$computers = dsquery computer "DC=kanzlei,DC=local" -o rdn
Write-Host ("In dieser Domäne gibt es die folgenden Server:")
write-host $computers
#configure all computers
foreach($computer in $computers) {
$session3 = New-PSSession -ComputerName $remote -Credential $cred_session
Invoke-Command -Session $session3 -ScriptBlock {
write-host "Tasks for $env:computername gonna be activated"
#### acitivate tasks ####
$tasks = Get-ScheduledTask -TaskPath "\RA-MICRO_Update_Routine\" | Enable-ScheduledTask | FL Taskname,State }
write-host "$tasks"
}
}
}
##### I want vriable $Computers and $Tasks here on Local ####
do anything with $tasks
do anything with $computers

LastExitCode of invoke-command does not match condition

I am running script through jenkins and the Invoke command should fail as the file already exits and should reach exit code 1 and error out and show a fail in jenkins but instead it still is exiting 0 as green
I have tried using Try catch and using $? but still cannot get this to show as red when failure
$Time = $args[1]
$Server = $args[2]
$username = $args[3]
$password = $args[4]
$pass="$password"|ConvertTo-SecureString -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PsCredential("ad\$username",$pass)
$session = New-PSSession -ComputerName $Server -Credential $Cred -ErrorAction Stop
Invoke-Command -Session $session -ScriptBlock {netsh trace start capture=yes tracefile=C:\Traces\netsh.etl}
If ($LastExitCode -eq 1)
{
exit 1
}
write-host "hello world"
start-sleep -Seconds $Time
Invoke-command -Session $session -ScriptBlock {netsh trace stop}
If ($LastExitCode -eq 1)
{
exit 1
}
exit 0
The file already exists which should be expected but not reaching the exit 1 inside either if statements when it should.
The $LastExistCode you are testing is on the local system, but you are running the command on a remote system. Try returning the $LastExistCode at the end of your scriptblock and test the result of the Invoke-Command
For example:
$result = Invoke-command -Session $session -ScriptBlock {netsh trace stop; $LastExitCode}
If ($result -eq 1)
{
exit 1
}
This assumes that netsh itself doesn't return anything (I didn't test it). If it does, you can typically supress the output by piping it to Out-Null:
Invoke-command -Session $session -ScriptBlock {netsh trace stop | Out-Null; $LastExitCode}

Background jobs stops after a few minutes

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?

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
}

Check the AppPool status through power-shell and start that on remote machine

The requirement is to extract the server name one by one and check the AppPool status, if that is found to be stopped, make it running. below code is not helping out.
$ErrorActionPreference = "Continue"
$status = gc -path "D:\Servers\server.txt"|ForEach-Object (invoke-command -ComputerName $_ -ScriptBlock {Import-Module Webadministration Get-WebAppPoolState -name (gc "D:\AppPool.txt")})
if ($status.value -eq "Started")
{
Write-Host ("ApppPool already running")
}
else
{
Invoke-Command -ScriptBlock {Start-WebAppPool}
Write-host ("AppPool has started successfully")
}
There were multiple problems with your code, I've gone through them individually so you can see what was stopping it from working correctly.
The syntax for foreach was wrong, you needed to use {} not () in this case. Normal brackets are only used like this ForEach ($number in $numArray ) {CODE} which you aren't.
You were checking $status outside the foreach loop - so it so was evaluating $status only once (with the final computers AppPool status) rather than for each computer.
Your second Invoke-Command didn't have a ComputerName parameter specified so was only running the command locally not against the remote computer, meaning the AppPool would never be started.
As you were specifying the AppPool name using gc "D:\AppPool.txt" this file would have to be present on every remote computer for it to work. I've changed this to be passed into the command as an argument so the file only needs to be on the computer running the script.
$Credentials = Get-Credential
$AppPools = Get-Content "D:\AppPool.txt"
$Servers = Get-Content -Path "D:\Servers\server.txt"
ForEach ($Server in $Servers) {
ForEach ($AppPool in $AppPools) {
$AppPoolState = Invoke-Command -ComputerName $Server -ScriptBlock {Import-Module WebAdministration; Get-WebAppPoolState -Name $args[0] } -ArgumentList $AppPool -Credential $Credentials
if ($AppPoolState.Value -eq "Started")
{
Write-Host "$AppPool AppPool already running on $Server"
}
else
{
Invoke-Command -ComputerName $Server -ScriptBlock {Start-WebAppPool -Name $args[0] } -ArgumentList $AppPool -Credential $Credentials
Write-Host "$AppPool AppPool started on $Server"
}
}
}
Note: I run a non-privileged account so have to supply Credentials. If the account you're running the script as has appropriate permissions to all the remote computers you can remove the three Credentials references.