The request was, without accessing to the server, only with a list of DFS path (around 200 path), try to get by script the DFS information such as right clicking on the folder then DFS Tab.
As I have 200 DFS path and multiple ReparsePoint inside I won't do it manually.
Also please note that I didn't have the permission to use DFSN module for Powershell.
So the idea was as following:
- The script should take a csv file as input with the DFS path
- The script should found out which folder have ReparsePoint
- The script should extract the DFS Tab information and export it to a csv file
So let's start:
- Input
- Script
2.1. Function : Write-InFile
2.2. Function : StartAnalyse
2.3. Function : Get-DFSDetails
2.4. Execute
2.5. The whole script
Input
As mentionned below, the input is going to be a csv with all the DFS path. Simple csv file, just one column call name and the path below.
Script
- Function : Write-InFile
Nothing very complicated, a function which write in a file.
It take two parameters, the message you want to write in file and the path where the file is.
Function Write-InFile([string]$message, [string]$filepath){
Add-Content $filepath "$message"
}
- Function : StartAnalyse
This function is going to parse your DFS to find out the ReparsePoint. I haven't Recurse in that case, because if it was the case, it will go inside some folders with ReparsePoint which wasn't my goal. If it didn't find a ReparsePoint, it will go inside folders until it find one. If it find one, it will get the DFS information through another function.
There are two parameters for this function, $dfs which is use for the export file, and $path which is the actual parsed folder.
Function StartAnalyse{
param( [string]$path, [string]$dfs )
$item = Get-ChildItem -Path $path
$item | ForEach-Object{
if($_.Attributes -band [System.IO.FileAttributes]::ReparsePoint){
Write-Host $_.FullName
Try {
Get-DFSDetails -Path $_.FullName -strdfs $dfs
}
Catch {
Write-Error $Error[0].Exception.Message
$Global:Error.Remove($Global:Error[0])
Write-InFile -message "$dfs;$path;;;$($Error[0].Exception.Message);" -filepath "$folderpath"
}
}
else{
StartAnalyse -path $_.FullName -dfs $dfs
}
}
}
- Function : Get-DFSDetails
That's the one you have been waiting for.
Firstable let's thanks Darklite1, he made the function to get this details in the following stack overflow post. I have edited a bit (remove things I didn't needed).
The in parameters you will find the $Path which is the folder where you have your ReparsePoint. And I have added $strdfs which is use for generating the report.
Function Get-DFSDetails {
[CmdLetBinding()]
Param (
[Parameter(Mandatory, ValueFromPipeline, Position=0)]
[ValidateScript({
if (Test-Path -LiteralPath $_ -PathType Container) {$true}
else {throw "Could not find path '$_'"}
})]
[String[]]$Path,
[Parameter(Mandatory, Position=0)]
[String]$strdfs
)
Begin {
$signature = @'
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Runtime.InteropServices;
public class Win32Api
{
[DllImport("netapi32.dll", SetLastError = true)]
private static extern int NetApiBufferFree(IntPtr buffer);
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int NetDfsGetClientInfo
(
[MarshalAs(UnmanagedType.LPWStr)] string EntryPath,
[MarshalAs(UnmanagedType.LPWStr)] string ServerName,
[MarshalAs(UnmanagedType.LPWStr)] string ShareName,
int Level,
ref IntPtr Buffer
);
public struct DFS_INFO_3
{
[MarshalAs(UnmanagedType.LPWStr)]
public string EntryPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string Comment;
public UInt32 State;
public UInt32 NumberOfStorages;
public IntPtr Storages;
}
public struct DFS_STORAGE_INFO
{
public Int32 State;
[MarshalAs(UnmanagedType.LPWStr)]
public string ServerName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ShareName;
}
public static List NetDfsGetClientInfo(string DfsPath)
{
IntPtr buffer = new IntPtr();
List returnList = new List();
try
{
int result = NetDfsGetClientInfo(DfsPath, null, null, 3, ref buffer);
if (result != 0)
{
throw (new SystemException("Error getting DFS information"));
}
else
{
DFS_INFO_3 dfsInfo = (DFS_INFO_3)Marshal.PtrToStructure(buffer, typeof(DFS_INFO_3));
for (int i = 0; i < dfsInfo.NumberOfStorages; i++)
{
IntPtr storage = new IntPtr(dfsInfo.Storages.ToInt64() + i * Marshal.SizeOf(typeof(DFS_STORAGE_INFO)));
DFS_STORAGE_INFO storageInfo = (DFS_STORAGE_INFO)Marshal.PtrToStructure(storage, typeof(DFS_STORAGE_INFO));
PSObject psObject = new PSObject();
psObject.Properties.Add(new PSNoteProperty("State", storageInfo.State));
psObject.Properties.Add(new PSNoteProperty("ServerName", storageInfo.ServerName));
psObject.Properties.Add(new PSNoteProperty("ShareName", storageInfo.ShareName));
returnList.Add(psObject);
}
}
}
catch (Exception e)
{
throw(e);
}
finally
{
NetApiBufferFree(buffer);
}
return returnList;
}
}
'@
if (-not ('Win32Api' -as [Type])) {
Add-Type -TypeDefinition $signature
}
}
Process {
foreach ($P in $Path) {
Try {
$DFS = [Win32Api]::NetDfsGetClientInfo($P) | Where-Object { $_.State -eq 6 } |
Select-Object ServerName, ShareName
Write-InFile -message "$strdfs;$Path;$($DFS.ServerName);\\$($DFS.ServerName)\$($DFS.ShareName);;" -filepath "$folderpath"
}
Catch {
Write-Error $Error[0].Exception.Message
$Global:Error.Remove($Global:Error[0])
Write-InFile -message "$strdfs;$Path;;;;$($Error[0].Exception.Message)" -filepath "$folderpath"
}
}
}
}
- Execute
How to call the functions above.
#Script
$folderpath = "Path\To\Output\ReportDFS.csv";
$csv = Import-Csv -Path "Path\To\Input.csv" -Delimiter ";"
Write-InFile -message "DFS;DFSPath;Server;ServerPath;Error;" -filepath "$folderpath"
foreach($csvI in $csv){
$dfs = $csvI.Name
StartAnalyse -path $dfs -dfs $dfs
}
- The whole script
Function Write-InFile([string]$message, [string]$filepath){
Add-Content $filepath "$message"
}
Function Get-DFSDetails {
[CmdLetBinding()]
Param (
[Parameter(Mandatory, ValueFromPipeline, Position=0)]
[ValidateScript({
if (Test-Path -LiteralPath $_ -PathType Container) {$true}
else {throw "Could not find path '$_'"}
})]
[String[]]$Path,
[Parameter(Mandatory, Position=0)]
[String]$strdfs
)
Begin {
$signature = @'
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Runtime.InteropServices;
public class Win32Api
{
[DllImport("netapi32.dll", SetLastError = true)]
private static extern int NetApiBufferFree(IntPtr buffer);
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int NetDfsGetClientInfo
(
[MarshalAs(UnmanagedType.LPWStr)] string EntryPath,
[MarshalAs(UnmanagedType.LPWStr)] string ServerName,
[MarshalAs(UnmanagedType.LPWStr)] string ShareName,
int Level,
ref IntPtr Buffer
);
public struct DFS_INFO_3
{
[MarshalAs(UnmanagedType.LPWStr)]
public string EntryPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string Comment;
public UInt32 State;
public UInt32 NumberOfStorages;
public IntPtr Storages;
}
public struct DFS_STORAGE_INFO
{
public Int32 State;
[MarshalAs(UnmanagedType.LPWStr)]
public string ServerName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ShareName;
}
public static List NetDfsGetClientInfo(string DfsPath)
{
IntPtr buffer = new IntPtr();
List returnList = new List();
try
{
int result = NetDfsGetClientInfo(DfsPath, null, null, 3, ref buffer);
if (result != 0)
{
throw (new SystemException("Error getting DFS information"));
}
else
{
DFS_INFO_3 dfsInfo = (DFS_INFO_3)Marshal.PtrToStructure(buffer, typeof(DFS_INFO_3));
for (int i = 0; i < dfsInfo.NumberOfStorages; i++)
{
IntPtr storage = new IntPtr(dfsInfo.Storages.ToInt64() + i * Marshal.SizeOf(typeof(DFS_STORAGE_INFO)));
DFS_STORAGE_INFO storageInfo = (DFS_STORAGE_INFO)Marshal.PtrToStructure(storage, typeof(DFS_STORAGE_INFO));
PSObject psObject = new PSObject();
psObject.Properties.Add(new PSNoteProperty("State", storageInfo.State));
psObject.Properties.Add(new PSNoteProperty("ServerName", storageInfo.ServerName));
psObject.Properties.Add(new PSNoteProperty("ShareName", storageInfo.ShareName));
returnList.Add(psObject);
}
}
}
catch (Exception e)
{
throw(e);
}
finally
{
NetApiBufferFree(buffer);
}
return returnList;
}
}
'@
if (-not ('Win32Api' -as [Type])) {
Add-Type -TypeDefinition $signature
}
}
Process {
foreach ($P in $Path) {
Try {
$DFS = [Win32Api]::NetDfsGetClientInfo($P) | Where-Object { $_.State -eq 6 } |
Select-Object ServerName, ShareName
Write-InFile -message "$strdfs;$Path;$($DFS.ServerName);\\$($DFS.ServerName)\$($DFS.ShareName);;" -filepath "$folderpath"
}
Catch {
Write-Error $Error[0].Exception.Message
$Global:Error.Remove($Global:Error[0])
Write-InFile -message "$strdfs;$Path;;;;$($Error[0].Exception.Message)" -filepath "$folderpath"
}
}
}
}
Function StartAnalyse{
param( [string]$path, [string]$dfs )
$item = Get-ChildItem -Path $path
$item | ForEach-Object{
if($_.Attributes -band [System.IO.FileAttributes]::ReparsePoint){
Write-Host $_.FullName
Try {
Get-DFSDetails -Path $_.FullName -strdfs $dfs
}
Catch {
Write-Error $Error[0].Exception.Message
$Global:Error.Remove($Global:Error[0])
Write-InFile -message "$dfs;$path;;;$($Error[0].Exception.Message);" -filepath "$folderpath"
}
}
else{
StartAnalyse -path $_.FullName -dfs $dfs
}
}
}
#Script
$folderpath = "Path\To\Output\ReportDFS.csv";
$csv = Import-Csv -Path "Path\To\Input.csv" -Delimiter ";"
Write-InFile -message "DFS;DFSPath;Server;ServerPath;Error;" -filepath "$folderpath"
foreach($csvI in $csv){
$dfs = $csvI.Name
StartAnalyse -path $dfs -dfs $dfs
}