PS2_-_Shares

advertisement
Continuing the PowerShell experience, this time by searching the network for shares and listing the
permissions assigned to each share. One reason to do this is to discover if any individual users have been
assigned access rights on a share. It’s a best practice to only assign share rights to security groups
because that centralizes rights assignment and reduces effort and chances for error.
So, since we’re going to perform the same task against (potentially) a lot of servers and shares, it makes
sense to develop a PowerShell function to perform the repetitive task. (One cool thing about PowerShell
is that if it doesn’t do something that you want, you can almost always write some PowerShell to make
it do it.)
OK, so here’s the script (I’ll explain what happens right after the listing):
function Get-SharePermission {
Param($ComputerName = $env:ComputerName)
$ShareData = @{}
$Shares = @()
Try {
Get-WMIObject win32_Share -ComputerName $ComputerName -ErrorAction Stop | Foreach {$ShareData += @{$_.Name=
@{'Path'=$_.Path;'Description'=$_.Description}}}
$ShareSecurity = Get-WMIObject win32_LogicalShareSecuritySetting -comp $ComputerName
foreach($Share in $ShareSecurity) {
$ShareName = $Share.Name
$ACLS = $Share.GetSecurityDescriptor().Descriptor.DACL
foreach($ACL in $ACLS) {
$User = "$($ACL.Trustee.Domain)\$($ACL.Trustee.Name)"
switch ($ACL.AccessMask) {
2032127 {$Perm = "Full Control"}
1245631 {$Perm = "Change"}
1179817 {$Perm = "Read"}
}
$Shares += New-Object PSobject -Property @{
'Server' = $ComputerName
'ShareName' = $ShareName
'Path'
= $ShareData[$ShareName].Path
'Description' = $ShareData[$ShareName].Description
'User'
= $User
'Permission' = $Perm
} # End property specification
} # End each ACL
} # End each Share
} # End Try
Catch {} # End Catch
Return $Shares
}
The function command defines a new function (Get-SharePermission, in this case). The script that tells
how to do that is enclosed in the outermost curly braces. The function begins be setting up some
internal variables. The Param statement identifies the parameters that are passed into function for to
operate on, in this case to be inserted into a variable named $ComputerName, with a default value of
the current computer. This is followed by the creation of two empty local variables ($ShareData [a hash
table or .NET Dictionary] and $Share [an array]). (Hash tables are indicated by @{} and arrays are
indicated by @().) If you don’t know what a hash table is, it’ll become clear shortly. The actual work of
this function happens in a Try/Catch block. In this case, the Catch block is empty because we don’t care
if a share doesn’t exist.
The Try block begins with a call to collect the win32_Share WMI data from the computer parameter. The
–ErrorAction Stop clause causes an immediate transfer to the Catch block which essentially exits the
function. Given that there are shares on the server, we add a hash table with the share name as the key
and a nested hash table (with the path and description values) as the value. Later in the script we’ll need
to be able to retrieve these.
The next step is to collect all the LogicalShareSecuritySettings from WMI. For each of these, we then get
the ACLs assigned to the shares (please note here that most of the admin shares (like C$) don’t have
ACLs assigned and won’t show up here. But, that’s OK in this case because we’re really only looking for
ACLs assigned to individual users and the admin shares are only accessible to the local administrators
group. From the ACLs, we’re going to create a custom object with the data we have collected. We
extract the user name from the ACL’s Trustee property, joining the domain and user names with a “/”.
We then translate the AccessMask integers into text in the Switch block. With that, we can populate the
$Share object with the data we need. The final statement in the function returns the data that we
collected as the value of the function.
Now that the function is defined, we can start collecting data from the servers.
$AllShares = @()
foreach ($Svr in (Get-ADComputer -Filter {OperatingSystem -like "*Server*"})) {
If (Test-Connection $Svr.Name -Count 1 -Quiet) {
Write-Host "Collecting Share Data from $($Svr.Name)"
foreach ($shr in (Get-SharePermission $Svr.Name | Group-Object ShareName)) {
$Perms = ($Shr.Group | Select @{N='Permissions';E={"$($_.User) ($($_.Permission))"}}).Permissions -join "`n"
$AllShares += [psCustomObject]@{'Server'=$Svr.Name;'ShareName'=$Shr.Name;'Path'=$Shr.Group[0].Path;'Permissions'=$Perms}
} # end each Share
} # end ping server
} # end for each server
This is accomplished by first creating an empty array ($AllShares) that we’re going to populate with the
results of the function call. The foreach block works by collecting the names of all the computers in AD
that have “Server” in the operating system name. The first step in this is to ping the server. Note that
this is performed in an IF-Then-Else block because test-connection –quiet call normally returns True or
False, and only returns an error if it can’t find the computer in DNS. Thus, in a Try block, it would
continue executing even if the server were not reachable. The next statement prints the name of the
server being examined to the console. We then process the share data collected. That data is grouped
by share name in order to consolidate the results under the server and share. The $Perms line joins each
of the users and their permissions for that particular share. A new object containing the desired results
is added to the AllShares collection.
We can then do what we need to with the finished data, such as export it to a CSV file using the ExportCsv cmdlet and then open it in Excel for further analysis.
Download