Getting Permissions From Remote Share (PowerShell) - windows

I am writing a script to get permissions and some other info on shares throughout the a network and I am having trouble getting the shares permissions. I read online that one can use "GetAccessMask" but I thought it was just for the current user.
#loop for each computer in computers file
ForEach ($computer in $allComputers)
{
Write-Host "Checking - $computer"
If($computer -ne '')
{
#check if online, this uses WMI so if you don't have access to the machine it will show as offline
If(Test-Connection -Computername $computer -ErrorAction SilentlyContinue)
{
$shares = Get-WmiObject -Class Win32_share -ComputerName $computer -Credential $uCredentials
ForEach($share in $shares)
{
$sName = $share.Name
$sPath = $share.Path
$sDesc = $share.Description
$objShare = New-Object -TypeName PSObject
$objShare = Add-Member -PassThru -InputObject $objShare -NotePropertyName Server -NotePropertyValue $computer
$objShare = Add-Member -PassThru -InputObject $objShare -NotePropertyName Online -NotePropertyValue $True
$objShare = Add-Member -PassThru -InputObject $objShare -NotePropertyName Share -NotePropertyValue $sName
$objShare = Add-Member -PassThru -InputObject $objShare -NotePropertyName Path -NotePropertyValue $sPath
$objShare = Add-Member -PassThru -InputObject $objShare -NotePropertyName Description -NotePropertyValue $sDesc
$objShare | Export-CSV -Path $fOutfile -Append -NoClobber -NoTypeInformation
}
}
}
}
Above is a snippet of my script (as a whole it reads server list from a file, lists the share name,path, description) and I am wondering if anyone knows how I could get permissions on a given share for all users/groups with rights to the share.
Thanks in advance!

After you get the Shares from win32_share Class, Get the Share Permissions from the Win32_LogicalShareSecuritySetting Class, like this:
$Shares = Get-WmiObject Win32_Share -ComputerName $computer -Credential $uCredentials |
? {$_.Type -eq 0} ## 0 for Disk Drive shares only see: https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-share
$Array = #()
$ACL = #()
Foreach ($Share in $Shares)
{
$ShareName = $share.name
$SharePermissions = Get-WmiObject Win32_LogicalShareSecuritySetting -Filter "name='$ShareName'" -ComputerName $computer
Foreach ($SP in $SharePermissions)
{
$SecDesc = $SP.GetSecurityDescriptor().Descriptor
foreach($ace in $SecDesc.DACL){
$UserName = $ace.Trustee.Name
If ($ace.Trustee.Domain -ne $Null) {$UserName = "$($ace.Trustee.Domain)\$UserName"}
If ($ace.Trustee.Name -eq $Null) {$UserName = $ace.Trustee.SIDString }
$ACL += New-Object Security.AccessControl.FileSystemAccessRule($UserName, $ace.AccessMask, $ace.AceType)
}
}
$Results = "" | Select Server,Name,Status,Path,Description, ID, Rights
$Results.Server = $Share.__Server
$Results.Name = $Share.Name
$Results.Status = $Share.Status
$Results.Path = $Share.Path
$Results.Description = $Share.Description
$Results.ID = $ACL | % {$_.IdentityReference}
$Results.Rights = $ACL | % {$_.FileSystemRights}
$Results = $Results | ? {$_.id -ne $null}
$Array += $Results
}
$Array

Related

How to get the share folder level permission using powershell

