Select folder names with a common word - powershell

I am trying to get the profile folders of the user User1 but don't want User10 folders from a directory.
Here is what I have tried:
Get-ChildItem -Path "$Profilesroot" -Recurse -Filter "*User1*"
and the out put shows User1, User1.v1, User10, User10.v1 folders
Same out put for the for the following:
Get-ChildItem "$profilesroot" -Recurse | Select-String -Pattern "User1"
Get-ChildItem "$profilesroot" -Recurse | Where {$_.Name -match 'User1'}
Get-ChildItem "$profilesroot" -Recurse | Where {$_.Name -like '*User1*'}
If I try the following, I am getting the required output but I feel there is a better option:
Get-ChildItem $profiles -Recurse | Where {$_.Name -like 'User1'}
Get-ChildItem $profiles -Recurse | Where {$_.Name -like 'User1.*'}
Apologies if the ask was not clear.

If you use Get-ChildItem's -Include parameter instead of -Filter, you can pass multiple PowerShell wildcard expressions.
Note:
Use of -Include is generally slower than use of -Filter, because the latter filters at the source, whereas -Include collects all items and then filters. Conversely, the -Include uses PowerShell's wildcard expressions, and not the more limited ones supported by -Filter, which are additionally saddled with legacy quirks.
However, a single Get-ChildItem call still outperforms a Get-ChildItem -Recurse ... | Where-Object { ... } pipeline.
That is - generally speaking - use something like
Get-ChildItem -Recurse ... | Where-Object { $_.Name -match '^User1\b' }, as suggested by Mathias R. Jessen, only if you truly need the enhanced matching flexibility that -match, the regular expression-based string-matching operator, provides.
If you're really looking for matching directories at all levels of the $ProfilesRoot subtree (-Recurse), use the following:
Get-ChildItem $ProfilesRoot -Recurse -Directory -Include User1, User1.*
If, by contrast, you're just looking for matching directories located directly in $ProfilesRoot:
Get-ChildItem $ProfilesRoot\* -Directory -Include User1, User1.*
Note the addition of \* to the (positionally implied) -Path argument, because in the absence of -Recurse -Include is unexpectedly only applied to the input path itself, not its children - see this answer for a detailed discussion of this counterintuitive behavior.

To get user's profile path, you should rely on operating system, but not on path concatenation.
$path = #(Get-WmiObject -Class 'Win32_UserProfile' |
Where-Object { $_.Special -eq $false } |
Where-Object { -not [string]::IsNullOrWhiteSpace($_.LocalPath) } |
Where-Object { $_.LocalPath.EndsWith("\User1") } |
Select-Object -ExpandProperty 'LocalPath' )[0]
More accurate way, because
sometimes profile path not matches username
sometimes profile path matches other user's name
sometimes profile path is not in profileroot
sometimes user have more than one profile and some of this profiles are broken and not used by user.
$path = #(Get-WmiObject -Class 'Win32_UserProfile' |
Where-Object { $_.Special -eq $false } |
Where-Object { -not [string]::IsNullOrWhiteSpace($_.LocalPath) } |
Where-Object { $_.SID -eq ([System.Security.Principal.NTAccount]('User1')).Translate([System.Security.Principal.SecurityIdentifier]).ToString() } |
Select-Object -ExpandProperty 'LocalPath' )[0]
Even more accurate way using SID matching and WMI filtering
$userSid = ([System.Security.Principal.NTAccount]('User1')).Translate([System.Security.Principal.SecurityIdentifier]).ToString()
$path = #(Get-WmiObject -Class 'Win32_UserProfile' -Filter "(Special = FALSE) AND (LocalPath LIKE '%\\%') AND (SID = '$($userSid)')" -Property #('LocalPath'))[0].LocalPath

Related

Powershell Get-ChildItem Exclude Default Windows Folders

