Running a For Loop through a Multiline Powershell Variable - powershell

I have section of a script where the user enters a list of server names which then checks to make sure there they exist in AD and then runs a command on each of the ones that do exist. This is what I have:
$machineNames = (read-host "Enter Server Name(s) (space separated)").Trim()
foreach ($machineName in (($machineNames).Split(' '))) {
Try {
Get-ADComputer $machineName | Out-Null
$veriMachineNames += "$machineName`n"
}
Catch {
Write-Host "*****Invalid Machine Name: $machineName" -Foreground Yellow
Write-Host "*****Skipping $machineName`n" -Foreground Yellow
}
}
foreach ($machine in $sepMachineNames) {
Write-Host "Server: $machine `n"
}
When I run this part of the script I get the following output (error intentionally included):
PS C:\> C:\script.ps1
Enter Machine Name(s) (space separated): server1 server2 server3
*****Invalid Machine Name: server3
*****Skipping server3
Server: server1
server2
As you can see it appears that the second foreach is seeing server1 and server2 as being on one line and not two lines. Is there a way to do this with just a variable? I'd rather not output the list to a file.

Instead of concatenating each name onto a big multi-line string manually, just output the individual names 1 by 1 and store them in a variable:
$veriMachines = foreach ($machineName in (($machineNames).Split(' '))) {
Try {
Get-ADComputer $machineName | Out-Null
# no piping to `|Out-Null`, this will "bubble up" to the variable
$machineName
}
Catch {
Write-Host "*****Invalid Machine Name: $machineName" -Foreground Yellow
Write-Host "*****Skipping $machineName`n" -Foreground Yellow
}
}
Now $veriMachines is an array of string (the machine names we just verified) that you can iterate over:
foreach($machine in $veriMachines){
Write-Host "Server: $machine"
}

Related

Powershell script to Stop and start windows Service using S.no

I have a listed my Windows Service Names in the Text file and I have added the code to display it by adding the S.no preceding to the Names,
Listofservices.txt contains
Print Spooler
Windows Update
Remote Desktop Services
Get-Content 'C:\Services\Listofservices.txt' | ForEach-Object { $i = 1 } { "$i.$_" ; $i++ }
Result
Print Spooler
Windows Update
Remote Desktop Services
now I would like to stop, start the services by entering only the S.no and I don't want to type the exact full name
$userinput = read-host -prompt "Enter the S.no to Stop/Start"
Stop-Service -Name "$userinput" -Force -Confirm
say for example if i enter the number 1 the Print Spooler service will be stopped
Here is one way you could do it following the code you already have, but as stated in comments, this is much simpler to do with Out-GridView -PassThru. Also do note, for these services, the PowerShell process will most likely require to be elevated.
$file = Get-Content path\to\file.txt
$file | ForEach-Object { $i = 1 } { "$i.$_" ; $i++ }
$userinput = Read-Host "Enter the S.no to Stop/Start"
try {
$choice = $file[-1 + $userinput]
if(-not $choice) {
throw 'Invalid selection..'
}
$service = Get-Service $choice
if('Running' -eq $service.Status) {
$service.Stop()
"$($service.Name) has been stopped.."
return # end the script here
}
$service.Start()
"$($service.Name) has been started.."
}
catch {
if($_.Exception.InnerException.InnerException.NativeErrorCode -eq 5) {
return "Process needs to be elevated."
}
"An error ocurred: $_"
}

Foreach loop in powershell with hasharray