#Cred= Get-Credential
$FolderPath = dir -Directory -Path "\\abc\dc\da" -Recurse -Force | where {$_.psiscontainer -eq $true}
$Report = #()
Foreach ($Folder in $FolderPath) {
$Acl = Get-Acl -Path $Folder.FullName
# $Name= Get-ChildItem $Folder -Recurse | where {!$_.PSIsContainer} |select-object fullname
foreach ($Access in $acl.Access)
{
$Properties = [ordered]#{'FolderName'=$Folder.FullName;'AD
Group or User'=$Access.IdentityReference;'Permissions'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
$Report += New-Object -TypeName PSObject -Property $Properties
}
}
$Report | Export-Csv -path "C:\Output\Test_16-06-2021.csv"
In the above script, I'm able to get all my folder structure with permission but I want to do with a custom parameter like if I want to only folder level 3 it should get me the output as below
\\abc\a\b\c
\\abc\a\c\d
not like
\\abc\a\b\c\d\text.txt
\\abc\a\c\d\e\f\g\demo.pdf
If you're using PowerShell 5.0, you can use the -Recurse and -Depth parameters combined:
[string]$rootFolder = Read-Host -Prompt "Enter root folder path (no trailing '\')"
[int]$recursionDepth = Read-Host -Prompt "Enter recursion depth"
[string]$outputCsv = Read-Host -Prompt "Enter output .csv file (full path)"
$folders = Get-ChildItem -Directory -Path $rootFolder -Recurse -Depth $recursionDepth -Force | Where-Object { $_.PSIsContainer -eq $true }
[array]$report = #()
foreach ($folder in $folders) {
$acl = Get-Acl -Path $folder.FullName
foreach ($access in $acl.access) {
[hashtable]$properties = [ordered]#{
'FolderName' = $folder.FullName;
'AD Group or User' = $access.IdentityReference;
'Permissions' = $access.FileSystemRights;
'Inherited' = $access.IsInherited
}
$report += New-Object -TypeName PSObject -Property $properties
}
}
Write-Host $report
$report | Export-Csv -Path $outputCsv
If that isn't an option, you can try the following:
[string]$rootFolder = Read-Host -Prompt "Enter root folder path (no trailing '\')"
[int]$recursionDepth = Read-Host -Prompt "Enter recursion depth"
[string]$outputCsv = Read-Host -Prompt "Enter output .csv file (full path)"
[string]$recursionStr = if ($recursionDepth -eq 0) { "\*" } else { ("\*" * ($recursionDepth + 1)) }
$folders = Get-ChildItem -Directory -Path "$rootFolder$recursionStr" -Force | Where-Object { $_.PSIsContainer -eq $true }
[array]$report = #()
foreach ($folder in $folders) {
$acl = Get-Acl -Path $folder.FullName
foreach ($access in $acl.access) {
[hashtable]$properties = [ordered]#{
'FolderName' = $folder.FullName;
'AD Group or User' = $access.IdentityReference;
'Permissions' = $access.FileSystemRights;
'Inherited' = $access.IsInherited
}
$report += New-Object -TypeName PSObject -Property $properties
}
}
Write-Host $report
$report | Export-Csv -Path $outputCsv
See Limit Get-ChildItem recursion depth

ec2 user-data skips block of Powershell

I have this script baked into an AWS-AMI, running the script logged into an ec2-instance works, but when calling from userdata the Join AD with newname part gets skipped.
# Get Credentials from SSM
echo $new_name
$domain = "xxxx"
$username = (Get-SSMParameterValue -Name ad_domain_user).Parameters[0].Value
$password = (Get-SSMParameterValue -Name ad_domain_password -WithDecryption $True).Parameters[0].Value | ConvertTo-SecureString -asPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username,$password)
# Get VPC Tags for OU Name
$vpc_id=(Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/network/interfaces/macs/$mac/vpc-id)
$env_name=(aws ec2 describe-vpcs --vpc-ids $vpc_id --query 'Vpcs[*].[Tags[?Key==`Name`] | [0].Value]' --output text)
echo "Attempting to join AD for env_name:$env_name" | Out-File "C:\Program Files\Amazon\Ec2ConfigService\Logs\pslog.txt" -Append
# Join AD with newname
Try {
if ("$env_name" -match "xxxx*") {
Add-Computer -DomainName $domain -ComputerName $env:computername -newname $new_name -Credential $credential -Force -Restart -ErrorAction 'Stop'
} elseif ("$env_name" -match "xxxx-xxxx-*") {
$oupath = "OU=Member Servers,OU=xxxx-xxxx,OU=xxxx,DC=aws,DC=ABC,DC=ORG"
Add-Computer -DomainName $domain -ComputerName $env:computername -newname $new_name -Credential $credential -Force -Restart -ErrorAction 'Stop' -OUpath$oupath
} elseif ("$env_name" -match "xxxx-xxxx-*") {
$oupath = "OU=Member Servers,OU=xxxx-xxxx,OU=xxxx,DC=aws,DC=ABC,DC=ORG"
Add-Computer -DomainName $domain -ComputerName $env:computername -newname $new_name -Credential $credential -Force -Restart -ErrorAction 'Stop' -OUpath $oupath
}
} Catch {
echo $_.Exception | Out-File "C:\Program Files\Amazon\Ec2ConfigService\Logs\Error-JoinDomain.txt" -Append
}
## If Error File Exists try again
Try{
If (Test-Path "C:\Program Files\Amazon\Ec2ConfigService\Logs\Error-JoinDomain.txt" -PathType Leaf) {
if ("$env_name" -match "xxxx*") {
Add-Computer -DomainName $domain -ComputerName $env:computername -newname $new_name -Credential $credential -Force -Restart -ErrorAction 'Stop'
} else {
Add-Computer -DomainName $domain -ComputerName $env:computername -newname $new_name -Credential $credential -Force -Restart -ErrorAction 'Stop' -OUpath $oupath
}
}
} Catch {
echo $_.Exception | Out-File "C:\Program Files\Amazon\Ec2ConfigService\Logs\Error-JoinDomain.txt" -Append
echo $_.Exception | Out-File "C:\Program Files\Amazon\Ec2ConfigService\Logs\pslog.txt" -Append
}

