Getting quick Server Ping Results in Powershell - powershell

I have written below PowerShell script to get the ping results of server and it also generates the log for the same. My script works fine, also generates log but it take so much time as there are many servers. Is there any way I can quickly get the results. I have tried start-job but that generates error.
$logpath = $logpath +"\" +$Logname
Function Log($txt)
{
if (! (Test-Path $logpath)) {
New-Item $logpath |Out-Null
}
$date = Get-Date -Format "dd_MMM_yyyy_hh:mm:ss - "
$txt1 = ($date + $txt)
Add-Content "$logpath" "$txt1"
Add-Content "$logpath" " "
}
$ServerDetails=import-csv $Servercsv
foreach($servertest in $ServerDetails)
{
if((Test-Connection -ComputerName $servertest.servers -Count 2))
{
Log("'" + $servertest.servers + "' Successfully started operation")
Write-Host "Started Operation Successfully"
}
if(!(Test-Connection -ComputerName $servertest.servers -Count 2))
{
Log("'" + $servertest.servers + "'Servers are not pinging")
Write-Host "Servers are not pinging"
}
}

Assumed your "log" function works as expected you could make the rest of your code a little more efficient:
$ServerList = import-csv $Servercsv
foreach ($ComputerName in $ServerList) {
$Connection = Test-Connection -ComputerName $ComputerName.servers -Count 1 -Quiet
if ($Connection) {
Log("'" + $ComputerName.servers + "' Successfully started operation")
Write-Host "Started Operation Successfully"
}
Else {
Log("'" + $ComputerName.servers + "'Servers are not pinging")
Write-Host "Servers are not pinging"
}
}

For the speed effort for pinging, try this one out and compare speeds relative to how you are doing/getting from yours.
Final Super-Fast Ping Command
function Test-OnlineFast
{
param
(
# make parameter pipeline-aware
[Parameter(Mandatory,ValueFromPipeline)]
[string[]]
$ComputerName,
$TimeoutMillisec = 1000
)
begin
{
# use this to collect computer names that were sent via pipeline
[Collections.ArrayList]$bucket = #()
# hash table with error code to text translation
$StatusCode_ReturnValue =
#{
0='Success'
11001='Buffer Too Small'
11002='Destination Net Unreachable'
11003='Destination Host Unreachable'
11004='Destination Protocol Unreachable'
11005='Destination Port Unreachable'
11006='No Resources'
11007='Bad Option'
11008='Hardware Error'
11009='Packet Too Big'
11010='Request Timed Out'
11011='Bad Request'
11012='Bad Route'
11013='TimeToLive Expired Transit'
11014='TimeToLive Expired Reassembly'
11015='Parameter Problem'
11016='Source Quench'
11017='Option Too Big'
11018='Bad Destination'
11032='Negotiating IPSEC'
11050='General Failure'
}
# hash table with calculated property that translates
# numeric return value into friendly text
$statusFriendlyText = #{
# name of column
Name = 'Status'
# code to calculate content of column
Expression = {
# take status code and use it as index into
# the hash table with friendly names
# make sure the key is of same data type (int)
$StatusCode_ReturnValue[([int]$_.StatusCode)]
}
}
# calculated property that returns $true when status -eq 0
$IsOnline = #{
Name = 'Online'
Expression = { $_.StatusCode -eq 0 }
}
# do DNS resolution when system responds to ping
$DNSName = #{
Name = 'DNSName'
Expression = { if ($_.StatusCode -eq 0) {
if ($_.Address -like '*.*.*.*')
{ [Net.DNS]::GetHostByAddress($_.Address).HostName }
else
{ [Net.DNS]::GetHostByName($_.Address).HostName }
}
}
}
}
process
{
# add each computer name to the bucket
# we either receive a string array via parameter, or
# the process block runs multiple times when computer
# names are piped
$ComputerName | ForEach-Object {
$null = $bucket.Add($_)
}
}
end
{
# convert list of computers into a WMI query string
$query = $bucket -join "' or Address='"
Get-WmiObject -Class Win32_PingStatus -Filter "(Address='$query') and timeout=$TimeoutMillisec" |
Select-Object -Property Address, $IsOnline, $DNSName, $statusFriendlyText
}
}
Test-OnlineFast -ComputerName google.de, powershellmagazine.com, 10.10.10.200, 127.0.0.1
<#
# Results
Address Online DNSName Status
------- ------ ------- ------
127.0.0.1 True DESKTOP-7AAMJLF Success
google.de True google.de Success
powershellmagazine.com True powershellmagazine.com Success
10.10.10.200 False Request Timed Out
#>