I want to search for files with .2fa extension on remote computers. I can find the files I want, but it takes a long time to get to the second computer because it scans all windows files.
I tried the -exclude and where arguments but they do not work.
Could you please help me? Thanks.
$ServerList = Import-Csv 'C:\PC.CSV'
$result = foreach ($pc in $ServerList.barkod) {
$exclude = '*ProgramData*','*Program Files*','*Program Files (x86)*','*Windows*'.'*winupdate*'
$sourcepath = 'c$'
Get-ChildItem -Path \\$pc\$sourcepath -Recurse | Where-Object { $_.Name -like "*.2fa" } |
where {$_.name -notin $Exclude}
}
$result
I tried
-Exclude $exclude
-where {$_.name -notin $Exclude}
-exclude doesn't work with subdirectories or -filter:
Get-ChildItem -Path \\$pc\$sourcepath\ -exclude $exclude |
get-childitem -recurse -filter *.2fa
Since you are looking for files with a certain extension, use the -Filter parameter.
This will be the fastest option to search for only .2fa files, disregarding all others. (Filter works on the Name property)
If you want to search the C: drive, you are bound to hit Access Denied exceptions and because to exclude a list of foldernames using post-process with a Where-Object clause,
Get-ChildItem will try and search in these folders you need to apend -ErrorAction SilentlyContinue to the command
$exclude = 'ProgramData','Program Files','Program Files (x86)','Windows'.'winupdate'
# create a regex string you can use with the `-notmatch` operator
# each item will be Regex Escaped and joined together with the OR symbol '|'
$excludeThese = ($exclude | ForEach-Object { [Regex]::Escape($_) }) -join '|'
$ServerList = (Import-Csv 'C:\PC.CSV').barkod
$sourcepath = 'c$'
$result = foreach ($pc in $ServerList) {
Get-ChildItem -Path "\\$pc\$sourcepath" -Filter '*.2fa' -File -Recurse -ErrorAction SilentlyContinue |
Where-Object {$_.DirectoryName -notmatch $excludeThese}
}
$result

User Directory Identification

I need to create a script to iterate through a list of user samaccountnames and identify network directories matching their samaccountname on the network. It doesn't seem to work though. Users home folders on the network use their samaccountname in the path. Here is what I have so far:
$userList = "C:\Users\sfp01\My
Documents\Data_Deletion_Testing\User_SamAccountName.csv"
$userDirectory = foreach ($user in $userList)
{
Get-ChildItem -Path "\\ceoii\" -Directory -Recurse | ? {}
}
Export-Csv -Path "C:\Users\sfp01\My
Documents\Data_Deletion_Testing\User_Directory.csv"
First, you need to import the csv as your first line just saves the location of the file in the variable rather than the contents of the file.
Second, you didn't provide the column name of the csv file that contains the user's saMAccountName. You'll need to set up your Where-Object to filter using that information. I am using -match on saMAccountName, but edit this to reflect your requirements.
And I don't think that \\servername\ isn't a valid share name, it should be a share like \\servername\share\ If you want to get all the shares from a server you could enumerate them with something like this invoke-command -ComputerName ceoii -ScriptBlock {Get-SmbShare}
You also probably want to only pull the list of folders once and then filter for each user.
Lastly, you save the information in $userDirectory so you'll want to pipe that information into your export-csv.
$userList = Import-CSV 'C:\Users\sfp01\My Documents\Data_Deletion_Testing\User_SamAccountName.csv'
$folders = Get-ChildItem -Path "\\ceoii\sharename" -Directory -Recurse
$userDirectory = foreach ($user in $userList) {
$folders | Where-Object {$_.name -match $user.saMAcountName}
}
$userDirectory | Export-Csv -Path 'C:\Users\sfp01\My Documents\Data_Deletion_Testing\User_Directory.csv'
More efficient than that would be to use -in or -contains if you know that the folder names exactly match.
$folders = Get-ChildItem -Path "\\ceoii\sharename" -Directory -Recurse
$userList = Import-CSV 'C:\Users\sfp01\My Documents\Data_Deletion_Testing\User_SamAccountName.csv' |
Select-Object -ExpandProperty saMAccountName
$folders |
Where-Object {$_.name -in $userList} |
Export-Csv -Path 'C:\Users\sfp01\My Documents\Data_Deletion_Testing\User_Directory.csv'

find and recurse