Error with code "Missing = operator after key in hash literal, hash literal was incomplete"

I have a list of users in a CSV File that I want to find out if/when they last logged in. I can get this info for an individual account but I need to write this to a file for several accounts.
The error I'm getting:
At line:5 char:7
import-module activedirectory
Missing = operator after key in hash literal
hash literal was incomplete
My Code:
$resultList = #()
Import-Csv C:\Users\admin\Desktop\SamAccountName.csv -header("SamAccountName") | Foreach-Object{
$user = ([adsisearcher]"(samAccountName=$($_.SamAccountName))").FindOne()
$resultList += New-Object -TypeName PSObject -Property #{
SamAccountName = $_.SamAccountName
Import-Module ActiveDirectory
function Get-ADUserLastLogon([string]$_.userName)
{
$dcs = Get-ADDomainController -Filter {Name -like "*"}
$time = 0
foreach($dc in $dcs)
{
$hostname = $dc.HostName
$user = Get-ADUser $userName | Get-ADObject -Properties lastLogon
if($user.LastLogon -gt $time)
{
$time = $user.LastLogon
}
}
$dt = [DateTime]::FromFileTime($time)
Write-Host $username "last logged on at:" $dt }
Get-ADUserLastLogon -UserName $user
}
}
}
$resultList | export-csv -Path c:\users\admin\desktop\SamAccountName_results.csv -NoTypeInfo
Instead of this:
$user = ([adsisearcher]"(samAccountName=$($_.SamAccountName))").FindOne()
$resultList += New-Object -TypeName PSObject -Property #{
SamAccountName = $_.SamAccountName
Please do this:
$user = ([adsisearcher]"(samAccountName=$($_.SamAccountName))").FindOne()
$resultList += New-Object -TypeName PSObject -Property #{
SamAccountName = $_.SamAccountName
}

Foreach Nested loops issue in powershell

