2

I have DHCP script that looks for matching hostnames in all the scopes on the DHCP servers

  • I first get all the DHCP servers and import a .txt of hostnames
$list = Get-Content C:\script\HostNameList.txt #Defines content it pulls as list 
$DHServers = Get-DhcpServerInDC #gives variable name for loop

 # Gets all DHCP servers ands scopes 
    foreach ($Server in $DHServers){
        $scopes = Get-DHCPServerv4Scope -ComputerName $Server.dnsname #get all scopes
    }
  • I loop through list of hostnames and scopes looking for a match. Somewhere in here is my issue
$Output = foreach ($hostname in $list) { #Calls each item in list a hostname and sends to output
    if (test-connection -count 1 -computername $hostname -quiet) #With 1 ping, check if hostname is online
    {   
        foreach ($scope in $scopes){ 
            if($scope | Get-DhcpServerV4Lease -ComputerName $server.dnsname | Where-Object HostName -like "$hostName*" ) #compares the hostname to lease to find which scope it is in
            { $scope.name } #return scope it found hostname in
        }
        [PSCustomObject]@{ #Rename varibles in data pull for output file
        Asset = $hostname
        Location = $scope.name #only want the name of the scope
        Status = "Online"
        }
    }   

    else #statement if hostname is not online
    { 
        Write-host "$hostname Is offline, only Last Location is known. $hostname was added to the output file." -BackgroundColor DarkRed
        [PSCustomObject]@{
        Asset = $hostname
        Location = $scope.name #only want the name of the scope, since the name = Location
        Status = "Offline"
        }
    }
}
$Output #show output in powershell
$Output | Export-Csv -Path C:\script\Asset_Result.csv -NoTypeInformation #outputs .csv
  • This is what it is doing, the output repeats the last item on the list of DHCP scopes.
Asset    Location         Status
-----     --------         ------
A847    Public Internet      Online
A261    Public Internet      Offline
A201    Public Internet      Online
  • This is what it should be doing
Asset    Location         Status
-----     --------         ------
A847        FLoor 1         Online
A261      West 1st FL       Offline
A201        Floor 3         Online

How can I get $scope.name in my if($scope | ... statement to go to my PSCustomObject after each iteration?

feelsgood
  • 135
  • 14
  • 1
    Wouldnt you have to place it in your found match? Meaning: `if($scope | Get-DhcpServerV4Lease -ComputerName $server.dnsname | Where-Object HostName -like "$hostName*" ) { $scope.name; [PSCustomObject]@{...` – Abraham Zinala Apr 07 '21 at 14:52

1 Answers1

2

This:

foreach ($Server in $DHServers){
  $scopes = Get-DHCPServerv4Scope -ComputerName $Server.dnsname #get all scopes
}

is - in net effect - the equivalent of:

$scopes = Get-DHCPServerv4Scope -ComputerName $DHServers[-1].dnsname #get all scopes

That is, you keep reassigning to the same variable ($scopes) in the loop body, replacing the previous value, so that you end up with only the result from the last loop iteration, for the last server stored in $DHServers, i.e. $DHServers[-1].


The best solution is to rely on PowerShell's ability to use statements such as foreach as an expression whose output - even iterative output from a loop - is automatically collected in an [object[]] array (with two or more outputs) by PowerShell:

# Collect the output from *all* Get-DHCPServerv4Scope calls.
[array] $scopes = foreach ($Server in $DHServers) {
  Get-DHCPServerv4Scope -ComputerName $Server.dnsname #get all scopes
}

Note: The [array] type constraint (same as: [object[]]) is only necessary if there can situationally be just one output object and you want to ensure that the collected output is always an array.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 2
    That was my guess too! Figured it was doing them one at a time as his actual intention, but this makes sense. – Abraham Zinala Apr 07 '21 at 15:02
  • 1
    @AbrahamZinala, yes, given the expected outcome, I think we can infer that collecting in an array is intended (which would also have worked with `$scopes += ...` inside a loop with a prior `$scopes = @()` initialization, but this type of iterative "appending" to an array is inefficient and therefore ill-advised). – mklement0 Apr 07 '21 at 15:07
  • Once all the scopes are collected in the array, how does ```foreach ($scope in $scopes){ if($scope | Get-DhcpServerV4Lease``` access that array to being comparing the host names to find matches? – feelsgood Apr 07 '21 at 15:18
  • 1
    @Bryce, if I understand correctly, you'll have to access the `$DHServers` array elements explicitly, along the lines of: `$i = 0; foreach ($scope in $scopes) { if($scope | Get-DhcpServerV4Lease -ComputerName $DHServers[$i++] ...` – mklement0 Apr 07 '21 at 15:24
  • You got it! This part ```$DHServers[$i++]``` is piping ```$DHServers``` into scope, then iterates through? – feelsgood Apr 07 '21 at 15:30
  • 1
    `$DHServers[$i++]` returns the i-th element from array `$DHServers` - this assumes that the `$DHServers` is still in scope when the `foreach ($scope in $scopes)` runs. – mklement0 Apr 07 '21 at 15:34
  • 1
    @BryceHoward, I was making the assumption that `$scopes` and `$DHServers` are _parallel_ arrays - but that may not be the case. Honestly, I haven't dug into what your code is trying to do. If your problem isn't solved yet, can I suggest you create a _new_ question just focused on your follow-up question, in a focused manner, ideally using an [MCVE (Minimal, Complete, and Verifiable Example)](http://stackoverflow.com/help/mcve)? Feel free to notify me here once you have done so, and I'm happy to take a look. – mklement0 Apr 07 '21 at 15:36
  • 1
    @mklement0 I posted a follow up question. Thanks again. – feelsgood Apr 07 '21 at 18:50
  • 1
    Thanks, @Bryce. I've looked at https://stackoverflow.com/q/66992392/45375, but so far I have nothing more to offer than zett42 already has in their answer. – mklement0 Apr 08 '21 at 11:09
  • 1
    @mklement0 Thanks for at least looking at it! I'll keep picking away at it on my own. Hopefully in a few days I'll be further along after learning more of PowerShell. – feelsgood Apr 08 '21 at 14:22