1

I have a text file containing a list of servers, one per line, like:

SERVER1
SERVER2
SERVER3

When I do a Get-Content on the file, I do see the output as:

SERVER1
SERVER2
SERVER3

So now I am writing a function that I want to take in the multiple servers as an array, and iterate over the array in the function. The function is currently like this:

function Get-LocalAdministrators 
{
    param(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [string[]]$computers
    )

    foreach ($computername in $computers)
    {
        $ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}

        foreach ($ADMIN in $ADMINS) 
        {
            $admin = $admin.replace("\\$computername\root\cimv2:Win32_UserAccount.Domain=","") # trims the results for a user
            $admin = $admin.replace("\\$computername\root\cimv2:Win32_Group.Domain=","") # trims the results for a group
            $admin = $admin.replace('",Name="',"\")
            $admin = $admin.REPLACE("""","") # strips the last "

            $objOutput = New-Object PSObject -Property @{
                Machinename = $($computername)
                Fullname = ($admin)
                #DomainName  =$admin.split("\")[0]
                #UserName = $admin.split("\")[1]
            }

        $objReport+=@($objOutput)
        }

        return $objReport
    }
}

Then I plan to call the function as:

Get-Content “C:\temp\computers.txt” | Get-LocalAdministrators

However, when I run the function, I can see that the value of $computers is {SERVER3} (i.e. only the last line in the file.) I have tried to find the answer to this via teh Google, and although there are a lot of array references/examples, I cannot find one where it combines reading the values from a file, into an array in a param statement. Please forgive my PS newb ignorance, and provide the clue that I need... Thanks.

UPDATE: Link to screenshot of script running in PowerGUI Script Editor showing the value of $computers during the run: debug run screenshot

1 Answer 1

1

When you pass objects via the pipeline into a function, only one is passed into your function at a time - not the whole array. So you don't need the foreach loop, nor do you need to make $computers an array in the function.

Also, when you have a pipeline function, you should be making use of the begin,process and end keywords. Each denotes a script block - begin is a scriptblock that is executed once (when the pipeline is "set up"), process is the scriptblock to be executed for each object passed via the pipeline, and end is just like begin only it runs after the last item has passed through.

So minimally, your function should be this:

function Get-LocalAdministrators
{
    param(
    [Parameter(Mandatory=$True,Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
    [string]$computer
    )
process{
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
# Do other stuff here
}
}

The MSDN documentation says (this is in get-help about_functions - there's more to it than this):

Piping Objects to Functions
Any function can take input from the pipeline. You can control how a function processes input from the pipeline using Begin, Process, and End keywords. The following sample syntax shows the three keywords:

      function <name> { 
          begin {<statement list>}
          process {<statement list>}
          end {<statement list>}
      }

  The Begin statement list runs one time only, at the beginning of 
  the function.  

  The Process statement list runs one time for each object in the pipeline.
  While the Process block is running, each pipeline object is assigned to 
  the $_ automatic variable, one pipeline object at a time. 

  After the function receives all the objects in the pipeline, the End 
  statement list runs one time. If no Begin, Process, or End keywords are 
  used, all the statements are treated like an End statement list.

Edit: After seeing the full code added by the OP, this works. Note that I have made the changes to your code as I describe above.

function Get-LocalAdministrators 
{
    param(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [string]$computer
    )

    process{
        $ADMINS = get-wmiobject -computername $computer -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computer',Name='administrators'""" | % {$_.partcomponent}

        foreach ($ADMIN in $ADMINS) 
        {
            $admin = $admin.replace("\\$computername\root\cimv2:Win32_UserAccount.Domain=","") # trims the results for a user
            $admin = $admin.replace("\\$computername\root\cimv2:Win32_Group.Domain=","") # trims the results for a group
            $admin = $admin.replace('",Name="',"\")
            $admin = $admin.REPLACE("""","") # strips the last "

            $objOutput = New-Object PSObject -Property @{
                Machinename = $($computer)
                Fullname = ($admin)
                #DomainName  =$admin.split("\")[0]
                #UserName = $admin.split("\")[1]
            }

        $objReport+=@($objOutput)
        }

        $objReport
    }
}
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks for the info, but this still doesn't fix the problem that $computers has only one value (the last line) from the pipeline from Get-Content... The function does run, but only gives me output for the last server named in the file... I'm assuming because $computers only has the one value in it. How do I pass in the multiple values (lines) from the file so that $computers has multiple values in it?
Get-Content reads all the lines into an array, where each element is one line. $computers should have as many value as lines in the file. My guess is that you're using an output file and overwriting it each time, so in the end you only have the results from the final iteration. It would help if you'd post the entire function.
You haven't shown how you're doing your output. $computers does have all the values in it (I ran the code myself), and if you replace the $admins line with just $computer you will see all 3 names output. Which leads me to the conclusion that there's something in the output that you aren't showing us that's causing your issue - that (..) section.
edited original post to: 1) add full function code 2) add link to screenshot showing script running in PowerGUI script editor showing value of $computers vs the output of Get-Content in the bottom left pane
@WillDennis please, please re-read my post in full. You need to drop the foreach and make the parameter a single string, not an array. Your OP is also flawed in that you're calling return within the foreach loop - so it's only going to run through one iteration!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.