I'm writing a powershell script to ping all the servers and check which are offline. but i have a bug. By name it works perfectly. But when i do test-connection with an IP it seems to work BUT i cant output the name of the IP in the hashlist. Could someone help me figure this out? Thanks!!
System.Collections.Hashtable.keys Is online/available, This is what it outputs. But i want it to say "Servername is online/available"
#Creating IP Array list
$ip_array = #{
Server = [ipaddress] "192.168.1.1"
sws = [ipaddress] "192.168.1.1"
}
Foreach ($ip in $ip_array)
{
if((Test-Connection -IPAddress $ip.values.ipaddresstostring -quiet -count 1 ) -eq $false)
{
write-output("$ip.keys Is offline/unavailable, please troubleshoot connection, script is terminating") | Red
}
else
{
$ping = $true
write-output("$ip.keys Is online/available") | Green
}
}
PowerShell's default pipeline semantics (any collection that can be enumerated and unraveled will be) makes dictionaries a pain to work with - piping them anywhere would result in a list of disjoint key-value-pairs, dictionary itself lost.
For this reason, PowerShell refuses to automatically enumerate dictionaries, and you must manually obtain an enumerator in order to loop over the entries in it:
foreach($entry in $ip_hash.GetEnumerator()){
# reference `$entry.Key` or `$entry.Name` for the key (eg. Server)
# reference `$entry.Value` for the value (eg. 192.168.1.1)
}
If you really intend to use a Hashtable for this, combining IP addresses with computernames, change to something like this:
# creating IP Hashtable
$ip_hash = #{
'192.168.1.1' = 'Server1'
'192.168.1.2' = 'Server2'
# etcetera
}
# loop through the hash, key-by-key
foreach ($ip in $ip_hash.Keys) {
$ping = Test-Connection -ComputerName $ip -Quiet -Count 1 -ErrorAction SilentlyContinue
if(!$ping) {
Write-Host "Server $($ip_hash[$ip]) is offline/unavailable, please troubleshoot connection, script is terminating" -ForegroundColor Red
}
else {
Write-Host "Server $($ip_hash[$ip]) is online/available" -ForegroundColor Green
}
}
Output would look like:
The Keys in the hash must all have unique values

Powershell, ping results in color

been working on a script/module in PowerShell for my work and can't seem to find where/what to input to make the ping results på green if it's a success and red if they timed out.
Param (
[Parameter(Position=0,Mandatory=$true)]
[String]$StoreID
)
$StoreNetworkArray = #(
("1017","xxx.x.x.x","x.x.x.x"),
)
$checkPing = $False
foreach ($currentStore in $StoreNetworkArray) {
if($currentStore[0] -eq $StoreID) {
$checkPing = $True # StoreID matches!
$WanIP = $currentStore[1]
$BreakoutIP = $currentStore[2]
} # end if
} # end foreach
if ($checkPing) {
# Store found, lets ping!
Write-Host "Checking status for store $StoreID using ping"
Write-Host "-----------------------------------------"
Write-Host "Pinging WAN IP: $WanIP"
ping $WanIP /n 10
Write-Host "-----------------------------------------"
Write-Host "Pinging Breakout IP: $BreakoutIP"
ping $BreakoutIP /n 10
Write-Host "-----------------------------------------"
}
} # End Function Check-StorePing```
ping returns an array of strings so you can check Foreach returned line:
ping $WanIP /n 10 | foreach {
if ($_ -like '*TTL=*'){
Write-Host $_ -ForegroundColor Green
}elseif($_ -like '*timed out*'){ # you might need to localize this part
Write-Host $_ -ForegroundColor Red
}else{ # remove the last else to get rid of the extra lines before and after the ping
Write-Host $_
}
}
You can even fit all of this in a single line but for now this has a better overview. You might need to localize the if. E.g. in a german environment Request timed out is Zeitberschreitung der Anforderung.

Script to search several servers for connected client IP addresses

