Hey all, another noob here. Having gone through the PS101 pages and mostly kinda-sorta understood what I read, I’m trying to do some scripting.
I have this script to recursively look through a path, find folders with inheritance removed, and print the path of just those folders:
$folders = Get-ChildItem -Recurse -Path "z:\temp"
foreach ($path in $folders)
{
if ($path.PSIsContainer -eq $false)
{
continue
}
if ((get-acl $path.fullname).AreAccessRulesProtected -eq $true)
{
$path.fullname
}
}
It works, which is great. But I don’t understand why it works. If I run $folders I get the same output as running Get-ChildItem -Recurse -Path "z:\temp". But how on Earth does the foreach ($path in $folders) work?
I don’t understand how we’re managing to grab just the path from the complete output of the Get-ChildItem command, especially because when I run $path I get complete results of Get-ChildItem for the last item that it processed.
In PowerShell you can assign the output of any command to a variable. When you output this variable the output looks the same like you would run the command. That’s helpful when you use the output of the command more than once.
PowerShell created implicitly an array for you with the objects Get-ChildItem provided. The foreach loop enumerates each individual element of that array and assigns it to the loop variable you specified as $path.
Since we work with objects and their properties in PowerShell you can access the individual properties with the so called dot notation $path.fullname. This way you get only the full path of the current object.
If you don’t need the raw data more than once your code can be shortened like this:
And even if you want to use the result of Get-ChildItem more than once you could omit the first if condition with the switch parameter -Directory for your Get-ChildItem. This will list only folders - not files. The opposite would be the parameter -File.
You should ALWAYS read the help for the cmdlets you’re about to use completely including the examples to learn how to use them:
Thank you, Olaf! I appreciate your help in this I’m still confused with the foreach ($path in $folders) part. When you say:
PowerShell created implicitly an array for you with the objects Get-ChildItem provided. The foreach loop enumerates each individual element of that array and assigns it to the loop variable you specified as $path .
How does it know which individual element of the array to specify as $path? Get-ChildItem returns more info than just the Name.
The foreach loop iterates over all single elements in the array. The current element is saved in the variable $path. Inside the loop YOU specify to use the property FullName of the current object saved in $path with the dot notation $path.FullName.
You can output other properties to the console in the same way:
$folders =
Get-ChildItem -Path 'z:\temp' -Directory
foreach ($path in $folders) {
"The name of the folder is '$($path.Name)' - the full path is '$($path.FullName)'"
}
Usually we try to have the result not with surrounding text. We want them as objects. This way we can use them for further steps
Hi Olaf, I really appreciate your expanded explanation! I think I’m beginning to understand.
When I run $folderList = Get-ChildItem -Path "z:\temp" -Recurse -Directory, the $folderList variable contains all the objects along with their individual properties that are returned by the Get-ChildItem cmdlet.
In the foreach, PowerShell creates the variable $path automatically when the foreach loop runs, starting with the first value in the array.
Running Get-ChildItem | Get-Member I see that .Name, .FullName, and PSIsContainer are properties of System.IO.DirectoryInfo.
But what’s actually in the array? How is it structured? If I run $folderList, this is what I see:
PS Z:\temp> $folderlist
Directory: Z:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
da---- 12/28/2021 10:30 AM xltmoore2x
d----- 7/28/2022 8:02 AM Auditing
PS Z:\temp>
Is the array just a list of the directory names? And it’s looping through the directory names and I can query the directory properties using System.IO.DirectoryInfo members from Get-ChildItem because that’s where the data originally came from?
If this is essentially correct, then I’ve had what my colleague Scott would call an “Aha! moment.”
If you want to see all of the properties of the variable I would use this
$FolderList | Get-Member
Get-Member is your best friend whenever you are concerned about what properties & methods you can use.
You are correct about that output being in the array, the Foreach loop goes from start to finish assigning it to the variable in the left hand side(in your case it’s $Folder) then runs whatever you have in the scriptblock against it. Then it assigns it to the next item in the array and so on.