PowerShell and Listing Shares on Your Network

From time to time, you may hear a question from staff about what shares have been set up on machines in your network.  One reason to ask this question is in implementing DFS.  To know all the shares that have been created over an extended period, and to make sure you document and understand what’s available on your network to all of your users, you need to somehow query this information.  Once you have file shares documented, you can more effectively implement DFS.  You will also know which printer shares have been set up.  And, ultimately, it’s always good to be aware of what is out there on your network or what people are doing with their machines.

There are some simple PowerShell scripts out there that touch on this in a very simple way.  But, a simple way to find a share on a machine is through this one-liner:


get-wmiobject -class "Win32_Share" -namespace "root\CIMV2" -computername "computername"

Simple enough.  However, one challenge is understanding RPC errors.  The primary reasons for returning an RPC error are:  You have a DNS resolution issue, a firewall issue on the target computer, or RPC isn’t running.

My primary goal in writing this script was to create some documentation and have a place to start for A) making sure we knew about all shares on all machines, B) having a report in csv format to see which shares didn’t have descriptions entered on the share setup, and finally C) being aware of any DNS issues so we could clean up DNS entries if necessary.

While this script isn’t 100% polished, it gets the job done.  We are doing several things here:

  • Get the entire list of computer objects in AD
  • Provide a simple progress indication to the user
  • Ping the computer and only try a WMI query against it if it responds
  • If the responding computer has an RPC error, handle that error and save the information to a csv file for resolution
  • Save all share information for each computer to a CSV file for documentation purposes
  • Only save the failed RPC errors if they occur

As always, please read through the script before attempting to run this.  I’ve commented each area to help you understand each section.  One section you might want to improve upon is only gathering share information if it is of a specific type(s).  In my case, I wanted to document ALL shares.

There’s a great post here:  http://blogs.technet.com/b/josebda/archive/2010/04/08/using-powershell-v2-to-gather-info-on-free-space-on-the-volumes-of-your-remote-file-server.aspx from Jose Barreto.  You could easily alter this script to show disk space and other information.

04/18/2012 – ADDENDUM: While running this script in a lab, I found a few problems with the script that I didn’t originally encounter on the first version. I will be adding some more conditional logic and see if I can’t correct the issues I’ve found.

I found a couple issues here. One after looking through comments from get-wmiobject queries by other people and several responses, including Jeffery Hicks, I decided only to query shares that would normally be accessed by users. This reduced the number of errors returned and also made the amount of data in the array smaller. One of the biggest challenges I ran into were the handful of different RPC errors. I found this quite curious. I went through all of the possible issues… are the services started, are there permissions issues, is it OS specific, etc. etc. I found no valid reason for these error. While enumerating machines from get-adcomputer or from a text file, the error would occur on random PC’s. If I used a one-liner to query the information using the computer names which failed on a previous test run of the script, the query was always successful.

To better understand what was happening, I set the following exception variables to true: ReportErrorShowExceptionClass, ReportErrorShowInnerException, and ReportErrorShowStackTrace. The continue statement in my trap wasn’t working when this error occurred, so I commented out my trap, set the above variables, and removed the default error action in order to find more information about what was going on.

Something curious happened. I ran the script a couple of times, no errors which terminated the script. Odd. Then, I had a hunch. It had to be the way I was handling the errors. I threw in a pause function and then to test the error handling, added a write-host with the error information and a pause statement to create my own breakpoint. I saw the big glaring problem, the way I was handling the errors from the get-wmiobject wasn’t working. Time to employ Try Catch.

But changing my previous error handling with a try/catch/finally block along with setting the default error action preference to silently continue and “logging” the errors seemed to do the trick.

I’m still curious why the wmi queries were so random. Why did they work in a one-liner and failed in a script? Some may know the answer, I’ve not ran into a reason for the cause.

Here is the current working version:

<#  
.SYNOPSIS
	Get Share Infornmation on Network Computers
.DESCRIPTION
	This script uses WMI and Active Directory to query all computers on a network within
	the domain to document shares.  It converts the share type information to readable share type.
.NOTES  
	File Name	: get-NetworkComputerShares.ps1
	Version		: 1.1
	Date		: 02/18/2012
	Author		: Ted Wagner
	Requires	: PowerShell V2  
.EXAMPLE
	PS c:\foo> .\get-NetworkComputerShares.ps1
#>
#Requires -Version 2.0

# Convert Share Type to Type Description
function get-ShareType($Share){
$ShareType = $(switch($Share){
		"0" {"Disk Drive"}
		"1" {"Print Queue"}
		"2" {"Device"}
		"3" {"IPC"}
		"2147483648" {"Disk Drive Admin"}
		"2147483649" {"Print Queue Admin"}
		"2147483650" {"Device Admin"}
		"2147483651" {"IPC Admin"}
	}
)
return $ShareType
}
Clear-Host
Import-Module ActiveDirectory

# Set Variables
$ErrorActionPreference = "silentlycontinue"
$counter = 0
$TotalProcessedCount = 0
$TotalSharesCount = 0
$ShareList = @()
$FailList = @()
# Let's set the error action preference to continue.  Trap using a trap statement below, display the error, and always continue.

# Get all AD Computer objects, select only the property "Name"
$Computers = Get-ADComputer -Filter 'Name -like "*"' | Select -Expand Name

foreach ($Computer in $Computers){
	$Counter++
	$TotalShares = $Computers.count
	$progress = [int]($Counter / $TotalShares * 100)
	Write-Progress -Activity "Getting inventory of Computers" -status "Processing shares on computer: $Computer - $counter out of $TotalShares" -perc $progress
	if (Test-Connection -Quiet -Count 1 -ComputerName $Computer){
		$TotalProcessedCount++
		try{
			$Shares = get-wmiobject -class "Win32_Share" -computername $Computer -ErrorVariable WMIError -ErrorAction SilentlyContinue | Select Name, Description, Path, Type | Where-Object { $_.type -eq "0"}
			# Make sure get-wmiobject returns data then populate array
			if ($Shares){
				foreach ($Share in $Shares) {
					$TotalSharesCount++			
					$ShareSummary = "" | Select ComputerName, Description, Name, Path, ShareType 
					$ShareSummary.Computername = $Computer
					$ShareSummary.Name = $Share.Name
					$ShareSummary.Description = $Share.Description
					$ShareSummary.Path = $Share.Path
					$ShareSummary.ShareType = get-ShareType $Share.Type
					$ShareList += $ShareSummary
				}
			}
		}
		catch{
				Write-warning "Error on computer number $counter - $Computer"
				$FailSummary = "" | Select ComputerName, Error
				$FailSummary.Computername = $Computer
				$FailSummary.Error = $WMIError[0].Exception
				$FailList += $FailSummary
				$WMIError.clear()
				continue
			}
		finally
		{
			$script:Exception = $_; continue
		}
	}
}

# Output data to CSV files - only output for RPC errors if errors received
$CSVFile = Read-Host "Enter filename/path for the Share Summary Report";$ShareList | Export-Csv $CSVFile -NoTypeInformation
if ($FailList){
	$CSVFile = Read-Host "Enter filename/path for the Share Failed Summary Report";$FailList | Export-Csv $CSVFile -NoTypeInformation
}
Write-Host "Processed $TotalSharesCount shares on $TotalProcessedCount computers"

November 2016 Update:

I’ve since been using the approach mentioned in this link: http://serverfault.com/questions/623710/can-you-use-a-powershell-script-to-find-all-shares-on-servers