Asked by:
Windows Powershell : Sort the hashtable

Question
-
I have a parameter that provides the output like this. When I try to sort for the Name property, it doesn't. I have tried the following code, but nothing works.
$writeParams | Sort-Object -Descending $writeParams | Sort-Object -Property Name -Descending $writeParams | Sort-Object -Property LastReboot -Descending
Name Value
Domain Phoneix-01
LastReboot 4/4/2020 2:03:03 AM
TaskTrigger {Tuesday, --, 02:00:00}
FileName C:\ServerPatchReport.html
KB KB4540723
InstalledOn 3/14/2020 2:44:12 AM
OSType Windows Server 2016
Domain Phoneix-02
LastReboot 4/6/2020 2:04:06 AM
TaskTrigger {Monday...
FileName C:\ServerPatchReport.html
KB KB4540688
InstalledOn 3/30/2020 2:19:56 AM
OSType Windows Server 2008 R2Monday, April 6, 2020 7:40 AM
All replies
-
You cannot sort a collection of hashes.
\_(ツ)_/
Monday, April 6, 2020 8:56 AM -
You cannot sort a collection of hashes.
\_(ツ)_/
Thanks. I am trying to feed this data into HTML. and then i am trying to sort. I can get the information in the HTML but the sorting the HTML also doesn't work.
I am really clueless as to how to make this work.
Monday, April 6, 2020 9:29 AM -
Sorry but you can only sort objects. You are trying to sort hash tables. Also hashes cannot be correctly converted to HTML.
Without knowing more about your code there is no way to answer your issue.
\_(ツ)_/
Monday, April 6, 2020 10:16 AM -
$computername = $env:computername $USERNAME = $env:username $DateStamp = (Get-Date -Format D) $FileDateStamp = Get-Date -Format yyyyMMdd $ScriptPath = Get-Location $ReportFileName = "$ScriptPath\ServerPatchReport.html" $ReportFileName2 = "$ScriptPath\ServerPatchReport-Unavailable.html" $BGColorTbl = "#EAECEE" $BGColorGood = "#4CBB17" $BGColorWarn = "#FFFC33" $BGColorCrit = "#FF0000" $PendingRebootYes = "Yes" $PendingRebootNo = "No" $ReportTitle = "$ReportTitle" $RunFrom = "This report was generated from $computername" $EmailSubject = "Millennium Patch Report for $DateStamp" $EmailAttachment = "$ScriptPath\Logo.PNG" $Global:Servers = Get-Content servers.txt <#================================================== Begin MAIN ==================================================#> # Create output file and nullify display output New-Item -ItemType file $ReportFileName -Force > $null New-Item -ItemType file $ReportFileName2 -Force > $null <#================================================== Write the HTML Header to the report file ==================================================#> ##HTML code If ($Servers.count -gt 0) { Write-ToLogFile -Info "Starting remote job against $($Servers.count) servers" $RemoteJob = Invoke-Command -ScriptBlock ${function:getRemoteServerInfo} -computername $Servers -AsJob $JobID = $RemoteJob.Id Wait-Job -Id $JobID -Timeout $JobTimeout | Out-Null $FailedServers = Get-Job -ID $JobID | select-object -expandproperty ChildJobs | Where-object {$_.State -ne "Completed"} | Select-object -expandproperty Location $CompletedJobs = Receive-Job -ID $JobID -ErrorAction SilentlyContinue Foreach ($Server in $FailedServers) { writeUnavailableData $ReportFileName2 $Server } Foreach ($Server in $CompletedJobs) { $Server | Sort-Object -Property LastReboot -Descending #Write-Host $Server $writeParams = @{ FileName = $ReportFileName Server = $Server.PSComputerName InstalledOn = $Server.InstalledOn KB = $Server.KB TaskTrigger = $Server.taskTrigger LastReboot = $Server.LastReboot } #$writeParams | sort-object @{Expression={$_[2]}; Ascending=$false} writeUpdateData @writeParams } Write-Host "Finishing report..." -ForegroundColor "Yellow" writeHtmlFooter $ReportFileName } <#================================================== Function to write server update information to the HTML report file ==================================================#> Function writeUpdateData { param($FileName,$Server,$InstalledOn,$Domain,$KB,$OSType,$DataCenter,$taskTrigger,$LastReboot) Add-Content $FileName "<tr>" Add-Content $FileName "<td align='center'>$Server</td>" Add-Content $FileName "<td align='center'>$OSType</td>" Add-Content $FileName "<td align='center'>$Domain</td>" Add-Content $FileName "<td align='center'>$InstalledOn</td>" Add-Content $FileName "<td align='center'>$LastReboot</td>" Add-Content $FileName "<td align='center'>$KB</td>" # Color BG depending on $Warning and $Critical days set in script If ($InstalledOn -eq "Error collecting data") { $DaySpanDays = "Error" } Else { $System = (Get-Date -Format "MM/dd/yyyy hh:mm:ss") $DaySpan = New-TimeSpan -Start $InstalledOn -End $System $DaySpanDays = $DaySpan.Days } If ($InstalledOn -eq "Error collecting data" -or $DaySpan.Days -gt $Critical) { # Red for Critical or Error retrieving data Add-Content $FileName "<td bgcolor=$BGColorCrit align='center'>$DaySpanDays</td>" #Add-Content $FileName "</tr>" } ElseIf ($DaySpan.Days -le $Warning) { # Green for Good Add-Content $FileName "<td bgcolor=$BGColorGood align=center>$DaySpanDays</td>" #Add-Content $FileName "</tr>" } Else { # Yellow for Warning Add-Content $FileName "<td bgcolor=$BGColorWarn align=center>$DaySpanDays</td>" #Add-Content $FileName "</tr>" } Add-Content $FileName "<td align='center'>$datacenter</td>" Add-Content $FileName "<td align='center'>$taskTrigger</td>" } <#================================================== Function for servers that are unavailable ==================================================#> Function writeUnavailableData { param($FileName,$Server) Add-Content $FileName "<tr>" Add-Content $FileName "<td bgcolor=$BGColorWarn align='center'>$server</td>" } <#================================================== Function to write the HTML footer ==================================================#> Function writeHtmlFooter { param($FileName) Add-Content $FileName "</table>" Add-content $FileName "<table width='75%' align=`"center`">" Add-Content $FileName "<tr bgcolor=$BGColorTbl>" #Add-Content $FileName "<td width='75%' align='center'><strong>Total Servers: $ServerCount</strong></td>" Add-Content $FileName "</tr>" Add-Content $FileName "</table>" Add-Content $FileName "</body>" Add-Content $FileName "</html>" } function getRemoteServerInfo { #Create output object $OutputObject = New-Object PSObject #Fetch last reboot date / time $LastReboot =gwmi win32_operatingsystem | %{ $_.ConvertToDateTime($_.LastBootUpTime) } $OutputObject | Add-Member -MemberType NoteProperty -Name LastReboot -value $LastReboot #Fetch patch info $session = [activator]::CreateInstance([type]::GetTypeFromProgID('Microsoft.Update.Session')) $searcher = $session.CreateUpdateSearcher() $totalupdates = $searcher.GetTotalHistoryCount() $remoteresult = $searcher.QueryHistory(0 , $totalupdates) | select-Object -First 1 | Select-Object Date, Title $OutputObject | Add-Member -MemberType NoteProperty -Name remoteresult -value $remoteresult $Installed = $remoteresult.date $InstalledOn = $Installed.tolocaltime() $OutputObject | Add-Member -MemberType NoteProperty -Name InstalledOn -value $InstalledOn $KB = $remoteresult.Title.Split('(')[1].split(')')[0] $OutputObject | Add-Member -MemberType NoteProperty -Name KB -value $KB #Fetch Scheduled Reboot Interval $OS = Invoke-Command { (Get-WMIObject win32_operatingsystem).caption } $caption = $OS.substring(25,4) if(($caption -eq "2016") -or ($caption -eq "2012")) { $task = Invoke-Command { Get-ScheduledTask | Where-Object {$_.Taskname -match "Weekly Scheduled Reboot"}} $tasktime = $task.Triggers[0] $tasktime = $tasktime | Select-Object StartBoundary $tasktime = $tasktime.StartBoundary.Substring(11) $taskday = $task.Triggers[0] $taskday = $taskday | Select-Object StartBoundary $taskday = $taskday.StartBoundary.substring(0,10) $taskday = (get-date $taskday).DayOfWeek $taskTrigger = $taskday , "--" , $tasktime $OutputObject | Add-Member -MemberType NoteProperty -Name tasktrigger -value $taskTrigger $OutputObject } else { $Schedule = new-object -com Schedule.Service $Schedule.connect() $rootTaskFolder = $Schedule.GetFolder("\") $task = $rootTaskFolder.GetTask("Weekly Scheduled Reboot") $taskTrigs = $task.NextRunTime $taskday = (get-date $taskTrigs).DayOfWeek | ForEach-Object{ $_ } | ft -AutoSize | Out-String $tasktime = $taskTrigs | ForEach-Object {([datetime]$_).ToString("HH:mm:ss")} $taskTrigger = $taskday , "--" , $tasktime $OutputObject | Add-Member -MemberType NoteProperty -Name tasktrigger -value $taskTrigger $OutputObject } }
Here is teh code, i removed the HTML code. let me know if that would be needed as well?Monday, April 6, 2020 10:30 AM -
I don't think anyone here wants to try to figure out what all of that is. You need to provide a clear example of the issue.
As noted above. You cannot sort hash tables. Make objects and not hashes. Objects pave properties that can be sorted.
This mat\y help you to understand how to ask a technical question in a forum:
\_(ツ)_/
Monday, April 6, 2020 1:38 PM -
Sorry, I will provide the gist of what i am providng.
- We have around 100 servers from which we pull hte information. I have created a function with the operations and calling that function in the invoke-command for remote execution. I think the issue is that the OutputObject doesn't hold all the values outside the loop as it is getting executed one by one. I am looking for a way in which the outputobjet will have all the values and then i should be able to use sort-object to sort it and add it to the HTML.
function getRemoteServerInfo { #Create output object $OutputObject = New-Object PSObject $OutputObject | Add-Member -MemberType NoteProperty -Name LastReboot -value $LastReboot $OutputObject | Add-Member -MemberType NoteProperty -Name InstalledOn -value $InstalledOn $OutputObject | Add-Member -MemberType NoteProperty -Name tasktrigger -value $taskTrigger $OutputObject } foreach ($S in $servers) { Invoke-Command -ScriptBlock ${function:getRemoteServerInfo} -computername $S -AsJob }
- Edited by Koz0s Monday, April 6, 2020 2:37 PM
Monday, April 6, 2020 2:34 PM -
You need to learn how to format code so that it is readable. That way you will be able to see your mistakes.
This would be the way to create objects that are sortable.
function getRemoteServerInfo { [pscustomobject]@{ LastReboot = $LastReboot InstalledOn = $InstalledOn TaskTrigger = $taskTrigger } }
You don't need a function to do this. Until you learn basic PowerShell I recommend avoiding functions. They will only confuse your early efforts.
\_(ツ)_/
Monday, April 6, 2020 3:46 PM -
Your function mat create an object but that object will contain no data as it is all null variables.
\_(ツ)_/
Monday, April 6, 2020 3:48 PM