Powershell list files by particular owner - powershell

Beginner here.
How can I modify this script to list files owned by a particular user rather than listing every single file. For instance, I only want to see files owned by user john doe.
Set-StrictMode -Version Latest $files = Get-ChildItem foreach($file in $files) {$owner=(Get-Acl $file).Owner $file | Add-Member NoteProperty Owner $owner $file}
Your help is greatly appreciated.

Try something like this:
$files = Get-ChildItem | Select *,#{n='Owner';e={(Get-Acl $_).Owner}} |
Where {!$_.PSIsContainer -and ($_.Owner -eq 'Domain\name')}
On V3 you can simplify this to:
$files = Get-ChildItem -File | Select *,#{n='Owner';e={(Get-Acl $_).Owner}} |
Where {$_.Owner -eq 'Domain\name'}

The simplest I've found is:
Get-ChildItem | Get-Acl | Where-Object { $_.Owner -match 'Domain\username' }

This might be faster:
$Owner = 'user1'
$SID = (Get-ADUser $Owner).sid
Get-ChildItem |
where { (Get-Acl $_).sddl -like "O:$SID*" } |
select *,#{l='Owner';e={$Owner}}
The ACL is stored as an SDDL string. The SID of file owner will always be at the beginning of the SDDL string, prefixed with O:. NTFS has to resolve the SIDs to an owner name. It takes less time to do a string match for the SID than to do the lookup and then match the name. It's not much, and it won't make much difference just doing a file or 10, but it starts to add up when you start doing thousands of them.

Another variant, but using .NET's File.GetAccessControl https://learn.microsoft.com/en-us/dotnet/api/system.io.file.getaccesscontrol?view=netframework-4.8 instead of Get-Acl cmdlet.
Credit to Get File Owner/Author
Get-ChildItem <path> -File | Select-Object fullname, LastAccessTime, LastWriteTime, CreationTime, #{N='Owner';E={$_.GetAccessControl().Owner}}

Related

Powershell - Find all extensions on network shares

I'm new to PS scripting (really, I started today) and, for a project, I need to create a .txt file with all the extensions from all shared folders on the local machine (a Windows file server).
I think I'm on the right path with this :
get-childitem -Path C:\test -Recurse | select extension -unique > $PSScriptRoot\ExtensionList.txt
It's doing exactly what I want for a given path and all subfolders but now I need to apply this to all shared folders on the machine.
I was able to list all the shared folder's path with this command :
$Shares= #(Get-WmiObject Win32_Share |
Select Name,Path,Type |
Where-Object { $_.Type -match '0|2147483648' } |
Select -ExpandProperty Path |
Select -Unique)
Write-Host $Shares
Now I'm stuck, I suppose I need to use the foreach command but I can't find the way to make it work.
Can someone help me put this together ?
Thanks,
You can try Get-SMBShare cmdLet:
Get-SMBShare | Foreach {
Get-ChildItem "\\$($_.name)" | Select-Object Extension -Unique
}
You're probably looking for something similar to this:
$Shares = #( Get-CimInstance Win32_Share | Where-Object { $_.Type -match '0|2147483648' } | Select -Unique )
ForEach ( $Share In $Shares ) { Get-ChildItem -Path $Share.Path -File -Recurse -ErrorAction Ignore | Select -Unique -ExpandProperty Extension }
I'll leave you to split the lines to match your particular style and to output to a file, (I'd advise that you consider using Out-File instead of > for that).
Thank you guys for your help! I was able to figure it out.
The following script will gather all extensions on shared folders, sort them, eliminate duplicates and empty lines, add "*' before the extension and create a file list.txt with the result.
#get shares
$Shares = #( Get-CimInstance Win32_Share |
Where-Object { $_.Type -match '0|2147483648' } |
Select -Unique )
#list all extensions
ForEach ( $Share In $Shares ) { Get-ChildItem -Path $Share.Path -File -Recurse -ErrorAction Ignore | Select -Unique -ExpandProperty Extension | out-file C:\extensions\List1.txt -append }
#remove empty lines
#(gc C:\extensions\List1.txt) -match '\S' | out-file C:\extensions\List2.txt
#Add * before extention type
gc C:\extensions\List2.txt | %{"*$_"} | out-file C:\extensions\List3.txt
#Sort by name
gc C:\extensions\List3.txt | sort | get-unique > C:\extensions\List4.txt
#Remove duplicates
$hash = #{}
gc C:\extensions\List4.txt |
%{if($hash.$_ -eq $null) { $_ }; $hash.$_ = 1} > C:\extensions\List.txt
#Delete list1-4
Remove-Item C:\extensions\List1.txt, C:\extensions\List2.txt, C:\extensions\List3.txt, C:\extensions\List4.txt