I have a folder structure d:\domains\<domain>\folder1\folder2\folderx
There are maybe 20 <domain> folders, with differing levels of folders below them.
I want to search all folders for .php files, and just print the unique <domain> folders where they exit.
So for example, if there are files found in
d:\domains\domain1.com\test\test
d:\domains\domain2.com\test\test
d:\domains\domain2.com\test\help
I just want domain1.com,domain2.com to be printed. It needs to work in PowerShell v2.
I have the following, but it only prints the first domain?
Get-ChildItem -Path #(Get-ChildItem -Path D:\domains | Where-Object {$_.PSIsContainer})[1].FullName -Recurse *.php |
Select-Object -ExpandProperty FullName
Enumerate the domain folders, then filter for those of them that contain .php files.
Get-ChildItem 'D:\domains' | Where-Object {
$_.PSIsContainer -and
(Get-ChildItem $_.FullName -Filter '*.php' -Recurse)
}
If you have PowerShell v3 or newer you can use the -Directory switch instead of checking for $_.PSIsContainer:
Get-ChildItem 'D:\domains' -Directory | Where-Object {
Get-ChildItem $_.FullName -Filter '*.php' -Recurse
}
Select the Name property from the output if you want just the folder/domain names:
... | Select-Object -Expand Name

gci and gci -recurse have different kind of outputs

I'm trying to make a filesystem inventory.
This works, it gives me the ower and ACL of each entry
Get-ChildItem \\Server\Share\* | Select-Object #{n='Path';e={ (Get-Item $_.PSPath).FullName }}, PSIsContainer, #{n='Owner';e={ (Get-Acl $_).Owner}}, #{n='Accesstostring';e={ (Get-Acl $_).Accesstostring}}
But using -Recurse gives me empty Owner and Accesstostring
Get-ChildItem \\Server\Share\ -Recurse | Select-Object #{n='Path';e={ (Get-Item $_.PSPath).FullName }}, PSIsContainer, #{n='Owner';e={ (Get-Acl $_).Owner}}, #{n='Accesstostring';e={ (Get-Acl $_).Accesstostring}}
Why does gci is sending something different alon the pipe ?
How can i fix this ?
(I don't want to make an array because that would not fit into memory)
They are different because one array contains a list of files, but in recurse it is an array of directory objects and each of the directory object contains a list of files.
The code below will do what you wanted. Please note that path needs to be in quotes if it contains spaces.
Get-ChildItem \\Server\Share\ -Recurse | Select-Object #{n='Path';e={ $_.FullName }}, PSIsContainer, #{n='Owner';e={ (Get-Acl $_.FullName).Owner}}, #{n='Accesstostring';e={ (Get-Acl $_.FullName).Accesstostring}}
Expanding on #Edjs-perkums answer, this calls Get-Acl once and expands two of its properties in a second Select-Object in the pipe. (Also reformatted into multiple lines for clarity, but it's a single pipeline.)
Get-ChildItem \\Server\Share\ -Recurse `
| Select-Object #{n='Path';e={ $_.FullName }},
#{n='ACL';e={ (Get-Acl $_.Fullname) }},
PSIsContainer `
| Select-Object Path, PSIsContainer,
#{n='Owner';e={ $_.ACL.Owner}},
#{n='Accesstostring';e={ $_.ACL.Accesstostring}}

PowerShell Filter on multiple parameters

I was wondering if is possible to specify multiple search filters as once. For example, I have this line of code that finds all files that have the "&" symbol.
get-childitem ./ -Recurse -Filter "*&*" |
? { $_.PSIsContainer } |
Select-Object -Property FullName
I'd like to extend this so that I can search one time and find files with other symbols like %,$,#, etc. I want to find files that have any of these symbols, not neccesarly files that have all of them so I assume there needs to be an OR somewhere. I tried the below code but it didn't seem to work for me:
get-childitem ./ -Recurse -Filter "*&*" -Filter "%" |
? { $_.PSIsContainer } |
Select-Object -Property FullName
You can use the -match operator and a regex for this:
Get-ChildItem -Recurse |
Where { !$_.PSIsContainer -and ($_.name -match '&|%|\$|#')} |
Select-Object -Property FullName
If you are on PowerShell v3 or higher you can simplify this a bit:
Get-ChildItem -Recurse -File |
Where Name -match '&|%|\$|#' |
Select-Object -Property FullName
If you have V3 or better, you can leverage the "globbing" wildcard feature:
get-childitem './*[&%$#]*' -Recurse | where {$_.PSIsContainer}
If you've got V4, you can dispense with the $_.PSIsContainer filter and use the -Directory switch:
get-childitem './*[&%$#]*' -Recurse -Directory