I'm trying to make a Powershell script to search 5 servers for connected client's IP addresses. There are 5 servers and clients are connected via a user tunnel and an asset one. I'm trying to make a looping script that asks for the asset number and username then searches all 5 servers then reports back the tunnel IPs.
My Powershell skills are very rudimentary. I've managed to make a script that mostly works, the trouble I seem to be having is getting the script to report negative results properly. Here's where I am so far:
Clear-Host
$continue = $true
while ($continue){
Write-Host "Tunnel IP finder" -ForegroundColor White
$Asset = Read-Host "Enter asset number"
$AssetAddress = "$asset.corporate.domain.com"
$User = Read-Host "Enter Username"
$Username = "$User#domain.com"
$servers = "RRAS_01","RRAS_02","RRAS_03","RRAS_04","RRAS_05"
Write-Host ""
$data1 = Foreach ($Server1 in $Servers)
{
Get-RemoteAccessConnectionStatistics -computername $Server1 | Where {$_.UserName -eq $AssetAddress} | Select ClientIPAddress | findstr /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"
}
foreach($item1 in $data1){
if($item1.length -gt 1){
Write-Host "Asset tunnel IP is $item1"-ForegroundColor Green}
}
if($item1.length -LT 1){
Write-Host "Unable to locate asset on RRAS servers"-ForegroundColor yellow
}
$data2 = Foreach ($Server2 in $Servers)
{
Get-RemoteAccessConnectionStatistics -computername $Server2 | Where {$_.UserName -eq $Username} | Select ClientIPAddress | findstr /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"
}
foreach($item2 in $data2){
if($item2.length -gt 1){
Write-Host "User tunnel IP is $item2"-ForegroundColor Green}
}
if($item2.length -lt 1){
Write-Host "Unable to locate user on RRAS servers"-ForegroundColor yellow
}
Write-Host ""
}
When I search for an asset number and username of someone who is connected it is reporting the results back like this:
Tunnel IP finder
Enter asset number: N02312
Enter Username: SmithJ
Asset tunnel IP is 10.120.xxx.xxx
User tunnel IP is 10.120.xxx.xxx
AOVPN Tunnel IP finder
Enter asset number:
Which is what I was looking to achieve, it displays the IPs and loops to enter more if needed, however when I input details that is not currently connected I get:
Tunnel IP finder
Enter asset number:
Enter Username:
AOVPN Tunnel IP finder
Enter asset number:
It's not reporting the negative results. When I take the scripting off and just have it dump what it thinks $item1/2 is supposed to be it prints nothing, so as far as I can tell $item1/2.length -LT 1 should be doing it.
I've tried experimenting with Else and Elseif, but I can't seem to make those work. There are probably better ways of doing this, but my Powershell is still very basic.
Any help would be greatly appreciated.
Thanks in advance.
It seems if you loop through a collection that has $null value the $item.length will be equal to 1, not to 0 and its value will not be equal to $null. Maybe that´s what happening to you.
PS C:\Windows\System32\WindowsPowerShell\v1.0> $x = $null
PS C:\Windows\System32\WindowsPowerShell\v1.0> $x.length
0
PS C:\Windows\System32\WindowsPowerShell\v1.0> $arr = {$null}
PS C:\Windows\System32\WindowsPowerShell\v1.0> $arr.length
1
PS C:\Windows\System32\WindowsPowerShell\v1.0> $arr | % {$_.length}
1
PS C:\Windows\System32\WindowsPowerShell\v1.0> $arr | % {$_ -eq $null}
False
In your code you only check for the length to be either less or greater than 1 so in the case of the length being equal to 1 it would not print anything. Since the $null check doesnt work I think the best option would be to change the second comparison operator to less or equal instead of less than:
if($item1.length -LE 1){
Write-Host "Unable to locate asset on RRAS servers"-ForegroundColor yellow
}

How do I add a string to a variable called from a CSV file before it is called in a function?

I am trying to ping a list of IPs, but I need to test variations of them for RACs and KVMs. I want to take the IP address (in the $ColumnHeader variable) and append "rac" to it before pinging it. I also will need to ping "arac", "raca", "kv", "akv", "kva", and "kvm", but I was just going to substitute those manually into the script after running it each time.
Param(
[Parameter(Mandatory=$true, position=0)][string]$csvfile
)
$ColumnHeader = "Name"
#$string = "rac"
#$subServer = "$($ColumnHeader)$($string)"
Write-Host "Reading file" $csvfile
$ipaddresses = Import-Csv $csvfile | Select-Object $ColumnHeader
Write-Host "Started Pinging.."
foreach ($ip in $ipaddresses) {
if (Test-Connection $ip.($ColumnHeader) -Count 1 -Quiet) {
Write-Host $ip.("Name") "Ping succeeded." -Foreground Green
} else {
Write-Host $ip.("Name") "Ping failed." -Foreground Red
}
}
Write-Host "Pinging Completed."
I've tried creating new variables $string and $subServer and using those in place of $ColumnHeader on line 14, but I get a "Cannot validate argument on parameter 'ComputerName'." error.
EDIT: I changed Line 7 from $subServer = $ColumnHeader + $string to $subServer = "$($ColumnHeader)$($string)", and I can successfully call $subServer on Line 14 in place of $ColumnHeader, but when I uncomment $string on Line 6, I get the aforementioned 'ComputerName' error again.