Search a specified path for multiple .xml files within the same folder

I am seeking help creating a PowerShell script which will search a specified path for multiple .xml files within the same folder.
The script should provide the full path of the file(s) if found.
The script should also provide a date.
Here's my code:
$Dir = Get-ChildItem C:\windows\system32 -Recurse
#$Dir | Get-Member
$List = $Dir | where {$_.Extension -eq ".xml"}
$List | Format-Table Name
$folder = "C:\Windows\System32"
$results = Get-ChildItem -Path $folder -File -Include "*.xml" | Select Name, FullName, LastWriteTime
This will return all xml files only and display the file name, full path to the file and last time it was written to. The "-File" switch is only available in Powershell 4 and up. So if doing it off a Windows 7 or Windows 2008 R2 Server, you will have to make sure you updated your WMF to 4 or higher. Without file the second like will look like.
#Powershell 2.0
$results = Get-ChildItem -Path $folder -Include "*.xml" | Where {$_.PSIsContainer -eq $false} | Select Name, FullName, LastWriteTime
I like the Select method mentioned above for the simpler syntax, but if for some reason you just want the file names with their absolute path and without the column header that comes with piping to Select (perhaps because it will be used as input to another script, or piped to another function) you could do the following:
$folder = 'C:\path\to\folder'
Get-ChildItem -Path $folder -Filter *.xml -File -Name | ForEach-Object {
[System.IO.Path]::GetFullPath($_)
}
I'm not sure if Select lets you leave out the header.
You could also take a look at this answer to give you some more ideas or things to try if you need the results sorted, or the file extension removed:
https://stackoverflow.com/a/31049571/10193624
I was able to make a few changes exporting the results to a .txt file, but though it provides the results I only want to isolate the same .xml files.
$ParentFolder = "C:\software"
$FolderHash = #{}
$Subfolders = Get-ChildItem -Path $ParentFolder
foreach ($EventFolder in $Subfolders) {
$XMLFiles = Get-ChildItem -Path $EventFolder.fullname -Filter *.xml*
if ($XMLFiles.Count -gt 1) {
$FolderHash += #{$EventFolder.FullName = $EventFolder.LastWriteTime}
}
}
$FolderHash
Judging from your self-answer you want a list of directories that contain more than one XML file without recursively searching those directories. In that case your code could be simplified to something like this:
Get-ChildItem "${ParentFolder}\*\*.xml" |
Group-Object Directory |
Where-Object { $_.Count -ge 2 } |
Select-Object Name, #{n='LastWriteTime';e={(Get-Item $_.Name).LastWriteTime}}

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'

Powershell get-acl from childitems that not equals foldername

At work we have a folder with lots of subfolders named like "MeyerS". (Lastname and the first letter of surname)
When I take a look at Get-ChildItem $path | Get-Acl the username equals the subfolder-name. But there is also a "SCHUELER\" in front of "MeyerS". This is what the output looks like a.e.: SCHUELER\MeyerS Allow Write, ReadAndExecute, Synchronize
Some subfolders don't have this kind of username. Now I want to output all these subfolders without this username- "combination".
With my first codesnippet I get all of them, but I really just want these specific ones.
I checked some similar questions, and found something. I modified it, but it shows all subfolders just without SCHUELER\MeyerS. I think I just need a small push to the right way.
The code so far:
$path = "R:\HOME"
$folders = Get-ChildItem $path | where {$_.psiscontainer}
foreach ($folder in $folders){
$domain = "domname"
$aclname = "ACLname"
$aclfullname ="$domain\$aclname"
Get-Acl | select -ExpandProperty Access | where {$_.identityreference -notcontains $aclfullname}
Write-Host $folder.FullName}
Short note: I tried a lot of variations with -noteq or -notlike.
What do I have to change?
If there is already an answer I really didn't know.
Sometimes it's really hard to enunciate yourself in another language. I hope you get my point.
Thanks.
$path = "R:\HOME"
$folders = Get-ChildItem $path | where {$_.psiscontainer}
foreach ($folder in $folders)
{
$domain = "domname"
$aclname = "ACLname"
$aclfullname ="$domain\$aclname"
$FoldersWithAclFullName = $null
$FoldersWithAclFullName = Get-Acl -Path $Folder `
| Select-Object -ExpandProperty Access `
| Where-Object -Property IdentityReference -ne -Value $aclfullname
if ( -not $FoldersWithAclFullName )
{
Write-Host $folder.FullName
}
}

