How to add an element back into an array - arrays

First off, I am new to Powershell, so please excuse any poor coding here.
I'm trying to write a script that queues commands. We have a piece of equipment that can only handle 32 commands at one time. What I want to do is build a command file that has many more than 32 commands and then it automatically queues any command after 32 until another free slot opens up. Everything seems to be working except when I go into my 'else' statement. I attempt to add the current $_ back into the array so it doesn't get lost and gets reprocessed, but this does not seem to be working.
I build my array from a text file:
$commands = #(Get-Content C:\scripts\temp\commands.txt)
When I try to add the current $_ value back into the array during the 'else' pause statement, it never adds back in, so that one particular command never enters back into the array. So if my script has to pause 15 times, 15 commands will never get ran as they just get processed by the 'else' statement and get thrown out of my 'if/else' loop.
Here's my if/else loop:
$commands | ForEach-Object {
If (Test-Path C:\scripts\temp\active_migrations.txt){
Remove-Item C:\scripts\temp\active_migrations.txt
}
CMD.EXE /C "ssh $user#$cluster -pw $PlainPassword lsmigrate" > C:\scripts\temp\active_migrations.txt
$count = Get-Content C:\scripts\temp\active_migrations.txt
$number_of_migrations = $count.Length / 6
IF ($number_of_migrations -lt 32)
{
Write-Host "Migrations are currently at $number_of_migrations. Proceeding with next vdisk migration."
Write-Host "Issuing command $_"
Write-Host "There are still $migrations_left migrations to execute of $total_migrations total."
Write-Host ""
CMD.EXE /C "ssh $user#$cluster -pw $PlainPassword $_"
SLEEP 2
$migrations_left--
}
ELSE
{
Write-Host "Migrations are currently at $number_of_migrations. Sleeping for 1 minute"
$commands = #($commands + $_)
Write-Host "There are still $migrations_left migrations to execute of $total_migrations total."
SLEEP 60
}}
}
Any help is much appreciated.

Thank you Paul. I ended up dumping things during the else statement to a temp array and it works! Appreciate the assistance.
function commands_temp
{
if (Test-Path C:\scripts\temp\commands_temp.txt)
{
$commands=#()
$commands=#(Get-Content C:\scripts\temp\commands_temp.txt)
Remove-Item C:\scripts\temp\commands_temp.txt
Proceed
}
Else
{
Write-Host "All migrations are either complete or successfully executed. Check the GUI or run lsmigrate CLI command for full status."

Related

How to add a delay after getting the list before starting the loop in the shell script

Below script list, the files, change the permissions on the file and moving it to a different folder. Sometimes the script is moving the file before the contents fully generated.
Need to add a delay after getting the list before starting the loop. Is this possible? Please help how to achieve this scenario to implement.
Can we use the sleep command to achieve this?
Script to change the file permissions and move it to main folder
function starts here
function mv_purge_files
{
cd $SRC
if  [ "$?" = "0" ]; then
for c in $(/usr/bin/ls *)
do
echo "ext: changing file permission $c"
/usr/bin/chmod 775 $c
echo "ext: moving $c"
/usr/bin/mv $c $TGT/$c
done
else
echo "Error accessing folder " $SRC
fi
}
program starts here 
SRC=/temp/file.in
TGT=/tgt/purge
mv_purge_files

Powershell displaying all contents of array instead of stepping through one at a time

I'm new to powershell and I'm working on a script that opens edge and searches bing for a specific term. I have an array of terms, and a for loop that steps through the array. The loop works but instead of displaying one array item on each loop all items are being used. Here's my script:
#create dictionary
$diction = #("iphone","android","untidy","stew","camp","fresh","groan","warlike","party","bake","zephyr","play","lamp")
#loop
For ($i=0; $i -lt $diction.Length; $i++) {
start microsoft-edge:http://www.bing.com/search?q=$diction[$i]
Start-Sleep -s 5
TASKKILL /IM MicrosoftEdge.exe
}
Read-Host -Prompt "Press Enter to exit"
Instead of
http://www.bing.com/search?q=iphone
then http://www.bing.com/search?q=android and so on the actual result is
http://wwwbing.com/search?q= iphone android untidy stew camp fresh groan warlike party bake zephyr play lamp
Am I missing something on how to display an array item in powershell?
Any help is appreciated, thanks in advance.
Update your code like this. Also, by using a variable for your command, you can use a debugger like ISE or VSCode to actually see what is being passed.
$cmd = "microsoft-edge:http://www.bing.com/search?q=$($diction[$i])"
start $cmd
If you are doing powershell you should pipe | instead of that for statement
During the pipe the value passed is stored as $_
The Foreach-object alais is %
Basically is the array piped to a foreach-object
"iphone","android","untidy","stew","camp","fresh","groan","warlike","party","bake","zephyr","play","lamp" |
%{
start microsoft-edge:http://www.bing.com/search?q=$_
Start-Sleep -s 5
TASKKILL /IM MicrosoftEdge.exe
}
Read-Host -Prompt "Press Enter to exit"

Pass String Array Varaible from Command Line (.BAT file) to Power Shell Script

I am trying to pass an array %variable% from command line to power shell and then perform operations with this array variable within power shell but I am having trouble passing the variable to power shell correctly. Current .BAT script to call power shell script is below...
SET STRING_ARRAY="test1" "test2" "test3" "test4"
Powershell.exe -executionpolicy remotesigned -File "FILEPATH\Build_DB.ps1" %STRING_ARRAY%
Then power shell script below to test for a sucessful handover of the array varaible is as follows:
$string_array=#($args[0])
Write-Host $string_array.length
for ($i=0; $i -lt $string_array.length; $i++) {
Write-Host $string_array[$i]
}
However all is returned is a length of 1 from power shell. What am I doing wrong here?
Alright, never mind I ended up coming up with a solution that works in my case so I am posting it here in case it is of benefit to anyone else. If someone has a better solution please let me know.
Change the power shell script as follows:
#The problem is that each item in the %STRING_ARRAY% variable is passed as
#an individual argument to power shell. To get around this we can just
#store all optional arguments passed to power shell as follows.
$string_array=#($args)
#Now (if desired) we can also remove any optional arguments we don't want
#in our new array using the following command.
$string_array = $string_array[2..($string_array.Length)]
Write-Host $string_array.length
for ($i=0; $i -lt $string_array.length; $i++) {
Write-Host $string_array[$i]
}

How to check if a scheduled Powershell script has failed to run in Nagios

I have a requirement where I need to be notified when a scheduled Powershell script fails at any point of time. I would like to configure a Nagios service for this, and need someone to point me in the right direction.
Cheers.
Shadab
There may be a power shell-specific way of doing this, but let me give you two ideas:
1) is there some output of the program that you can monitor? A log file that gets touched when the script runs, etc? If so, you can monitor that file in nagios.
or,
2) can you modify the script to send an "I finished" message to nagios? If so, you can setup a notification when that message has not been received (goes "stale").
You need to use exit codes. Check out documentation on Nagios Plugin API, but below are the exit/return codes you should use in your script:
Plugin Return Code Service State Host State
0 OK UP
1 WARNING UP or DOWN/UNREACHABLE
2 CRITICAL DOWN/UNREACHABLE
3 UNKNOWN DOWN/UNREACHABLE
Here's an example of a script I wrote for an Icinga check, maybe this will help give you some ideas?: (http://www.baremetalwaveform.com/?p=311 for full article)
$state = (rstcli64 --information --volume 2> Out-Null | select-string -Pattern "State:") -split "`r"
If (
($state.count -gt 0) -and ($state.count -eq ($state | Where-Object -FilterScript {$_ -match "Normal"}).count)
)
{
#OK
Write-Host "RST Volume state OK"
exit 0
}
If (
$state.count -eq 0
)
{
#UNKNOWN
Write-Host "RST Volume state UNKNOWN"
exit 3
}
else
{
#CRITICAL
Write-Host "RST Volume state CRITICAL"
exit 2
}

