Need a way to shuffle data around
-
Friday, January 18, 2013 8:03 PM
I have a script that queries HBA information on servers and outputs that data into a text file for each server. The powershell script launches psexec on the remote server that calls a batch file with the HBA query commands. The batch file redirects the output to a text file locally. The text file is then copied to a network share. There is one text file per server. This script works well. Here is the main script:
$SrvList = "C:\batch\dan\servers_main.lst" $server = Get-Content $SrvList $exe = "C:\batch\dan\bin\psexec.exe" $LogLoc = "\\<serverName>\logs\HBA Info\" $LogFile = $LogLoc + "Execution_Results.log" $DateAndSuch = Date # Make sure we can move forward if (!(Test-Path $LogLoc)) { New-Item $LogLoc -type directory } # Initialize and create log file Write-Output "$DateAndSuch -- Initializing HBA Gather script" >> $LogFile if (!(Test-Path $exe)) { Write-Output "$DateAndSuch -- psexec.exe not found!" >> $LogFile Write-Output "----END OF EXECUTION----" >> $LogFile exit } if (!(Test-Path $SrvList)) { Write-Output "$DateAndSuch -- server.lst not found!" >> $LogFile Write-Output "----END OF EXECUTION----" >> $LogFile exit } # Set up shell $Host.UI.RawUI.WindowTitle = HBA Gather Script" clear Write-Output "$DateAndSuch -- Initialization complete" >> $LogFile # Loop through server list and gather HBA data foreach ($i in $server) { # call date variable again, to get accurate timestamp for this iteration $DateAndSuch = Date Write-Output "Gathering HBA data from $i" Write-Output "$DateAndSuch -- HBA data from $i" >> $LogFile $params = '\\'+$i+' -u <userID> -p <password> -d cmd.exe /c "\\<batchServer>\C$\batch\dan\bin\hba.bat"' Write-Output $params $execResult = (Start-Process -FilePath $exe -ArgumentList $params -Wait -PassThru).ExitCode $execResult = [int]$execResult if ($execResult = '0') { Write-Host "Execution result " -NoNewline Write-Host "$execResult " -ForegroundColor Green -NoNewline Write-Host "on $i" } else { Write-Host "Execution result " -NoNewline Write-Host "$execResult " -ForegroundColor Red -NoNewline Write-Host "on $i" } Write-Output "$DateAndSuch -- Finished executing HBA data gathering on $i with this return code: $execResult" >> $LogFile } Write-Output "----END OF EXECUTION----" >> $LogFile # Emulate the pause command in old school batch Write-Output "Press any key to continue ..." $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Here is the batch file that runs locally on each server (kicked off by the above script):
@echo off set logFile="\\serverName\logs\HBA Info\hbaInfo_%computername%.txt" set errlogFile="\\serverName\logs\HBA Info\stdErr\sclistderr_%computername%.txt" set stdlogFile="\\serverName\logs\HBA Info\stdOut\sclistd_%computername%.txt"
IF EXIST "C:\Program Files (x86)\QLogic Corporation\SANsurferCLI" ( set scliExe="C:\Program Files (x86)\QLogic Corporation\SANsurferCLI\scli.exe" ) ELSE ( set scliExe="C:\Program Files\QLogic Corporation\SANsurferCLI\scli.exe" ) %scliExe% -i > out.txt 2>&1 %scliExe% -c >> out.txt 2>&1 IF %ERRORLEVEL% NEQ 0 GOTO errOut FIND "Host Name" < out.txt >> %logFile% FIND "WWPN" < out.txt >> %logFile% FIND "HBA Model" < out.txt >> %logFile% FIND "HBA Status" < out.txt >> %logFile% FIND "Connection Options" < out.txt >> %logFile% FIND "Actual Connection Mode" < out.txt >> %logFile% FIND "Data Rate :" < out.txt >> %logFile% FIND "Actual Data Rate" < out.txt >> %logFile% FIND "Execution Throttle" < out.txt >> %logFile% FIND "Port Down Retry Count" < out.txt >> %logFile% FIND "Link Down Timeout" < out.txt >> %logFile% GOTO end :errOut copy out.txt %errlogFile% del out.txt del QLInitLog.txt :end copy out.txt %stdlogFile% del out.txt del QLInitLog.txt
Example output of one of the text files:
--------------------------------------------------------------------
Host Name : <serverName>
Host Name : <serverName>
HBA Instance : 0
HBA Instance : 1
Port ID : <IDNum>
Port ID : <IDNum>
HBA Port : 1
HBA Port : 2
Port Name : <HBA WWN>
Port Name : <HBA WWN>
HBA Model : <model>
HBA Model : <model>
HBA Status : Online
HBA Status : Online
Connection Options : 1 - Point-to-Point Only
Connection Options : 1 - Point-to-Point Only
Actual Connection Mode : Point to Point
Actual Connection Mode : Point to Point
Data Rate : 4 Gbps
Data Rate : 4 Gbps
Actual Data Rate : 4 Gbps
Actual Data Rate : 4 Gbps
Execution Throttle : 65535
Execution Throttle : 65535
Port Down Retry Count : 45
Port Down Retry Count : 45
Link Down Timeout (seconds) : 45
Link Down Timeout (seconds) : 45--------------------------------------------------------------------
Now that I have hundreds of individual text files with the information that I need, I'd like a way to put them all in a .csv so I can sort them etc... Ideally, I'd like to have each Parameter name as a column heading (Server name, WWN, Model, Status etc...).
Does anyone have any input on a good method of accomplishing this?
- Edited by Dan Hyman Friday, January 18, 2013 8:05 PM
All Replies
-
Friday, January 18, 2013 9:43 PM
Parse each file into a single C SV line and add to a file.
This can be easily done with PowerShell using the load data from string CmdLet:
help ConvertFrom-StringData -full¯\_(ツ)_/¯
-
Friday, January 18, 2013 11:02 PM
cat stringdata.txt| out-string| %{$_ -replace ':','='}| ConvertFrom-StringData| %{new-object PsObject -Prop $_}¯\_(ツ)_/¯
-
Friday, January 18, 2013 11:46 PM
Hi jrv, from the example posted, the 'key' fields are not unique, so you're going to get...
ConvertFrom-StringData : Data item 'Host Name' in line 'Host Name = <serverName>' is already defined.
I propose this probably over-complicated method instead...
$testdata=Get-Content 'c:\temp\testdata.txt' $instancecount=(((Select-String -Inputobject $testdata -Pattern 'HBA Instance' -AllMatches).Matches).Count) -1 0..$instancecount | ForEach{New-Variable -Name "hash$($_)" -value @{} -force} $testdata | ForEach{ $tempname,$tempvalue=$_ -split '\s+:\s' For($i=0;$i -le $instancecount;$i++){ if(!(iex $"hash$($i).ContainsKey('$tempname')")){iex $"hash$($i).Add('$tempname','$tempvalue')";$i=$instancecount} } } $output=@() For($i=0;$i -le $instancecount;$i++){ iex $"output+=New-Object PSObject -Property $"hash$($i) } $output | ft 'Host Name','HBA Port','HBA Instance' -a Result: Host Name HBA Port HBA Instance --------- -------- ------------ <serverName> 1 0 <serverName> 2 1Let the agitating begin :-)
Inspired by Heineken.
- Marked As Answer by Dan Hyman Monday, January 21, 2013 3:32 PM
-
Saturday, January 19, 2013 12:16 AM
The file posted is in error. The utility does not produce duplicate lines. I suspect the OP combined two files and sorted them. This won't work. You have to load one file at a time. The string data converter was made just for this scenario.
¯\_(ツ)_/¯
-
Saturday, January 19, 2013 12:28 AMOh well, it was an interesting exercise in dealing with an unknown number of hash tables.
Inspired by Heineken.
-
Saturday, January 19, 2013 12:39 AM
Oh well, it was an interesting exercise in dealing with an unknown number of hash tables.
Inspired by Heineken.
Ha! I think Dan has gone home for the week. We will see on Monday.
Dortmunder Actien Brauerei/DAB (Lager)
¯\_(ツ)_/¯
-
Saturday, January 19, 2013 12:41 AM
His batch file does appear to be running the command twice into the same output file...
%scliExe% -i > out.txt 2>&1
%scliExe% -c >> out.txt 2>&1
Inspired by Heineken.
-
Saturday, January 19, 2013 12:44 AM
His batch file does appear to be running the command twice into the same output file...
%scliExe% -i > out.txt 2>&1
%scliExe% -c >> out.txt 2>&1
Inspired by Heineken.
Yup - then he sorted it thinking that might help.¯\_(ツ)_/¯
-
Saturday, January 19, 2013 12:50 AM
haha.. now we play the waiting game...
"Dortmunder Actien Brauerei/DAB (Lager)"
How does it taste? I can only see what the bottle looks like :-)
http://en.wikipedia.org/wiki/Dortmunder_Actien_Brauerei
Inspired by Heineken.
-
Saturday, January 19, 2013 12:53 AM
Dan - it would be much easier of you set the output option to output XML. This is structured data and can be loaded and converted very easily.
¯\_(ツ)_/¯
-
Saturday, January 19, 2013 12:55 AM
haha.. now we play the waiting game...
"Dortmunder Actien Brauerei/DAB (Lager)"
How does it taste? I can only see what the bottle looks like :-)
http://en.wikipedia.org/wiki/Dortmunder_Actien_Brauerei
Inspired by Heineken.
If you can get the Octoberfest special brew it is heaven.¯\_(ツ)_/¯
-
Monday, January 21, 2013 2:59 PMMost of the output files do have duplicate lines (such as server name, HBA model etc...) because almost all of my servers have more than one HBA. Most have two but some of my database servers have up to 8.
-
Monday, January 21, 2013 3:00 PMCorrect. I run scli with the '-i' switch and run it again with the '-c' switch. They produce different output; I'm extracting data from both and dumping it in the text file.
-
Monday, January 21, 2013 3:01 PM
I did play around with sorting data, combining all the text files (cp *.txt hbaInfo_all.txt) etc... to see if the text was easier to work with.
-
Monday, January 21, 2013 3:04 PM
Thank you guys for the input so far! This is great stuff. I love the idea of throwing the data into a hash table and then being able to work with the data from there. I'll play with some of the suggestions above and see how it works out. Please keep the suggestions coming; you guys are great!
Just an FYI; I'm relatively new to powershell and haven't done much with creating custom objects and working with hashtables. I'm open to suggestions on a better method for accomplishing this same goal.
Thanks again for the help on this!
-
Monday, January 21, 2013 5:31 PM
Correct. I run scli with the '-i' switch and run it again with the '-c' switch. They produce different output; I'm extracting data from both and dumping it in the text file.
You should select the switch that outputs XML. This can be eawsily converted without a lot of messing around.
Output as text will not be in pairs of lines but as one list for each HBA. These are easily separated into two objects.
¯\_(ツ)_/¯
-
Monday, January 21, 2013 6:46 PM
I use data that is returend from the -i switch and the -c switch in scli, here is the output from 'scli.exe -c -x':
<?xml version="1.0" encoding="ISO-8859-1" ?> - <QLogic> <AppName>SANsurfer FC/CNA HBA CLI</AppName> <AppVersion>1.7.3.37</AppVersion> - <HBA> <HBA Port="0" WWNN="00-00-00-00-00-00-00-00" WWPN="00-00-00-00-00-00-00-00" /> <Param ConnectionOption="1" DataRate="1" FrameSize="2048" HardLoopID="0" LoopResetDelay="5" EnableHostAdapterBIOS="1" EnableHardLoopId="0" FibreChannelTapeSupport="1" ExecutionThrottle="256" LoginRetryCount="8" PortDownRetryCount="45" EnableLipFulllogin="1" LinkDownTimeout="45" EnableTargetReset="1" LUNsPerTarget="256" /> </HBA> - <HBA> <HBA Port="1" WWNN="00-00-00-00-00-00-00-01" WWPN="00-00-00-00-00-00-00-01" /> <Param ConnectionOption="1" DataRate="1" FrameSize="2048" HardLoopID="0" LoopResetDelay="5" EnableHostAdapterBIOS="1" EnableHardLoopId="0" FibreChannelTapeSupport="1" ExecutionThrottle="256" LoginRetryCount="8" PortDownRetryCount="45" EnableLipFulllogin="1" LinkDownTimeout="45" EnableTargetReset="1" LUNsPerTarget="256" /> </HBA> <Status>0</Status> <Reboot>0</Reboot> </QLogic>
Here is the output from 'scli.exe -i -x':
<?xml version="1.0" encoding="ISO-8859-1" ?> - <QLogic> <AppName>SANsurfer FC/CNA HBA CLI</AppName> <AppVersion>1.7.3.37</AppVersion> - <HBA> <GeneralInfo Port="0" Model="XXX0000" WWNN="00-00-00-00-00-00-00-00" WWPN="00-00-00-00-00-00-00-00" PortID="00-00-00" SerialNumber="xxxxx00000" DriverVersion="9.1.7.16" BIOSVersion="1.24" FirmwareVersion="4.03.01" OptionROMBiosVersion="1.24" OptionROMFCodeVersion="1.25" OptionROMEFIVersion="1.08" OptionROMFirmwareVersion="4.00.24" TargetCount="3" PCIBus="8" PCIDevice="1" ActualConnectionMode="Point To Point" ActualDataRate="2 Gbps" PortType="NPort" Status="Online" /> </HBA> - <HBA> <GeneralInfo Port="1" Model="XXX0000" WWNN="00-00-00-00-00-00-00-01" WWPN="00-00-00-00-00-00-00-01" PortID="00-00-00" SerialNumber="xxxxx00000" DriverVersion="9.1.7.16" BIOSVersion="1.24" FirmwareVersion="4.03.01" OptionROMBiosVersion="1.24" OptionROMFCodeVersion="1.25" OptionROMEFIVersion="1.08" OptionROMFirmwareVersion="4.00.24" TargetCount="3" PCIBus="8" PCIDevice="33" ActualConnectionMode="Point To Point" ActualDataRate="2 Gbps" PortType="NPort" Status="Online" /> </HBA> <Status>0</Status> <Reboot>0</Reboot> </QLogic>
- Edited by Dan Hyman Monday, January 21, 2013 7:21 PM
-
Monday, January 21, 2013 7:17 PM
Here is what that really looks like as XML and not a screen scrape from IE.
<?xml version="1.0" encoding="ISO-8859-1" ?> <QLogic> <AppName>SANsurfer FC/CNA HBA CLI</AppName> <AppVersion>1.7.3.37</AppVersion> <HBA> <HBA Port="0" WWNN="00-00-00-00-00-00-00-00" WWPN="00-00-00-00-00-00-00-00" /> <Param ConnectionOption="1" DataRate="1" FrameSize="2048" HardLoopID="0" LoopResetDelay="5" EnableHostAdapterBIOS="1" EnableHardLoopId="0" FibreChannelTapeSupport="1" ExecutionThrottle="256" LoginRetryCount="8" PortDownRetryCount="45" EnableLipFulllogin="1" LinkDownTimeout="45" EnableTargetReset="1" LUNsPerTarget="256" /> </HBA> <HBA> <HBA Port="1" WWNN="00-00-00-00-00-00-00-01" WWPN="00-00-00-00-00-00-00-01" /> <Param ConnectionOption="1" DataRate="1" FrameSize="2048" HardLoopID="0" LoopResetDelay="5" EnableHostAdapterBIOS="1" EnableHardLoopId="0" FibreChannelTapeSupport="1" ExecutionThrottle="256" LoginRetryCount="8" PortDownRetryCount="45" EnableLipFulllogin="1" LinkDownTimeout="45" EnableTargetReset="1" LUNsPerTarget="256" /> </HBA> <Status>0</Status> <Reboot>0</Reboot> </QLogic>I am posting this so you can get an idea of how the XML works so you can see how to query it. Notice that there are two HBAs and they are in separate containers. To use these we want to turn them into PS objects.
¯\_(ツ)_/¯
-
Monday, January 21, 2013 7:28 PM
Example:
PS > $xml=[xml](cat c:\scripts\hbadat.xml) PS > $xml.Qlogic.HBA[0].Param|ft ConnectionOption DataRate FrameSize HardLoopID LoopResetDelay EnableHostAdapterBIOS EnableHardLoopId FibreChannelTape pport ---------------- -------- --------- ---------- -------------- --------------------- ---------------- ---------------- 1 1 2048 0 5 1 0 1Of course it wraps on the display but you can see it is an object. We can now export the records to a CSV filr using PowerShell or we can combine the XML into on composite object.
The data is hierarchical so unless it is denotmalized it cannot easily be put into a CSV file. I recommend moving it into a composite XML file and using POwerShell to create reports.
YOu should also be aware that the data needs to be tagged with the server name before it is combined.
¯\_(ツ)_/¯
- Edited by jrvMicrosoft Community Contributor Monday, January 21, 2013 7:29 PM
-
Monday, January 21, 2013 7:54 PM
Thank you again for the input. In case you are wondering, here is what I'm running with for now.
# Declare and populate vars $SrvList = "C:\batch\dan\servers_main.lst" $server = Get-Content $SrvList $exe = "C:\batch\dan\bin\psexec.exe" $LogLoc = "\\<serverName>\logs\HBA Info\" $LogFile = $LogLoc + "Execution_Results.log" $hbaFiles = $LogLoc + "hbaInfo_*" $hbaAll = $LogLoc + "all_hba_params.txt" $DateAndSuch = Date # Get credentials of user who's context will be used to execute psexec - the PromptForCredential method calls the Get-Credential cmdlet $creds = $host.ui.PromptForCredential("Account Authorization", "Please enter your username and password (i.e. domain\user).", "", "NetBiosUserName") # Make sure we can move forward if (!(Test-Path $LogLoc)) { New-Item $LogLoc -type directory } # Initialize and create log file Write-Output "$DateAndSuch -- Initializing SANSurver HBA Gather script" >> $LogFile if (!(Test-Path $exe)) { Write-Output "$DateAndSuch -- psexec.exe not found!" >> $LogFile Write-Output "----END OF EXECUTION----" >> $LogFile exit } if (!(Test-Path $SrvList)) { Write-Output "$DateAndSuch -- server.lst not found!" >> $LogFile Write-Output "----END OF EXECUTION----" >> $LogFile exit } # Set up shell $Host.UI.RawUI.WindowTitle = "SANSurfer Gather Script" clear Write-Output "$DateAndSuch -- Initialization complete" >> $LogFile # Loop through server list foreach ($i in $server) { # call date variable again, to get accurate timestamp for this iteration $DateAndSuch = Date Write-Output "Gathering HBA data from $i" Write-Output "$DateAndSuch -- HBA data from $i" >> $LogFile $params = '\\'+$i+' -u ' + $creds.Username + ' -p ' + $creds.GetNetworkCredential().Password + ' -d cmd.exe /c "\\<server>\C$\batch\dan\bin\scli.bat"' # Write-Output $params $execResult = (Start-Process -FilePath $exe -ArgumentList $params -Wait -PassThru).ExitCode $execResult = [int]$execResult if ($execResult = '0') { Write-Host "Execution result " -NoNewline Write-Host "$execResult " -ForegroundColor Green -NoNewline Write-Host "on $i" } else { Write-Host "Execution result " -NoNewline Write-Host "$execResult " -ForegroundColor Red -NoNewline Write-Host "on $i" } Write-Output "$DateAndSuch -- Finished executing HBA data gathering on $i with this return code: $execResult" >> $LogFile } Write-Output "----END OF EXECUTION----" >> $LogFile # Emulate the pause command in old school batch Write-Output "Press any key to continue ..." $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") # <-- this command produces an error in ISE, but works fine when invoked by powershell.exe # Combine HBA files [string]$outpath = $LogLoc + "all_hba_params.txt" Get-ChildItem -path $LogLoc -recurse |?{ ! $_.PSIsContainer } |?{($_.name).contains(".txt")} | %{ Out-File -filepath $outpath -inputobject (get-content $_.fullname) -Append} # Parse "all" file $HBAdata=Get-Content $hbaAll $instancecount=(((Select-String -Inputobject $HBAdata -Pattern 'HBA Instance' -AllMatches).Matches).Count) -1 0..$instancecount | ForEach{New-Variable -Name "hash$($_)" -value @{} -force} $HBAdata | ForEach{ $tempname,$tempvalue=$_ -split '\s+:\s' For($i=0;$i -le $instancecount;$i++){ if(!(iex $"hash$($i).ContainsKey('$tempname')")){iex $"hash$($i).Add('$tempname','$tempvalue')";$i=$instancecount} } } $output=@() For($i=0;$i -le $instancecount;$i++){ iex $"output+=New-Object PSObject -Property $"hash$($i) } # output to text $output | ft 'Host Name','HBA Port','HBA Instance', 'Port ID', 'HBA Port', 'Port Name', 'HBA Model', 'HBA Status', 'Connection Options', 'Actual Connection Mode', 'Data Rate', 'Actual Data Rate', 'Execution Throttle', 'Port Down Retry Count', 'Link Down Timeout (seconds)' -Wrap > "C:\batch\dan\HBA_All.txt" # output to grid $output | Out-GridView # output to csv $output | Export-Csv -path "C:\batch\dan\HBA_All.csv"
- Edited by Dan Hyman Monday, January 21, 2013 7:56 PM
-
Monday, January 21, 2013 7:59 PM
The XML data can also be directly opened or imported into Excel without using PowerShell. It is structured correctly for use in Excel.
¯\_(ツ)_/¯
-
Monday, January 21, 2013 9:04 PM
Thank you again for the input. In case you are wondering, here is what I'm running with for now.
# Declare and populate vars $SrvList = "C:\batch\dan\servers_main.lst" $server = Get-Content $SrvList $exe = "C:\batch\dan\bin\psexec.exe" $LogLoc = "\\<serverName>\logs\HBA Info\" $LogFile = $LogLoc + "Execution_Results.log" $hbaFiles = $LogLoc + "hbaInfo_*" $hbaAll = $LogLoc + "all_hba_params.txt" $DateAndSuch = Date # Get credentials of user who's context will be used to execute psexec - the PromptForCredential method calls the Get-Credential cmdlet $creds = $host.ui.PromptForCredential("Account Authorization", "Please enter your username and password (i.e. domain\user).", "", "NetBiosUserName") # Make sure we can move forward if (!(Test-Path $LogLoc)) { New-Item $LogLoc -type directory } # Initialize and create log file Write-Output "$DateAndSuch -- Initializing SANSurver HBA Gather script" >> $LogFile if (!(Test-Path $exe)) { Write-Output "$DateAndSuch -- psexec.exe not found!" >> $LogFile Write-Output "----END OF EXECUTION----" >> $LogFile exit } if (!(Test-Path $SrvList)) { Write-Output "$DateAndSuch -- server.lst not found!" >> $LogFile Write-Output "----END OF EXECUTION----" >> $LogFile exit } # Set up shell $Host.UI.RawUI.WindowTitle = "SANSurfer Gather Script" clear Write-Output "$DateAndSuch -- Initialization complete" >> $LogFile # Loop through server list foreach ($i in $server) { # call date variable again, to get accurate timestamp for this iteration $DateAndSuch = Date Write-Output "Gathering HBA data from $i" Write-Output "$DateAndSuch -- HBA data from $i" >> $LogFile $params = '\\'+$i+' -u ' + $creds.Username + ' -p ' + $creds.GetNetworkCredential().Password + ' -d cmd.exe /c "\\<server>\C$\batch\dan\bin\scli.bat"' # Write-Output $params $execResult = (Start-Process -FilePath $exe -ArgumentList $params -Wait -PassThru).ExitCode $execResult = [int]$execResult if ($execResult = '0') { Write-Host "Execution result " -NoNewline Write-Host "$execResult " -ForegroundColor Green -NoNewline Write-Host "on $i" } else { Write-Host "Execution result " -NoNewline Write-Host "$execResult " -ForegroundColor Red -NoNewline Write-Host "on $i" } Write-Output "$DateAndSuch -- Finished executing HBA data gathering on $i with this return code: $execResult" >> $LogFile } Write-Output "----END OF EXECUTION----" >> $LogFile # Emulate the pause command in old school batch Write-Output "Press any key to continue ..." $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") # <-- this command produces an error in ISE, but works fine when invoked by powershell.exe # Combine HBA files [string]$outpath = $LogLoc + "all_hba_params.txt" Get-ChildItem -path $LogLoc -recurse |?{ ! $_.PSIsContainer } |?{($_.name).contains(".txt")} | %{ Out-File -filepath $outpath -inputobject (get-content $_.fullname) -Append} # Parse "all" file $HBAdata=Get-Content $hbaAll $instancecount=(((Select-String -Inputobject $HBAdata -Pattern 'HBA Instance' -AllMatches).Matches).Count) -1 0..$instancecount | ForEach{New-Variable -Name "hash$($_)" -value @{} -force} $HBAdata | ForEach{ $tempname,$tempvalue=$_ -split '\s+:\s' For($i=0;$i -le $instancecount;$i++){ if(!(iex $"hash$($i).ContainsKey('$tempname')")){iex $"hash$($i).Add('$tempname','$tempvalue')";$i=$instancecount} } } $output=@() For($i=0;$i -le $instancecount;$i++){ iex $"output+=New-Object PSObject -Property $"hash$($i) } # output to text $output | ft 'Host Name','HBA Port','HBA Instance', 'Port ID', 'HBA Port', 'Port Name', 'HBA Model', 'HBA Status', 'Connection Options', 'Actual Connection Mode', 'Data Rate', 'Actual Data Rate', 'Execution Throttle', 'Port Down Retry Count', 'Link Down Timeout (seconds)' -Wrap > "C:\batch\dan\HBA_All.txt" # output to grid $output | Out-GridView # output to csv $output | Export-Csv -path "C:\batch\dan\HBA_All.csv"
If it does what you want then use it, It is about 10 times as many lines of code as would be necessary using XML. Next time always look at the XML solution early as much of the time it will reduce the problem size.¯\_(ツ)_/¯

