Compare-object output in variable - powershell
I'm building a script that will compare the last octed of in-use IPv4 addreses, with all the available octeds (2 till 254).
I am already this far that I do get a result by comparing array's, but my end-result is also an array, and I cannot seem to get only the number.
My script:
$guestIP = #("192.168.31.200","192.168.31.31","192.168.31.90","192.168.31.25","192.168.31.100")
$AllLastOcted = $("2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71","72","73","74","75","76","77","78","79","80","81","82","83","84","85","86","87","88","89","90","91","92","93","94","95","96","97","98","99","100","101","102","103","104","105","106","107","108","109","110","111","112","113","114","115","116","117","118","119","120","121","122","123","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","144","145","146","147","148","149","150","151","152","153","154","155","156","157","158","159","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","177","178","179","180","181","182","183","184","185","186","187","188","189","190","191","192","193","194","195","196","197","198","199","200","201","202","203","204","205","206","207","208","209","210","211","212","213","214","215","216","217","218","219","220","221","222","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254")
$guestIP = $guestIP | sort -Property {$_-replace '[\d]'},{$_-replace '[a-zA-Z\p{P}]'-as [int]}
$AllLastOcted = $AllLastOcted | sort -Property {$_-replace '[\d]'},{$_-replace '[a-zA-Z\p{P}]'-as [int]}
$guestIP = $guestIP -replace('192.168.31.','')
Compare-Object -ReferenceObject ($AllLastOcted ) -DifferenceObject ($guestIP) | select -Property InputObject -First 1 | set-Variable AvailableOcted -PassThru
$AvailableOcted
My goal is, is that I have as result the first-available octed that I can use.
like:
write-host "IP that can be used is 192.168.31.$AvailableOcted"
PS > IP that can used is 192.168.31.2
You can simplify this a lot.
Instead of defining all numbers from 2 to 254 you can use the range operator to create the array. You also don't need the [int] casts. Instead of using the Compare-Object cmdlet to filter the octeds, you can use the Where-Object cmdlet:
$guestIP = #("192.168.31.200","192.168.31.31","192.168.31.90","192.168.31.25","192.168.31.100")
$AllLastOcted = 2 .. 254
$usedOcted = $guestIP -replace '.*\.'
$nextAvailableOcted = $AllLastOcted | Where { $_ -NotIn $usedOcted } | select -first 1
write-host "IP that can be used is 192.168.31.$nextAvailableOcted"
Output:
IP that can be used is 192.168.31.2
Well, as simple as:
$AvailableOcted.InputObject
would return only the value.
So it would look like this:
write-host ("IP that can be used is 192.168.31." + $AvailableOcted.InputObject)
Related
Select all unique third octet in a list of IP addresses with PowerShell
I have a list of IP addresses. They all start with 10.10. I want all the unique values of the third octet. This way I can count how many of that unique value there are. 10.10.26.251 10.10.27.221 10.10.26.55 10.10.31.12 10.10.12.31 10.10.31.11 10.10.27.15 10.10.26.5 When I am done I want to know that I have 3 .26 network devices, 2 27, and so on so forth. Other than breaking down the octet with a split and looping through each one, I can't think of any single liners. Any suggestions?
here's a small variant. [grin] i already had this before noticing the other answers - and it is a tad different. what it does ... creates a collection of IPv4 address objects to work with groups them by a calculated property [the 3rd octet] creates a [PSCustomObject] for each resulting group sends it to the $Octet3_Report variable shows it on screen output to a CSV file would be easy at that point. here's the code ... $IP_List = #( [ipaddress]'10.10.26.251' [ipaddress]'10.10.27.221' [ipaddress]'10.10.26.55' [ipaddress]'10.10.31.12' [ipaddress]'10.10.12.31' [ipaddress]'10.10.31.11' [ipaddress]'10.10.27.15' [ipaddress]'10.10.26.5' ) $Octet3_Report = $IP_List | Group-Object -Property {$_.ToString().Split('.')[2]} | ForEach-Object { [PSCustomObject]#{ Octet_3 = $_.Name Count = $_.Count } } $Octet3_Report on screen output ... Octet_3 Count ------- ----- 26 3 27 2 31 2 12 1
It's like me to figure it out after the fact. The Return contains the dns records. The IP address are stored inside recorddata. I pull the end of the IP address off. Then loop through grabbing only the range and count with a foreach loop to make it cleaner. $DNSRecordCounts = #() $Ranges = ($Return | where-object {$_.recorddata -like "10.10.*"}).recorddata -replace "\.\d{1,3}$" | select -Unique foreach ($range in $Ranges) { $DNSRecordCounts += [pscustomobject][ordered]#{ IPRange = $range Count = ($Return | Where-Object {$_.recorddata -like "$($range).*"}).Count } }
Based on your question and what I can infer from your own answer, if you are looking for something a little more like "idiomatic" PowerShell you want the following: $Return ` | Select-Object -ExpandProperty recorddata ` | ForEach-Object { $_ -match "\d+\.\d+\.(?<octet>\d+)\.\d+" | Out-Null $Matches.octet } ` | Group-Object ` | ForEach-Object { [PSCustomObject]#{ Octet = $_.Name Count = $_.Count } }
How do I join two lines in PowerShell
I'm trying to get Information about our VMs in Hyper-V via PowerShell. This is what I got so far: $Path = 'c:/VM.csv' "Name,CPUs,Dynamischer Arbeitsspeicher,RAM Maximum (in MB),RAM Minimum (in MB), Size" > $Path $line1 = Get-VM | %{($_.Name, $_.ProcessorCount, $_.DynamicMemoryEnabled, ($_.MemoryMaximum/1MB), ($_.MemoryMinimum/1MB)) -join ","} $line2 = Get-VM –VMName * | Select-Object VMId | Get-VHD | %{$_.FileSize/1GB -join ","} $out = $line1+","+ $line2 Write-Output $out | Out-File $Path -Append Import-Csv -Path $Path | Out-GridView The Problem is that the second object ($line2) should be in the same column as $line1. As you can see, currently the information about the size of the VMs ($line2) is written in rows under the output of $line1. Also the order is wrong. Any idea what is wrong with my code? Thanks in advance.
I think you messed it up a little, Export-CSV will do the job without the need to manually define the csv structure. Anyway, regarding your code I think you can improve it a little, (I don't have hyper-v to test this, but I think it should work) What I've done is create a results array to hold the final data, then using foreach loop i'm iterating the Get-VM Results and creating a row for each VM, at the end of each iteration I'm adding the row to the final results array, so: $Results = #() foreach ($VM in (Get-VM)) { $Row = "" | Select Name,CPUs,'Dynamischer Arbeitsspeicher','RAM Maximum (inMB)','RAM Minimum (in MB)',Size $Row.Name = $VM.Name $Row.CPUs = $VM.ProcessorCount $Row.'Dynamischer Arbeitsspeicher' = $VM.DynamicMemoryEnabled $Row.'RAM Maximum (inMB)' = $VM.MemoryMaximum/1MB $Row.'RAM Minimum (in MB)' = $VM.MemoryMinimum/1MB $Total=0; ($VM.VMId | Get-VHD | %{$Total += ($_.FileSize/1GB)}) $Row.Size = [math]::Round($Total) $Results += $Row } $Results | Export-Csv c:\vm.csv -NoTypeInformation
This is definitely not the proper way to build an object list, instead you should do something like this: Get-VM | Select Name, #{Name = "CPUs"; Expression = {$_.ProcessorCount}, #{Name = "Dynamischer Arbeitsspeicher"; Expression = {$_.DynamicMemoryEnabled}, #{Name = "RAM Maximum (in MB)"; Expression = {$_.MemoryMaximum/1MB}, #{Name = "RAM Minimum (in MB)"; Expression = {$_.MemoryMinimum/1MB}, #{Name = "Size"; Expression = {$_.VMId | Get-VHD | %{$_.FileSize/1GB -join ","}} | Export-Csv c:\vm.csv -NoTypeInformation
Parsing multiple valus in multiple variables
I am trying to find a way to execute a command in powershell and put each line of the result in a different variable to use them later in my script. For example if i execute the below command: C:\> Get-VMHost -Name hq-esxi-prod-01a.nsx.gss | Get-VM | select Name I will get the below: Name ---- HQ-LinServ-01a HQ-Win2012-01a HQ-Web-02a I want to have a script that will add each line in a different variable in a script (excluding the first which is name). how can i do that. Thank you for your help.
You can use Set-Variable in a loop to put each value in a separate variable: $i = 0 ... | Get-Vm | Select-Objet -Expand Name | ForEach-Object { Set-Variable -Name "vm$i" -Value $_ $i++ } However, that usually isn't good advice. It's more common to put all names in one (array) variable: $vmList = ...| Get-Vm | Select-Object -Expand Name so you can access individual names via $vmList[<index>], or (if you need access by some kind of name) in a hashtable: $i = 0 $vmList = #{} ... | Get-Vm | Select-Objet -Expand Name | ForEach-Object { $vmList["vm$i"] = $_ $i++ } Best practice would depend on the particular scenario you need this for, though.
Thank you for your reply, I have tried you answer but it seems that i am using PowerCLI for VMware it does not include Select-Object -Expand (not sure i had an exception), However your answer have mad me reach to a suitable answer for this. I have used the below and it worked fine using foreach and adding the values in an array and then reading them as below: $p1vmname = Get-VMHost -Name hq-esxi-prod-01a.nsx.gss | Get-VM | select Name $p1vmlist = #() foreach ($p1line in $p1vmname) { $p1vmlist += $p1line } $p1 = 0 do { $x = $p1+1 Write-Host -BackgroundColor:Black -ForegroundColor:Yellow "vm number $x is "$p1vmlist[$p1]"." $p1++ } until ($p1 -eq $p1vmc) } However when using this the names was not totally correct as they had some additional characters as below: vm number 1 is #{Name=HQ-Web-01a} vm number 2 is #{Name=HQ-LinServ-01a} vm number 3 is #{Name=HQ-Win2012-01a} so i used split and trim to get rid of these as below and worked fine. $p1vmname = Get-VMHost -Name hq-esxi-prod-01a.nsx.gss | Get-VM | select Name $p1vmlist = #() foreach ($p1line in $p1vmname) { $p1vmlist += $p1line } $p1 = 0 do { $x = $p1+1 $p1vmlist[$p1] = ($p1vmlist[$p1]) -split("=") | Select-Object -Last 1 $p1vmlist[$p1] = $p1vmlist[$p1].trimend("}") Write-Host -BackgroundColor:Black -ForegroundColor:Yellow "vm number $x is "$p1vmlist[$p1]"." $p1++ } until ($p1 -eq $p1vmc) } Output: vm number 1 is HQ-Web-01a . vm number 2 is HQ-LinServ-01a . vm number 3 is HQ-Win2012-01a . Thank you so much for your answer that helped me a lot. I am really enjoying scripting now.
Sort by ascending number order
$var_1text = $var_2text = $var_17text = $null Get-Variable -Name var_* I get the following output : 1-17-2 var_1text var_17text var_2text But I want the following output : 1-2-17 var_1text var_2text var_17text
Use the Sort-Object cmdlet: Get-Variable -Name var_* |Sort-Object { ($_.Name -replace "[^\d]","") -as [int] }
Along the same lines Get-Variable -Name var_* | Select-Object *,#{L="NameIndex";E={[void]($_.Name -match '\d+');[int]$Matches[0]}} | Sort-Object NameIndex You can create a calculated property that only contains the number portion. Cast it to [int] and sort on that property. This would be especially useful if you need to refer to this more than once in the code as supposed to recalling the regex.
PowerShell - filtering for unique values
I have an input CSV file with a column containing information similar to the sample below: 805265 995874 805674 984654 332574 339852 I'd like to extract unique values into a array based on the leading two characters, so using the above sample my result would be: 80, 99, 98, 33 How might I achieve this using PowerShell?
Use Select-Object and parameter -unique: $values = '805265', '995874', '805674', '984654', '332574', '339852' $values | Foreach-Object { $_.Substring(0,2) } | Select-Object -unique If conversion to int is needed, then just cast it to [int]: $ints = $values | Foreach-Object { [int]$_.Substring(0,2) } | Select-Object -unique
I'd use the Group-Object cmdlet (alias group) for this: Import-Csv foo.csv | group {$_.ColumnName.Substring(0, 2)} Count Name Group ----- ---- ----- 2 80 {805265, 805674} 1 99 {995874} 1 98 {984654} 2 33 {332574, 339852}
You might use a hash table: $values = #(805265, 995874, 805674, 984654, 332574, 339852) $ht = #{} $values | foreach {$ht[$_ -replace '^(..).+','$1']++} $ht.keys 99 98 33 80
You could make a new array with items containing the first two characters and then use Select-Object to give you the unique items like this: $newArray = #() $csv = Import-Csv -Path C:\your.csv $csv | % { $newArray += $_.YourColumn.Substring(0, 2) } $newArray | Select-Object -Unique
Just another option instead of using Select-Object -unique would be to use the Get-Unique cmdlet (or its alias gu; see the detailed description here) as demonstrated below: $values = #(805265, 995874, 805674, 984654, 332574, 339852) $values | % { $_.ToString().Substring(0,2) } | Get-Unique # Or the same using the alias $values | % { $_.ToString().Substring(0,2) } | gu