Powershell output

Having trouble getting the output I want from some powershell commands. I'm creating a powershell script to help clean up home directories. I need to get the permissions of the directory and make sure that the name of the directoy and the user who has access match.
I'm using the Get-Acl function and it has alot of extra data. In theory the file permissions on these directories should have Administrators as the owner, the user should be the only person listed under Access.
PS C:\> Get-Acl "\\fs1\home\e55555"
Directory: \\fs1\home
Path Owner Access
---- ----- ------
e55555 BUILTIN\Administrators DOM\e55555 Allow ...
I would like to filter out everything except what is under access. I tried piping | select Access but it doesn't give me the same output.
I know I'll have extra information besides the UserID so I figured I could write to a file and try to "grep" what I needed. Through some googling and experimentation I got some output I felt would be easy to parse, here is the command and output:
PS C:\> $test = Get-Acl \\fs1\home\\e55555 | Select-Object -ExpandProperty Access
| select IdentityReference
IdentityReference
-----------------
DOM\e55555
NT AUTHORITY\SYSTEM
BUILTIN\Administrators
NT AUTHORITY\Authenticated Users
Tried to use regex to find the line I wanted, none of the things I tried gave me any output. I tried different variations of the commands below and also tried parsing a file instead of a variable:
echo $test | Select-String -pattern "^DOM"
[regex]::matches($test,"^DOM")
So how can I trim down my output on my get-acl command? And how can I "grep" for any lines starting with DOM without extra data?
This should give you the access-objects for all users in your domain
$path = "\\fs1\home\\e55555"
(Get-Acl $path).Access | where { $_.IdentityReference -like "DOM*"}
If you want to check that user is in there, you could use:
$path = "\\fs1\home\\e55555"
$username = $path | Split-Path -Leaf
(Get-Acl $path).Access | where { $_.IdentityReference -like "DOM\$username"}
I didn't extract the Identityreference property since you need the whole access object if you want to check the permissions. If you save the Get-Acl outputs to a variable (ex. $access = Get-Acl ......), you can check that the user had a access rule by using if($access) { do something }
EDIT: Just as an idea. If you only want the folders where a user with the same name as the folder doesn't have an access rule(without checking what kind of rights the user has), you could try:
$acls = Get-ChildItem "\\fs1\home\" | Get-Acl
foreach ($acl in $acls) {
$users = $acl.Access | select -ExpandProperty IdentityReference
$username = $acl.PSChildName
if ($users -notcontains "DOM\$username") { $username }
}
This should output an array of foldernames(ex. "e55555") where something IS wrong(ex. user "e55555" doesn't have any access to the folder "e55555").
I think you think-string all the time. Try to see objects instead. And to filter - use where, not select-string. E.g.:
$HomeDrive = '\\fs1\home\'
$User = 'e55555'
(Get-Acl $HomeDrive$User).Access |
where { $_.IdentityReference -match $user }
That should get you started...? :)
Try adding the -Expand to IdentityReference too. To build on what you were doing:
Get-Acl "\\fs1\home\\e55555" | Select-Object -ExpandProperty Access |
select -expand IdentityReference | ?{ $_.StartsWith("DOM") }
To make it simpler:
(Get-Acl "\\fs1\home\\e55555").Access | Select -Expand IdentityReference | ?{ $_.StartsWith("DOM") }