Test-Connection with an array of targetnames and the asjob parameter is fast (powershell 5.1). Unresponsive addresses have a null responsetime. Annoyingly, the property names don't match the column headings.
$list = 'microsoft.com','yahoo.com'
$results = test-connection $list -count 1 -asjob | receive-job -wait
$results | select address,responsetime
address responsetime
------- ------------
yahoo.com 39
microsoft.com

Related

Foreach loop in powershell with hasharray

I'm writing a powershell script to ping all the servers and check which are offline. but i have a bug. By name it works perfectly. But when i do test-connection with an IP it seems to work BUT i cant output the name of the IP in the hashlist. Could someone help me figure this out? Thanks!!
System.Collections.Hashtable.keys Is online/available, This is what it outputs. But i want it to say "Servername is online/available"
#Creating IP Array list
$ip_array = #{
Server = [ipaddress] "192.168.1.1"
sws = [ipaddress] "192.168.1.1"
}
Foreach ($ip in $ip_array)
{
if((Test-Connection -IPAddress $ip.values.ipaddresstostring -quiet -count 1 ) -eq $false)
{
write-output("$ip.keys Is offline/unavailable, please troubleshoot connection, script is terminating") | Red
}
else
{
$ping = $true
write-output("$ip.keys Is online/available") | Green
}
}
PowerShell's default pipeline semantics (any collection that can be enumerated and unraveled will be) makes dictionaries a pain to work with - piping them anywhere would result in a list of disjoint key-value-pairs, dictionary itself lost.
For this reason, PowerShell refuses to automatically enumerate dictionaries, and you must manually obtain an enumerator in order to loop over the entries in it:
foreach($entry in $ip_hash.GetEnumerator()){
# reference `$entry.Key` or `$entry.Name` for the key (eg. Server)
# reference `$entry.Value` for the value (eg. 192.168.1.1)
}
If you really intend to use a Hashtable for this, combining IP addresses with computernames, change to something like this:
# creating IP Hashtable
$ip_hash = #{
'192.168.1.1' = 'Server1'
'192.168.1.2' = 'Server2'
# etcetera
}
# loop through the hash, key-by-key
foreach ($ip in $ip_hash.Keys) {
$ping = Test-Connection -ComputerName $ip -Quiet -Count 1 -ErrorAction SilentlyContinue
if(!$ping) {
Write-Host "Server $($ip_hash[$ip]) is offline/unavailable, please troubleshoot connection, script is terminating" -ForegroundColor Red
}
else {
Write-Host "Server $($ip_hash[$ip]) is online/available" -ForegroundColor Green
}
}
Output would look like:
The Keys in the hash must all have unique values

Powersell - Remotely Query if User Exists Across Domain [Fastest]

