Home > Net >  Get Uptime on Each Computer in an Array, Select the machines with the most uptime, and remotely exec
Get Uptime on Each Computer in an Array, Select the machines with the most uptime, and remotely exec

Time:11-18

The majority of this code was pulled from a blog online, but I think it's exactly the way I need to be tackling this. I want to get the top 4 machines from an OU based on uptime, and run a script that lives on each of the top 4 machines. I know that the problem involves the Array losing access to the Get-ADComputer properties, but I'm unsure of how to pass these new properties back to their original objects. This works as expected until it gets to the foreach loop at the end.

$scriptBlock={ 
    $wmi = Get-WmiObject -Class Win32_OperatingSystem
    ($wmi.ConvertToDateTime($wmi.LocalDateTime) – $wmi.ConvertToDateTime($wmi.LastBootUpTime)).TotalHours
}

$UpTime = @()


Get-ADComputer -Filter 'ObjectClass -eq "Computer"' -SearchBase "OU=***,OU=***,OU=***,DC=***,DC=***"  -SearchScope Subtree `
    | ForEach-Object { $Uptime  = `
            (New-Object psobject -Property @{
                    "ComputerName" = $_.DNSHostName
                    "UpTimeHours" = (Invoke-Command -ComputerName $_.DNSHostName -ScriptBlock $scriptBlock)
                }
            )
        }

 $UpTime | Where-Object {$_.UpTimeHours -ne ""} | sort-object -property @{Expression="UpTimeHours";Descending=$true} | `
    Select-Object -Property ComputerName,@{Name="UpTimeHours"; Expression = {$_.UpTimeHours.ToString("#.##")}} | Select-Object -First 4 |`
        Format-Table -AutoSize -OutVariable $Top4.ToString()




foreach ($Server in $Top4.ComputerName) {

    Invoke-Command -ComputerName $Server -ScriptBlock {HOSTNAME.EXE}
}

I'm not married to Invoke-Command in the last foreach but am having the same issues when I try to use psexec. Also, I'm running hostname.exe as a check to make sure I'm looping through the correct machines before I point it at my script.

CodePudding user response:

Here's a streamlined version of your code, which heeds the comments on the question:

# Get all computers of interest.
$computers = Get-ADComputer -Filter 'ObjectClass -eq "Computer"' -SearchBase "OU=***,OU=***,OU=***,DC=***,DC=***" -SearchScope Subtree 

# Get the computers' up-times in hours.
# The result will be [double] instances, but they're also decorated
# with .PSComputerName properties to identify the computer of origin.
$upTimes = Invoke-Command -ComputerName $computers.ConputerName { 
  ((Get-Date) - (Get-CimInstance -Class Win32_OperatingSystem).LastBootUpTime).TotalHours
}

# Get the top 4 computers by up-time.
$top4 = $upTimes | Sort-Object -Descending | Select-Object -First 4

# Invoke a command on all these 4 computers in parallel.
Invoke-Command -ComputerName $top4.PSComputerName -ScriptBlock { HOSTNAME.EXE }
  • Related