I put together a script that searches for a user’s profile on a list of computers and removes the profile if found. It works, but now I’m trying to clean it up and break it into a function or two, add help comments, logging, etc. Initially, I had a pair of nested ForEach loops:
ForEach ($c in $ComputerName) {. . .
ForEach ($u in $UserName) { . . . }
}
I am given understand that for the purposes of writing output to a log file, it would be better to pipe the variables to ForEach-Object. Is that correct? If so, how do I handle the objects inside the nested foreach loops? Referencing both the username and computername as $_ would be confusing at best, and in my case it wouldn’t work as I need to reference the computer as well as the user from inside the 2nd Foreach.
It’s generally a good practice to save the value of $_ to some other variable at the start of your ForEach-Object loops. That way if some other piece of code reassigns $_ later, you don’t lose the value you needed.
That said, if you already have your $ComputerName and $UserName arrays in memory, there’s really not much advantage to using ForEach-Object over foreach. The main difference is that you can pipe the results of ForEach-Object to another command, but there are ways to get around that even if you’re using foreach. Here’s one trick I use on occasion when I want to use foreach but still have it pipe results to something else:
# presumably, these are both arrays of strings that you want to enumerate over.
$computerName = @()
$userName = @()
& {
foreach ($computer in $computerName)
{
foreach ($user in $userName)
{
[pscustomobject] @{
ComputerName = $computer
UserName = $user
}
}
}
} |
Export-Csv -Path .\test.csv -NoClobber
By placing the foreach loops into an anonymous script block (curly braces) and invoking that script block with the call operator (&), the objects produced by the inner loop will be piped to Export-Csv one at a time, just as ForEach-Object allows you to do. Instead of an anonymous script block, you can also just put them into a function, like this:
function Some-FunctionName
{
[CmdletBinding()]
param (
[string[]]
$ComputerName,
[string[]]
$UserName
)
foreach ($computer in $ComputerName)
{
foreach ($user in $UserName)
{
[pscustomobject] @{
ComputerName = $computer
UserName = $user
}
}
}
}
# presumably, these are both arrays of strings that you want to enumerate over.
$computerName = @()
$userName = @()
Some-FunctionName -ComputerName $computerName -UserName $userName |
Export-Csv -Path .\test.csv -NoClobber
Ahh, so if the nested ForEach are inside a function, I would pipe the output to a log file when the function is called, rather than as a part of the function… that will work great, Thanks!