Abstract
So I work for a company that has roughly 10k computer assets on my domain. My issue is the time it takes to query if a user exists on a computer to see if they've ever logged into said computer. We need this functionality for audits in case they've done something they shouldn't have.
I have two methods in mind I've researched to complete this task, and a third alternative solution I have not thought of;
-Method A: Querying every computer for the "C:\Users<USER>" to see if LocalPath exists
-Method B: Checking every computer registry for the "HKU:<SID>" to see if the SID exists
-Method C: You are all smarter than me and have a better way? XD
Method A Function
$AllCompFound = #()
$AllADComputer = Get-ADComputer -Properties Name -SearchBase "WhatsItToYa" -filter 'Name -like "*"' | Select-Object Name
ForEach($Computer in $AllADComputers) {
$CName = $Computer.Name
if (Get-CimInstance -ComputerName "$CName" -ClassName Win32_Profile | ? {"C:\Users\'$EDIPI'" -contains $_.LocalPath}) {
$AllCompFound += $CName
} else {
#DOOTHERSTUFF
}
}
NOTE: I have another function that prompts me to enter a username to check for. Where I work they are numbers so case sensitivity is not an issue. My issue with this function is I believe it is the 'if' statement returns true every time because it ran rather than because it matched the username.
Method B Function
$AllCompFound = #()
$AllADComputer = Get-ADComputer -Properties Name -SearchBase "WhatsItToYa" -filter 'Name -like "*"' | Select-Object Name
$hive = [Microsoft:Win32.RegistryHive]::Users
ForEach($Computer in $AllADComputers) {
try {
$base = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive, $Computer.Name)
$key = &base.OpenSubKey($strSID)
if ($!key) {
#DOSTUFF
} else {
$AllCompFound += $Computer.Name
#DOOTHERSTUFF
}
} catch {
#IDONTTHROWBECAUSEIWANTITTOCONTINUE
} finally {
if($key) {
$key.Close()
}
if ($base) {
$base.Close()
}
}
}
NOTE: I have another function that converts the username into a SID prior to this function. It works.
Where my eyes start to glaze over is using Invoke-Command and actually return a value back, and whether or not to run all of these queries as their own PS-Session or not. My Method A returns false positives and my Method B seems to hang up on some computers.
Neither of these methods are really fast enough to get through 10k results, I've been using smaller pools of computers in order to get test these results when requested. I'm by no means an expert, but I think I have a good understanding, so any help is appreciated!
First, use WMI Win32_UserProfile, not C:\Users or registry.
Second, use reports from pc to some database, not from server to pc. This is much better usually.
About GPO: If you get access, you can Add\Remove scheduled task for such reports through GPP (not GPO) from time to time.
Third: Use PoshRSJob to make parallel queries.
Get-WmiObject -Class 'Win32_USerProfile' |
Select #(
'SID',
#{
Name = 'LastUseTime';
Expression = {$_.ConvertToDateTime($_.LastUseTime)}}
#{
Name = 'NTAccount';
Expression = { [System.Security.Principal.SecurityIdentifier]::new($_.SID).Translate([System.Security.Principal.NTAccount])}}
)
Be careful with translating to NTAccount: if SID does not translates, it will cause error, so, maybe, it's better not to collect NTAccount from user space.
If you have no other variants, parallel jobs using PoshRSJob
Example for paralleling ( maybe there are some typos )
$ToDo = [System.Collections.Concurrent.ConcurrentQueue[string]]::new() # This is Queue (list) of computers that SHOULD be processed
<# Some loop through your computers #>
<#...#> $ToDo.Enqueue($computerName)
<#LoopEnd#>
$result = [System.Collections.Concurrent.ConcurrentBag[Object]]::new() # This is Bag (list) of processing results
# This function has ComputerName on input, and outputs some single value (object) as a result of processing this computer
Function Get-MySpecialComputerStats
{
Param(
[String]$ComputerName
)
<#Some magic#>
# Here we make KSCustomObject form Hashtable. This is result object
return [PSCustomObject]#{
ComputerName = $ComputerName;
Result = 'OK'
SomeAdditionalInfo1 = 'whateverYouWant'
SomeAdditionalInfo2 = 42 # Because 42
}
}
# This is script that runs on background. It can not output anything.
# It takes 2 args: 1st is Input queue, 2nd is output queue
$JobScript = [scriptblock]{
$inQueue = [System.Collections.Concurrent.ConcurrentQueue[string]]$args[0]
$outBag = [System.Collections.Concurrent.ConcurrentBag[Object]]$args[1]
$compName = $null
# Logging inside, if you need it
$log = [System.Text.StringBuilder]::new()
# we work until inQueue is empty ( then TryDequeue will return false )
while($inQueue.TryDequeue([ref] $compName) -eq $true)
{
$r= $null
try
{
$r = Get-MySpecialComputerStats -ComputerName $compName -EA Stop
[void]$log.AppendLine("[_]: $($compName) : OK!")
[void]$outBag.Add($r) # We append result to outBag
}
catch
{
[void]$log.AppendLine("[E]: $($compName) : $($_.Exception.Message)")
}
}
# we return log.
return $log.ToString()
}
# Some progress counters
$i_max = $ToDo.Count
$i_cur = $i_max
# We start 20 jobs. Dont forget to say about our functions be available inside job
$jobs = #(1..20) <# Run 20 threads #> | % { Start-RSJob -ScriptBlock $JobScript -ArgumentList #($ToDo, $result) -FunctionsToImport 'Get-MySpecialComputerStats' }
# And once per 3 seconds we check, how much entries left in Queue ($todo)
while ($i_cur -gt 0)
{
Write-Progress -Activity 'Working' -Status "$($i_cur) left of $($i_max) computers" -PercentComplete (100 - ($i_cur / $i_max * 100))
Start-Sleep -Seconds 3
$i_cur = $ToDo.Count
}
# When there is zero, we shall wait for jobs to complete last items and return logs, and we collect logs
$logs = $jobs | % { Wait-RSJob -Job $_ } | % { Receive-RSJob -Job $_ }
# Logs is LOGS, not result
# Result is in the result variable.
$result | Export-Clixml -Path 'P:/ath/to/file.clixml' # Exporting result to CliXML file, or whatever you want
Please be careful: there is no output inside $JobScript done, so it must be perfectly done, and function Get-MySpecialComputerStats must be tested on unusual ways to return value that can be interpreted.

