Have you fought trying to query nested, duplicate-named folders? Hopefully this will help solve the problem! Suppose you have a VM folder-tree similar to this:
So, how do you get the "\dotcom\linux\dev" folder using PowerCLI? If you query for just "dev" then you can get an array of folders.
You can parse through the array and, using the parent object, traverse the tree backwards validating the folder names. But, what if you have 100s of folders? In my opinion, this is not an optimal approach. We really need to do this:
This is great case for recursion. In my words, recursion is a "stack" of operations. When an operation completes its result is used by the next operation in the "stack". Most importantly there has to be base-case which causes the last operation in the stack to return a valid result. Then each operation can be popped off the "stack" and its result can be used by the previous operation until the final result is obtained. What does all this mean? Let's see what the "stack" for our query looks like:
stack[0] : return get-folder -name "dev" -location (folder result of stack[1])
stack[1] : return get-folder -name "linux" -location (folder result of stack[2])
stack[2] : return get-folder -name "dotcom" -location (folder result of stack[3])
stack[3] : return get-folder -norecursion (this gets us the root folder for the Datacenter)
Since it's LIFO then stack[3] will be evaluated and the result will be used by stack[2]. Then stack[2] will be evaluated and the result will be used by stack[1]. Then stack[1] will be evaluated and the result will be used by stack[0]. Finally stack[0] will be evaluated and that will be nested folder we are trying to find. Simple, right? Here's the scripting (notice there are no loops):
# get folder location based on sub-folders
function getVcFolderByPath {
param([string]$folderString)
if ($folderString -eq "") {
return (get-folder -noRecursion)
} else {
$folderArr = $folderString -split "\\"
$folderName = $folderArr[-1]
$updatedFolderString = [string]::join("\", $folderArr[0 .. ($folderArr.length-2)])
return (get-folder -name $folderName -location (getVcFolderByPath $updatedFolderString))
}
}
What is this doing you ask? First is our base-case:
if ($folderString -eq "") {
return (get-folder -noRecursion)
When we can't go back any further in the folderString then we must be at the root so return the root folder to be used by the previous operation in the "stack". If we aren't at the last item then we need to split $folderString on the "\"
$folderArr = $folderString -split "\\"
Then, we can get the last folder name in the current folderString
$folderName = $folderArr[-1]
Then, we create an updatedFolderString with the last folder name removed
$updatedFolderString = [string]::join("\", $folderArr[0 .. ($folderArr.length-2)])
Finally, we call ourselves again, this time sending updateFolderString
return (get-folder -name $folderName -location (getVcFolderByPath $updatedFolderString))
This will continue until updateFolderString is empty and we are at the base-case. Looking back at the "stack" representation from above, here's what we have:
stack[0] : return get-folder -name "dev" -location (getVcFolderByPath "\dotcom\linux")
stack[1] : return get-folder -name "linux" -location (getVcFolderByPath "\dotcom")
stack[2] : reutrn get-folder -name "dotcom" -location (getVcFolderByPath "")
stack[3] : return get-folder -norecursion
Like I said, simple! Here's what it looks like when we call the function.
This does assume there is only one Datacenter. As with all scripts, your mileage may vary depending on your environment. Comments/Suggestions are welcome. Happy Querying!
UPDATED!
Since seems like using a sledgehammer to hang a picture so I'd thought I'd include the easy for-loop method as well:
# get folder location based on sub-folders
function getVcFolderByPath {
param([string]$folderString)
$folder = get-folder -norecursion
$folderArr = $folderString -split "\\"
for ($i=1 ; $i -lt $folderArr.length ; $i++) {
$folder = get-folder -name $folderArr[$i] -location $folder
}
return $folder
}
And then call it just like before.
The information is the same.
UPDATED!
Since seems like using a sledgehammer to hang a picture so I'd thought I'd include the easy for-loop method as well:
# get folder location based on sub-folders
function getVcFolderByPath {
param([string]$folderString)
$folder = get-folder -norecursion
$folderArr = $folderString -split "\\"
for ($i=1 ; $i -lt $folderArr.length ; $i++) {
$folder = get-folder -name $folderArr[$i] -location $folder
}
return $folder
}
And then call it just like before.
The information is the same.
Hello, an amazing Information dude. Thanks for sharing this nice information with us. BPMN Notation
ReplyDelete