Overview - Where-Object - Complex Filters using ScriptBlocks
People are often not aware of the extensibility of the Where-Object
cmdlet and how you can leverage it’s power to create complex filters.
I’m talking about creating a scriptblock
containing the filtering logic and using it in your command
For Example: here, let’s create a scriptblock named $custom_gcifilter
;
- In it, I declare an array of pre-defined strings
- I have a boolean variable named
$valid
that will be returned by the scriptblock:$False
and the value is filtered out from theWhere
clause,$True
it is included - I declare a variable name (
$name=$_.Name
) . Note the$_
. This represent the current instance in the pipeline.
This line checks if the current instance has a name included in the $a
array and if the instance was created more than 10 minutes ago. if so, it sets the $valid
to $True
if(($($ts.Minutes) -gt 10) -and ($a.Contains($name))) { $valid=$True }
Complete filer script block
$custom_gcifilter = {
$a = @('microsoft.com','google.com','videotron.com','bell.ca','military.com','panasonic.com')
$valid=$False;$name=$_.Name;[DateTime]$dt=$_.CreationTime;[timespan]$ts = [datetime]::now - $dt;
if(($($ts.Minutes) -gt 10) -and ($a.Contains($name))) { $valid=$True }
$valid
}
Now, we use it like so:
Get-ChildItem -Path "." -Recurse | Where $custom_gcifilter
Advanced Example: Filter Directories based on Permissions
Let’s crank the level a bit. We need to filter directories based on the permissions we have on them. This is a bit trickier because there is multiple data sets to cross check.
- The user specifies the permissions to have on the directories listed, example
@('Modify','FullControl','Write')
- We need to get the current user group appartenance.
- For each paths, we get the FileSystemRights and IdentityReference
- We check if the FileSystemRights match the user-specified permissions
- We check if the IdentityReference is included in our current user group list
Here’s the code:
[string[]]$Permissions=@('Modify','FullControl','Write')
$aclfilter_perm = {
$ir=$_.IdentityReference;$fsr=$_.FileSystemRights.ToString();$hasright=$false;
ForEach($pxs in $Permissions){ if($fsr -match $pxs){$hasright=$True;}};
$GroupList.Contains($ir) -and $hasright
}
# Get a dir to check
$CurrentPath = (Get-Location).Path
(Get-Acl $CurrentPath).Access | Where $aclfilter_perm
Wrapping things up: check directory permissions
Here’s a pratical example: listing the PSModule
folders and checking the ones we have access to:
function Get-WritableModulePath{
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory=$false, ValueFromPipeline=$true, HelpMessage="Permissions")]
[string[]]$Permissions=@('Modify','FullControl','Write')
)
$VarModPath=[System.Environment]::GetEnvironmentVariable("PSModulePath")
$Paths=$VarModPath.Split(';')
Write-Verbose "Get-WriteableFolder from $Path and $PathsCount childs"
# 1 -> Retrieve my appartenance (My Groups)
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
$groups = $id.Groups | foreach-object {$_.Translate([Security.Principal.NTAccount])}
$GroupList = @() ; ForEach( $g in $groups){ $GroupList += $g ; }
Sleep -Milliseconds 500
$PathPermissions = [System.Collections.ArrayList]::new()
$aclfilter_perm = {
$ir=$_.IdentityReference;$fsr=$_.FileSystemRights.ToString();$hasright=$false;
ForEach($pxs in $Permissions){ if($fsr -match $pxs){$hasright=$True;}};
$GroupList.Contains($ir) -and $hasright
}
ForEach($p in $Paths){
if(-not(Test-Path -Path $p -PathType Container)) { continue; }
$perm = (Get-Acl $p).Access | Where $aclfilter_perm | Select `
@{n="Path";e={$p}},
@{n="IdentityReference";e={$ir}},
@{n="Permission";e={$_.FileSystemRights}}
if( $perm -ne $Null ){
$null = $PathPermissions.Add($perm)
}
}
return $PathPermissions
}
Note
In the command below
$perm = (Get-Acl $p).Access | Where $aclfilter_perm | Select `
@{n="Path";e={$p}},
@{n="IdentityReference";e={$ir}},
@{n="Permission";e={$_.FileSystemRights}}
Note that the Select
statement is using variables declared in the scriptblock
used in the Where-Object
clause. When you declare a variable in the pipeline, it can be used later on, in other clauses in the pipeline.
Get the code
Important Note Do You have Issues accessing the core repository? Don’t be shy and send me an EMAIL to guillaumeplante.qc@gmail.com and I will fix access for you