How do I add a string to a variable called from a CSV file before it is called in a function?

I am trying to ping a list of IPs, but I need to test variations of them for RACs and KVMs. I want to take the IP address (in the $ColumnHeader variable) and append "rac" to it before pinging it. I also will need to ping "arac", "raca", "kv", "akv", "kva", and "kvm", but I was just going to substitute those manually into the script after running it each time.
Param(
[Parameter(Mandatory=$true, position=0)][string]$csvfile
)
$ColumnHeader = "Name"
#$string = "rac"
#$subServer = "$($ColumnHeader)$($string)"
Write-Host "Reading file" $csvfile
$ipaddresses = Import-Csv $csvfile | Select-Object $ColumnHeader
Write-Host "Started Pinging.."
foreach ($ip in $ipaddresses) {
if (Test-Connection $ip.($ColumnHeader) -Count 1 -Quiet) {
Write-Host $ip.("Name") "Ping succeeded." -Foreground Green
} else {
Write-Host $ip.("Name") "Ping failed." -Foreground Red
}
}
Write-Host "Pinging Completed."
I've tried creating new variables $string and $subServer and using those in place of $ColumnHeader on line 14, but I get a "Cannot validate argument on parameter 'ComputerName'." error.
EDIT: I changed Line 7 from $subServer = $ColumnHeader + $string to $subServer = "$($ColumnHeader)$($string)", and I can successfully call $subServer on Line 14 in place of $ColumnHeader, but when I uncomment $string on Line 6, I get the aforementioned 'ComputerName' error again.

Add-PSsnapin in runspace with foreach-parallel

