Appending data from one variable onto another in powershell - powershell

I've got two variables that have two separate list with exactly the same amount of lines:
$server = $agentserver.name
$type = $agentserver.agentservertype
Example data output
$server $type
server1 windows
server2 ndmp
I want to append the data from $type onto $server with a ","
so the output would look like this:
server1,windows
server2,ndmp
I have been trying to use foreach loops and increment one onto the other but I can't get it to work properly this is my code I am using:
$agentserver = foreach($i in $server){foreach($j in $type){$i + ($j++)}}
How can I get this to append properly in powershell?

so $agentserver is an object with the columns name and agentservertype - you can do the following:
$commaList = foreach($as in $agentserver) {
$as.name,$as.agentservertype -join ','
}

Related

Enumerate through array fails

I'm enumerating through all of the datastores in our VMware environment to get names and used space.
When I run the foreach loop, it's both enumerating through the array, and not enumerating through the array.
Here's my script:
$list = #()
$row = '' | select Name, UsedSpace
$datastores = Get-Datastore
foreach ($store in $datastores) {
$row.name = $store.name;
$row.usedspace = [math]::Round(($store.extensiondata.summary.capacity - $store.extensiondata.summary.freespace)/1gb)
Write-Host $row; #To Verify that each row is different, and that enumeration is working#
$list += $row;
}
Console Output:
#{name=datastore1; usedspace=929}
#{name=datastore2; usedspace=300}
#{name=datastore3; usedspace=400}
$list variable output:
Name Usedspace
Datastore3 400
Datastore3 400
Datastore3 400
So it's enumerating through. getting all the correct data. but for some reason the line $list += $row is waiting until the last object in the array, grabs only that data, but knows that there's 3 objects in the array, and populates each index with that objects data.
The only thing I've done to troubleshoot is bounced my PowerShell console.
The reason for this is that $row is a single object. You created it once, and then you keep changing the values of its properties. When you add it to the array, you're adding a reference to it, not a copy. So the values seen will always be those that were most recently set.
Recreate your $row on every iteration of the loop.
Alternatively you could create a PSCustomObject
$list = foreach ($store in Get-Datastore) {
[PSCustomObject]#{
Name = $store.name
UsedSpace = [math]::Round(($store.extensiondata.summary.capacity -
$store.extensiondata.summary.freespace)/1gb)
}
}
$list
As mentioned in the comments, with:
$row = '' | select Name, UsedSpace; $row.GetType()
you implicitly also create an (empty) PSCustomObject,
but as this needs to be created in every iteration of the foreach and then (inefficiently) appended to $list by rebuilding the array - directly building the PSCustomObject is IMO more clear / straight forward.

Powershell trim text using a special character

I have a list of hostnames which have the domain and subdomian in the FQDN. I need to get only the parent (root) domain name from it.
I have tried with substring but have not succeeded.
abc.xyz.me.com
def.me.com
ghi.sub.new.com
jkl.sup.old.com
these are some examples and from the list and I would like to get the root domains (me,new,old).
The simple way would be to use split and get the index of -2
$FQDN = ('abc.xyz.me.com', 'def.me.com', 'ghi.sub.new.com', 'jkl.sup.old.com')
ForEach ($Domain in $FQDN)
{
write-host ($Domain.split(".")[-2])
}
You probably want to do more than just write to host, but that should give you the idea.
Split the string, reverse the array and then pull the second member
$list = #(
"abc.xyz.me.com",
"def.me.com",
"ghi.sub.new.com",
"jkl.sup.old.com"
)
$List | ForEach-Object {
[Array]::Reverse(($Arr = $_.Split(".")))
$TLD, $SLD, $Null = $Arr
$TLD # You're top level domain
$SLD # The second level domain
# The rest of the values after those two get sent to null land
}
Here's a solution that gets a unique list of the full parent domains into a variable named $ParentDomains:
$Domains = 'abc.xyz.me.com', 'def.me.com', 'ghi.sub.new.com', 'jkl.sup.old.com'
$ParentDomains = $Domains | ForEach-Object {
$Domain = $_.Split('.')
$Domain[-2]+'.'+$Domain[-1]
} | Get-Unique
$ParentDomains
Explanation:
Iterates through the list of domains via ForEach-Object. Each domain in the loop is represented by $_.
Splits the string on the '.' character
Uses the index indicator [] to get the second to last [-2] and last [-1] items in each array and outputs them as a new string separated by a '.'.
Pipes the result to Get-Unique to remove duplicates.

String matching in PowerShell

I am new to scripting, and I would like to ask you help in the following:
This script should be scheduled task, which is working with Veritas NetBackup, and it creates a backup register in CSV format.
I am generating two source files (.csv comma delimited):
One file contains: JobID, FinishDate, Policy, etc...
The second file contains: JobID, TapeID
It is possible that in the second file there are multiple same JobIDs with different TapeID-s.
I would like to reach that, the script for each line in source file 1 should check all of the source file 2 and if there is a JobID match, if yes, it should have the following output:
JobID,FinishDate,Policy,etc...,TapeID,TapeID....
I have tried it with the following logic, but sometimes I have no TapeID, or I have two same TapeID-s:
Contents of sourcefile 1 is in $BackupStatus
Contents of sourcefile 2 is in $TapesUsed
$FinalReport =
foreach ($FinalPart1 in $BackupStatus) {
write-output $FinalPart1
$MediaID =
foreach ($line in $TapesUsed){
write-output $line.split(",")[1] | where-object{$line.split(",")[0] -like $FinalPart1.split(",")[0]}
}
write-output $MediaID
}
If the CSV files are not huge, it is easier to use Import-Csv instead of splitting the files by hand:
$BackupStatus = Import-Csv "Sourcefile1.csv"
$TapesUsed = Import-Csv "Sourcefile2.csv"
This will generate a list of objects for each file. You can then compare these lists quite easily:
Foreach ($Entry in $BackupStatus) {
$Match = $TapesUsed | Where {$_.JobID -eq $Entry.JobID}
if ($Match) {
$Output = New-Object -TypeName PSCustomObject -Property #{"JobID" = $Entry.JobID ; [...] ; "TapeID" = $Match.TapeID # replace [...] with the properties you want to use
Export-Csv -InputObject $Output -Path <OUTPUTFILE.CSV> -Append -NoTypeInformation }
}
This is a relatively verbose variant, but I prefer it like this.
I am checking for each entry in the first file whether there is a matching entry in the second. If there is one I combine the required fields from the entry of the first list with the ones from the entry in the second list into one object that I can then export very comfortably using Export-Csv.