What I need to do is to compare the Licence attribute associated with each Username from $O365Users with Enabled attribute using the matching Employee ID in $userID (if it exists). With the standard nested ForEach (above) We use this script to help manage our local Active Directory and MSOL (Microsoft Online – Office 365) objects. My question is : I have got an issue related to the foreach loop so same object returns multiple (forever) I want to do it line-by-line for each user
Import-Module ActiveDirectory
Import-Module MSOnline
$password = ConvertTo-SecureString 'PASSWORD' -AsPlainText -Force
$LiveCred = New-Object System.Management.Automation.PSCredential ("username#domain.com", $password)
New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection
Connect-MsolService -Credential $Livecred
$O365Users = Get-MsolUser -All
ForEach ($O365User in $O365Users)
{
$userID = Import-CSV "c:\Export\list.csv"
$ADuser = Get-ADUser -Filter "EmployeeID -eq $($userID.EmployeeID)" -Properties whenCreated, Enabled, SAMAccountName
If (($ADUser.Enabled -eq $True) -and ($O365User.isLicensed = $true))
{
Get-MsolUSer -UserPrincipalName $ADuser.UserPrincipalName
Set-MsolUserLicense -UserPrincipalName $ADuser.UserPrincipalName -RemoveLicenses "company:ENTERPRISEPACK"
}
}
CSV file :
EmployeeID
52576
1234
8599
Here you go this should work
$userID = Import-Csv "c:\export\list.csv"
foreach ($user in $userID){
$ADuser = Get-ADUser -Filter "EmployeeId -eq $($user.EmployeeID)" -Properties whenCreated, Enabled, SAMAccountName
$O365User = Get-MsolUser -UserPrincipalName $ADuser.UserPrincipalName
if(($ADuser.Enabled -eq $true) -and ($O365User.isLicensed -eq $true)){
Get-MsolUSer -UserPrincipalName $ADuser.UserPrincipalName
Set-MsolUserLicense -UserPrincipalName $ADuser.UserPrincipalName -RemoveLicenses "company:ENTERPRISEPACK"
}
}
Regarding the follow-up question on performance (just what i think might increase performance, no warranty and not tested):
$userID = Import-Csv "c:\export\list.csv"
$adusers = Get-ADUser -Filter * -properties EmployeeID,whenCreated,Enabled,SAMAccountname
$msolusers = Get-MsolUser -All
foreach ($user in $userID){
$ADuser = $adusers | where {$_.EmployeeID -eq $user.EmployeeID}
$O365User = $msolusers | where {$_.UserPrincipalName -eq $ADuser.UserPrincipalName}
if(($ADuser.Enabled -eq $true) -and ($O365User.isLicensed -eq $true)){
Set-MsolUserLicense -UserPrincipalName $ADuser.UserPrincipalName -RemoveLicenses "company:ENTERPRISEPACK"
}
}
Depending on how many of the AD / MSOL users there are and you have to match this might de- or increase the execution time, you will have to test since i cant.
I also removed the get-msoluser in your if statement since it´s only function is generating (unnecessary?) output. If there are any problems with my "improvements" let me know and we can see what we can do ;)
Please try:
Import-Module ActiveDirectory
Import-Module MSOnline
$password = ConvertTo-SecureString 'PASSWORD' -AsPlainText -Force
$LiveCred = New-Object System.Management.Automation.PSCredential ("username#domain.com", $password)
New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection
Connect-MsolService -Credential $Livecred
$userIDs = Import-CSV "c:\Export\list.csv"
$O365Users = Get-MsolUser -All
ForEach ($O365User in $O365Users)
{
foreach ($userID in $userIDs)
{
$ADuser = Get-ADUser -Filter "EmployeeID -eq $($userID.EmployeeID)" -Properties whenCreated, Enabled, SAMAccountName,ObjectGUID
$valuetoconvert=$ADuser.ObjectGUID
$guid = [GUID]$valuetoconvert
$bytearray = $guid.tobytearray()
$ImmutableID = [system.convert]::ToBase64String($bytearray)
If (($ADUser.Enabled -eq $True) -and ($O365User.isLicensed = $true) -and ($ImmutableID -eq $O365User.ImmutableID ) )
{
Get-MsolUSer -UserPrincipalName $ADuser.UserPrincipalName
Set-MsolUserLicense -UserPrincipalName $ADuser.UserPrincipalName -RemoveLicenses "company:ENTERPRISEPACK"
}
}
}

Get the domain name of the user of ADSI object?

In the following script, it will print all the users of the groups. However, the domain name is missing (Some users are in different Windows domain)?
$computer = [ADSI]"WinNT://$server,computer"
$computer.psbase.children | ? {
$_.psbase.schemaClassName -eq 'group'
} | % {
$gn = $_.name.ToString()
write-host $gn
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | % {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}
}
Try fetching the SID instead of the name and translate that back to a username:
$computer.psbase.children | ? {
$_.psbase.schemaClassName -eq 'group'
} | % {
$gn = $_.name.ToString()
write-host $gn
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | % {
$bytes = $_.GetType().InvokeMember('objectSid', 'GetProperty', $null, $_, $null)
$sid = New-Object Security.Principal.SecurityIdentifier ($bytes, 0)
$sid.Translate([Security.Principal.NTAccount])
}
}
The result should include the computer or domain name.
We have a similar issue where there are accounts from different domains on the computers and we need the domain back. Unfortunately the SID fetch doesn't work I think for local accounts and the domains the computer used to be joined to in some cases, so it didn't return all results.
This was the best solution I found for us:
Admin = $_.GetType().InvokeMember("AdsPath", 'GetProperty', $null, $_, $null)
will return results like
WinNT://#domain#/#account#
or WinNT://#domain of computer#/#computer-name#/#account#
for local accounts
$servers= get-content 'C:\temp\work\localadmins\serverlist_in.txt'
$output = 'C:\temp\work\localadmins\serverlist_out.csv'
$results = #()
foreach($server in $servers)
{
$admins = #()
$group =[ADSI]"WinNT://$server/Administrators"
$members = #($group.psbase.Invoke("Members"))
$members | foreach {
$obj = new-object psobject -Property #{
Server = $Server
Admin = $_.GetType().InvokeMember("AdsPath", 'GetProperty', $null, $_, $null)
}
$admins += $obj
}
$results += $admins
}
$results | Export-csv $Output -NoTypeInformation

Resources