I use the funtion foreach-parallel for run many scriptblock like runspace
the first load snapin correctly but all next return 2 error
1..5 | Foreach-Parallel -Throttle 5 -Timeout 5 -sleeptimer 5 {
add-PSSnapin 'Quest.ActiveRoles.ADManagement'
try {
get-qadUser 'Domain\me'
} catch {
return "$($Error[0].Exception)"
}
}
my errors is :
add-PSSnapin : An item with the same key has already been added
get-qadUser : function doesn't exist
In runspacePool the command Add-PSSnapin and Import-Module doesn't work !
It's need to add in Initial Default State not in ScriptBlock:
$ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
[void]$ISS.ImportPSSnapIn('Quest.ActiveRoles.ADManagement', [ref]$null)
[void]$ISS.ImportPSModule('PSTerminalServices')
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host)
$RunspacePool.Open()
I made a comment above on what I think you should do but to clarify you will want to ensure the snapin is loaded before your call so make sure its executed before you run your Foreach-parallel.
add-PSSnapin 'Quest.ActiveRoles.ADManagement'
Foreach-Parallel -Throttle 5 -Timeout 5 -sleeptimer 5 {
get-qadUser 'domain\testUser'
}
There is an easy way to test for a cmdlet and if not found add the PSSnapin or Import-Module
Adding the below to the start of your script will check for the presence of a CMDLET and if not found, add it.
IF(
Get-Command get-qadUser -ErrorAction SilentlyContinue){}
ELSE{add-PSSnapin 'Quest.ActiveRoles.ADManagement'}
Finaly I use another code, I use like that :
$Servers | Run-Parallel -scriptBlock $ScriptBlock -TimeOut 10 -PSModules 'PSTerminalServices' -PSSnapins 'Quest.ActiveRoles.ADManagement' | out-gridView
complet code
function Run-Parallel {
<#
.Synopsis
This is a quick and open-ended script multi-threader searcher
http://www.get-blog.com/?p=189#comment-28834
Improove by Alban LOPEZ 2016
.Description
This script will allow any general, external script to be multithreaded by providing a single
argument to that script and opening it in a seperate thread. It works as a filter in the
pipeline, or as a standalone script. It will read the argument either from the pipeline
or from a filename provided. It will send the results of the child script down the pipeline,
so it is best to use a script that returns some sort of object.
Authored by Ryan Witschger - http://www.Get-Blog.com
.PARAMETER ScriptBlock
This is where you provide the PowerShell ScriptBlock that you want to multithread.
.PARAMETER ItemObj
The ItemObj represents the arguments that are provided to the child script. This is an open ended
argument and can take a single object from the pipeline, an array, a collection, or a file name. The
multithreading script does it's best to find out which you have provided and handle it as such.
If you would like to provide a file, then the file is read with one object on each line and will
be provided as is to the script you are running as a string. If this is not desired, then use an array.
.PARAMETER InputParam
This allows you to specify the parameter for which your input objects are to be evaluated. As an example,
if you were to provide a computer name to the Get-Process cmdlet as just an argument, it would attempt to
find all processes where the name was the provided computername and fail. You need to specify that the
parameter that you are providing is the "ComputerName".
.PARAMETER AddParam
This allows you to specify additional parameters to the running command. For instance, if you are trying
to find the status of the "BITS" service on all servers in your list, you will need to specify the "Name"
parameter. This command takes a hash pair formatted as follows:
#{"key" = "Value"}
#{"key1" = "Value"; "key2" = 321; "key3" = 1..9}
.PARAMETER AddSwitch
This allows you to add additional switches to the command you are running. For instance, you may want
to include "RequiredServices" to the "Get-Service" cmdlet. This parameter will take a single string, or
an aray of strings as follows:
"RequiredServices"
#("RequiredServices", "DependentServices")
.PARAMETER MaxThreads
This is the maximum number of threads to run at any given time. If resources are too congested try lowering
this number. The default value is 20.
.PARAMETER SleepTimer
This is the time between cycles of the child process detection cycle. The default value is 200ms. If CPU
utilization is high then you can consider increasing this delay. If the child script takes a long time to
run, then you might increase this value to around 1000 (or 1 second in the detection cycle).
.PARAMETER TimeOut
this is the timeOut for slower instance, only each other are returned
.PARAMETER PSModules
List of PSModule name to include for use in ScriptBlock
.PARAMETER PSSapins
List of PSSapin name to include for use in ScriptBlock
.EXAMPLE
Both of these will execute the scriptBlock and provide each of the server names in AllServers.txt
while providing the results to GridView. The results will be the output of the child script.
gc AllServers.txt | Run-Parallel $ScriptBlock_GetTSUsers -MaxThreads $findOut_AD.ActiveDirectory.Servers.count -PSModules 'PSTerminalServices' | out-gridview
#>
Param(
[Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
$ItemObj,
[ScriptBlock]$ScriptBlock = $null,
$InputParam = $Null,
[HashTable] $AddParam = #{},
[Array] $AddSwitch = #(),
$MaxThreads = 20,
$SleepTimer = 200,
$TimeOut = 5,
[string[]]$PSSapins = $null,
[string[]]$PSModules = $null
)
Begin{
$ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
ForEach ($Snapin in $PSSapins){
[void]$ISS.ImportPSSnapIn($Snapin, [ref]$null)
}
ForEach ($Module in $PSModules){
[void]$ISS.ImportPSModule($Module)
}
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host)
$RunspacePool.Open()
$Jobs = #()
if ($CommonObject.Settings.Debug) {$CommonObject.host.ui.WriteLine("[ Start ] :")}
}
Process{
Write-Progress -Activity "Preloading Threads" -Status "Starting Job $($jobs.count)"
#ForEach ($Object in $ItemObj){
if ($ItemObj){
$PowershellThread = [powershell]::Create().AddScript($ScriptBlock)
If ($InputParam -ne $Null){
$PowershellThread.AddParameter($InputParam, $ItemObj.ToString()) | out-null
}Else{
$PowershellThread.AddArgument($ItemObj.ToString()) | out-null
}
ForEach($Key in $AddParam.Keys){
$PowershellThread.AddParameter($Key, $AddParam.$key) | out-null
}
ForEach($Switch in $AddSwitch){
$PowershellThread.AddParameter($Switch) | out-null
}
$PowershellThread.RunspacePool = $RunspacePool
$Handle = $PowershellThread.BeginInvoke()
$Job = [pscustomobject][ordered]#{Handle=''; Thread=''; object=''}
$Job.Handle = $Handle
$Job.Thread = $PowershellThread
$Job.Object = $ItemObj.ToString()
$Jobs += $Job
if ($CommonObject.Settings.Debug) {$CommonObject.host.ui.WriteLine("`t$ItemObj")}
}
#}
}
End{
$ResultTimer = Get-Date
While (#($Jobs | Where-Object {$_.Handle -ne $Null}).count -gt 0) {
$Remaining = "$($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).object)"
If ($Remaining.Length -gt 60){
$Remaining = $Remaining.Substring(0,60) + "..."
}
Write-Progress `
-Activity "Waiting for Jobs - $($MaxThreads - $($RunspacePool.GetAvailableRunspaces())) of $MaxThreads threads running" `
-PercentComplete (($Jobs.count - $($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).count)) / $Jobs.Count * 100) `
-Status "$(#($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False})).count) remaining - $remaining"
ForEach ($Job in $($Jobs | Where-Object {$_.Handle.IsCompleted -eq $True})){
$Job.Thread.EndInvoke($Job.Handle)
$Job.Thread.Dispose()
$Job.Thread = $Null
$Job.Handle = $Null
$ResultTimer = Get-Date
}
If (($(Get-Date) - $ResultTimer).totalseconds -gt $TimeOut){
$NOK = $($Jobs | Where-Object {$_.Handle})
if ($CommonObject.Settings.Debug) {$CommonObject.host.ui.WriteErrorLine("[ TimeOut ] $($NOK.count) : $($NOK.object)")}
$NOK | %{
if ($CommonObject.Settings.Debug) {$CommonObject.host.ui.WriteErrorLine("[ stop ] $($_.object)")}
$_.thread.Stop() | Out-Null
if ($CommonObject.Settings.Debug) {$CommonObject.host.ui.WriteErrorLine("[ dispose ] $($_.object)")}
$_.thread.Dispose()
if ($CommonObject.Settings.Debug) {$CommonObject.host.ui.WriteErrorLine("[ null ] $($_.object)")}
$_.Thread = $Null
$_.Handle = $Null
}
$RunspacePool.Close() | Out-Null
$RunspacePool.Dispose() | Out-Null
exit
}
Start-Sleep -Milliseconds $SleepTimer
}
$RunspacePool.Close() | Out-Null
$RunspacePool.Dispose() | Out-Null
}
}

Script grabbing all the ips instead of just one and placing all of them in to variable

Here is what I am trying to accomplish.
Read all computers from a list
go through one by one and determine if the invoke-request produces an "OK"
if it does , place the computer name and the word yes in an excel spread sheet.
otherwise put the computer name and the word "NO" in the second column.
Instead of the script grabbing each ip in the servers.txt file .. it is putting them all together and failing. What am I missing here? As you can see below it is just putting all the ips in the $server variable.
Here is the error.
Invoke-WebRequest : Cannot bind parameter 'Uri'. Cannot convert value "http:// Computer1 Computer2 Computer3:1055" to type "System.Uri". Error: "Invalid URI: The
ERROR: hostname could not be parsed."
And the code is below
$Computers = Get-Content -Path C:\temp\servers.txt
foreach ($Server in $computers)
{
$reply = Invoke-WebRequest http://$computers":1055" | Select-Object statusdescription
if ($reply.statusdescription = "OK")
{
$Sheet1.Cells.Item($intRowSoft, 1) = $server
$Sheet1.Cells.Item($intRowSoft, 2) = "YES"
$intRow = $intRow + 1
}
else {
$Sheet1.Cells.Item($intRowSoft, 1) = $server
$Sheet1.Cells.Item($intRowSoft, 2) = "NO"
$intRow = $intRow + 1
}
}
The problem is that you are referencing $computers and not $server.
$reply = Invoke-WebRequest http://$server":1055" | Select-Object statusdescription