Usage of hashtable in PowerShell to replace objects - powershell

Let's say I have the following scenario:
An IP address is linked to a particular string and I want to match an action.
Example:
IP address: 1.1.1.1
String: "Home"
IP address: 5.5.5.5
String: "Work"
if($IP -eq 1.1.1.1)
{
#Do something with "Home"
}
What would I be needing to use to have 'pretty' code instead of multiple if loops ?

The easiest thing to do here is to create a lookup Hashtable where IP's are the keys, and the corresponding strings are the values:
$lookupIP = #{
'1.1.1.1' = 'Home'
'5.5.5.5' = 'Work'
# etcetera
}
Now, if you have an ip in a variable, simply do
$ip = '1.1.1.1'
# Do something with the corresponding string
Write-Host "$ip will do something with $($lookupIP[$ip])"
If you like, you can add a test first to see if the $ip can be found in the lookup table:
if ($lookupIP.ContainsKey($ip)) {
Write-Host "$ip will do something with $($lookupIP[$ip])"
}
else {
Write-Warning "IP '$ip' was not found in the hashtable.."
}

Related

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 - only if statement executes despite input

I'm trying to start my Powershell portfolio with and easy script that calculates Network ID or BroadcastID depending on input from the user. That being said, I can only get my if statement to run. I am unsure what I am missing here. I have tried searching this as I know I cannot be the only one to have this issue, but I am unable to find it. Any education on my error would be appreciated as it seems like a basic flaw.
Thanks!
#prompt for IP and subnet mask
$ip = Read-Host -Prompt "Enter your IP address"
$mask = Read-Host - Prompt "Enter your subnet mask"
[String]$UserDecision = Read-Host -Prompt "Enter N if you would like to calculate your Network ID or B if you would like to calculate your Broadcast address."
$splitmask=$mask.split(".")
$wildcard="$(255 - $splitmask[0]).$(255 - $splitmask[1]).$(255 - $splitmask[2]).$(255 - $splitmask[3])"
# ip and mask variable to ip addresses
$ip = [ipaddress] $ip
$mask = [ipaddress] $mask
#determine networkID
function CalculateNetID {
$networkID = [ipaddress] ($ip.Address -band $mask.Address)
#print NetworkID to console
echo "The Network id is $($networkID.IPAddressToString)"
}
function CalculateBroadcastID {
$networkID = [ipaddress] ($ip.Address -band $mask.Address)
#convert wildcard to IP addresses
$wildcard= [ipaddress] $wildcard
$broadcast = [ipaddress] $($wildcard.Address -bor $NetworkID.Address)
#print broadcast to console
echo "The Broadcast id is $broadcast"
}
if ($UserDecision -eq "N" -or "n"){
CalculateNetID
}
elseif($UserDecision -eq "B" -or "b"){
CalculateBroadcastID
}
else{
echo "Please retry and enter the character associated with the ID you would like to calculate"
}
Here is your problem:
$false -or 'n' # => True
As you can see, this is what's happening in your first if statement, the correct syntax for your condition should be:
if($UserDecision -eq "N" -or $UserDecision -eq "n") {
Same thing applies for the elseif.
Note that, PowerShell comparison operators are not case-sensitive by default, so the -or conditions could be just removed:
if($UserDecision -eq "n") {
You might also want to consider using a switch statement instead of chained if, elseif, else:
switch($UserDecision) {
N { CalculateNetID }
B { CalculateBroadcastID }
Default {
"Please retry and enter the character associated with the ID you would like to calculate"
}
}

compare two string variables to determine if it is the same

I have $loopback_address is 192.168.1.1/24 and $source_address is 192.168.1.1. I wrote a PowerShell script to split the loopback address and compare it to the source address as below:
$Loopback_ip = ($loopback_address -split '/')
# so my $loopback_ip[0] is now equal to 192.168.1.1 which should be the
# same as the source_address.
if ($loopback_ip[0] -eq $source_address) {
Write-Host "same"
} else {
Write-Host "different"
}
The result should be "same" but it is "different".

Nested hashtable export in PowerShell?

I'm currently trying to create a easy to read document containing all devices on are network (3k+). Currently I have all my data within nested hashtables like so:
$devices = #{"hostname" = #{"Mac Address" = #{"IP Address" = "True or False"}}}
It stores the hostname of the device in $devices. Within the $hostname there is a hashtable containing all MAC addresses associated with that hostname. Within the MAC address there is a hashtable containing all IPs associated with that MAC address.
I've already created part of the script that creates the hashtable and stores the data. I have ran into a road block with exporting the data into a CSV that can be read in Excel with the format of.
Hostname, Mac Address, IP Address
server1, MM.MM.MM.SS.SS.SS , 1.1.1.1
1.1.1.2
MM.MM.MN.SS.SS.SA , 1.1.1.3
server2, MM.MM.MB.SS.SS.ST , 1.2.3.1
, 1.5.2.1
and so on.
Edit:
foreach ($hostname in $devices.Keys) {
echo $hostname
foreach ($Macs in $devices.$hostname.Keys) {
echo $Macs
foreach ($IPs in $devices.$hostname.$Macs.Keys) {
echo $IPs
}
}
}
Create custom objects in your innermost loop, collect the output in a variable, then export the data:
$csv = foreach ($hostname in $devices.Keys) {
foreach ($MAC in $devices.$hostname.Keys) {
foreach ($IP in $devices.$hostname.$Macs.Keys) {
[PSCustomObject]#{
'Hostname' = $hostname
'MAC Address' = $MAC
'IP Address' = $IP
}
}
}
}
$csv | Export-Csv 'C:\path\to\output.csv' -NoType
If you want output exactly like your example (which I wouldn't recommend) you need to keep track of the previous $hostname and $MAC and create blank object properties in case those match the respective current value.

[System.Net.Dns]::GetHostbyAddress COMPARE strings

I have a CSV file with hostnames and their IP addresses and I've to deploy something on them but, I can only use their IP addresses.
So I need to confirm if the IP address stills matching the hostname before start the deployment.
I wrote this script but is not doing what I expected...
Anyone can see where is the problem?
Thanks
$computerName = 'testName'
$computerIP = '192.168.32.148'
$var1 = [System.Net.Dns]::GetHostbyAddress("$computerIP").hostname
if ($var1 -like $computerName) {
"$computerName IS LIKE $var1"
}else{
"$computerName NOT LIKE $var1"
}
OUTPUT
testName NOT LIKE testName.mycompany.net
DESIRED OUTPUT
testName IS LIKE testName.mycompany.net
-like uses exact wildcard matching, and you're not using any wildcards in your -like operation!
Try this:
if ($var1 -like "$computerName*") {
"$computerName IS LIKE $var1"
}else{
"$computerName NOT LIKE $var1"
}
(Notice the * after the $computerName value)
For more information about wildcard matching, check out Get-Help about_Wildcards