Use Powershell to run Psexec command

First post so please don't hurt me. I've searched around but can't seem to find a way to do what I want. I've made a script that copies a folder I have to numerous computers at \$computer\c$. In these folders is a batch file that runs an .exe. What I want to do is have Powershell pull from the same computers.txt that I used to copy the folder and then use psexec to run the batch file. I could do this all manually but scripting it seems to be a problem, here's what I thought would work but apparently not.
$computers = gc "C:\scripts\computers.txt"
foreach ($computer in $computers) {
if (test-Connection -Cn $computer -quiet) {
cd C:\pstools
psexec \\%computer cmd
C:\Folder\install.bat"
} else {
"$computer is not online"
}
}
Ok, let's take it from the top then.
$computers = gc "C:\scripts\computers.txt"
That loads the contents of the "computers.txt" file into the variable $computers. Simple enough, no issues there.
Next we have a ForEach loop. It splits up the contents of $computers and processes each line (presumably the name of a computer) as $computer against all the code within the curly braces.
foreach ($computer in $computers) {
That loop starts up with a standard If-Then statement. If (condition) then {do stuff}. In this case it is testing to see if the $computer is available on the network. If it is, then it attempts to run PSExec on it. If it isn't online it runs the Else clause, we'll get to that in a second.
if (test-Connection -Cn $computer -quiet) {
Then it changes directory. Kind of pointless, but ok, whatever. You could have just called it explicitly, such as C:\PSTools\PSExec.exe <arguments> and saved a line, but there's really no harm done.
cd C:\pstools
Then you are calling PSExec, though there's a little syntax error here. It should be $computer and not %computer. Also, it should just have the command you want to execute, not cmd and the command on a second line. You may have better results if you use the Call operator (&) to make powershell realize that it's trying to execute something and not run a cmdlet or function or what not.
& psexec \\$computer C:\Folder\install.bat
After that is the Else clause that says if the computer isn't online to write the string "$computer is not online" followed by closing braces for the Else clause and the ForEach loop.
} else {
"$computer is not online"
}
}
Edit: Ok, your finished script should look something like this (enclosed target in quotes in case there are spaces in the path):
$computers = gc "C:\scripts\computers.txt"
foreach ($computer in $computers) {
if (test-Connection -Cn $computer -quiet) {
& C:\pstools\psexec.exe \\$computer "C:\folder\install.bat"
} else {
"$computer is not online"
}
}
I realize this question is from 2014, and this answer will not directly address the question the user asked. But for people who come across this question these days, I want to throw out there that you don't need to use PSExec if you're using PowerShell*. Since you're already in PowerShell, just use Invoke-Command.
Syntax would be
Invoke-Command -ComputerName $Computer -ScriptBlock { C:\Folder\install.bat }
It's really that easy.
*Requires PowerShell remoting to be enabled on the target server. << Some people are using PSExec to enable PSRemoting by running winrm quickconfig... So it's still a valid question and the two things "PSExec" and "PSRemoting" are different.
Give this a try. You had a % where you wanted a $. Also the cmd.exe call is unnecessary.
$computers = gc "C:\scripts\computers.txt"
foreach ($computer in $computers) {
if (test-Connection -Cn $computer -quiet) {
cd C:\pstools
psexec \\$computer "C:\Folder\install.bat"
} else {
"$computer is not online"
}
}
use & (call) operator , &psexec \$computer "C:\Folder\install.bat"

Resources