Powershell to read some strings from each line

I have a requirement like:
Have a text file containing the following in the following pattern
172.26.xxy.zxy:Administrator:Password
172.26.xxy.yyx:Administrator:Password
172.26.xxy.yyy:Administrator:Password
172.26.xxy.yxy:Administrator:Password
I need my powershell script to read each word and use that word whereever required. For example,
foreach(something)
{
I want the IP's(172.26.---.---) to read and store the value as a variable.
I want to store the two words after **:** in seperate variables.
}
How can this be done? I know to read an entire file or get some specific string. But I need the same to be done on each line.Any help would be really appreciated.
Something like this? You can just split on the : and then store your variables based on the index
$contents = Get-Content C:\your\file.txt
foreach($line in $contents) {
$s = $line -split ':'
$ip = $s[0]
$user = $s[1]
$pass = $s[2]
write-host $ip $user $pass
}
minor edit: "t" missing in content.
You can write a regular expression to replace to remove the parts you do not need
$ip_address= '172.26.xxy.zxy:Administrator:Password' -replace '^(.+):(.+):(.+)$','$1'
$user= '172.26.xxy.zxy:Administrator:Password' -replace '^(.+):(.+):(.+)$','$2'
$pwd= '172.26.xxy.zxy:Administrator:Password' -replace '^(.+):(.+):(.+)$','$3'
I think the more generic and pure Powershell way would be something like this:
Select-String "(.*):(.*):(.*)" c:\file.txt |
Select #{Name="IP"; Expression = {$_.Matches.Groups[1]}},
#{Name="User"; Expression = {$_.Matches.Groups[2]}},
#{Name="Password"; Expression = {$_.Matches.Groups[3]}}
The Output would be then an array of objects each having three properties IP, User and Password. So you can now use them for your purposes, or just add more commands at the end of the pipe.

Powershell array of arrays loop process

I need help with loop processing an array of arrays. I have finally figured out how to do it, and I am doing it as such...
$serverList = $1Servers,$2Servers,$3Servers,$4Servers,$5Servers
$serverList | % {
% {
Write-Host $_
}
}
I can't get it to process correctly. What I'd like to do is create a CSV from each array, and title the lists accordingly. So 1Servers.csv, 2Servers.csv, etc... The thing I can not figure out is how to get the original array name into the filename. Is there a variable that holds the list object name that can be accessed within the loop? Do I need to just do a separate single loop for each list?
You can try :
$1Servers = "Mach1","Mach2"
$2Servers = "Mach3","Mach4"
$serverList = $1Servers,$2Servers
$serverList | % {$i=0}{$i+=1;$_ | % {New-Object -Property #{"Name"=$_} -TypeName PsCustomObject} |Export-Csv "c:\temp\$($i)Servers.csv" -NoTypeInformation }
I take each list, and create new objects that I export in a CSV file. The way I create the file name is not so nice, I don't take the var name I just recreate it, so if your list is not sorted it will not work.
It would perhaps be more efficient if you store your servers in a hash table :
$1Servers = #{Name="1Servers"; Computers="Mach1","Mach2"}
$2Servers = #{Name="2Servers"; Computers="Mach3","Mach4"}
$serverList = $1Servers,$2Servers
$serverList | % {$name=$_.name;$_.computers | % {New-Object -Property #{"Name"=$_} -TypeName PsCustomObject} |Export-Csv "c:\temp\$($name).csv" -NoTypeInformation }
Much like JPBlanc's answer, I kinda have to kludge the filename... (FWIW, I can't see how you can get that out of the array itself).
I did this example w/ foreach instead of foreach-object (%). Since you have actual variable names you can address w/ foreach, it seems a little cleaner, if nothing else, and hopefully a little easier to read/maintain:
$1Servers = "apple.contoso.com","orange.contoso.com"
$2Servers = "peach.contoso.com","cherry.contoso.com"
$serverList = $1Servers,$2Servers
$counter = 1
foreach ( $list in $serverList ) {
$fileName = "{0}Servers.csv" -f $counter++
"FileName: $fileName"
foreach ( $server in $list ) {
"-- ServerName: $server"
}
}
I was able to resolve this issue myself. Because I wasn't able to get the object name through, I just changed the nature of the object. So now my server lists consist of two columns, one of which is the name of the list itself.
So...
$1Servers = += [pscustomobject] #{
Servername = $entry.Servername
Domain = $entry.Domain
}
Then...
$serverList = $usaServers,$devsubServers,$wtencServers,$wtenclvServers,$pcidevServers
Then I am able to use that second column to name the lists within my foreach loop.