从 UNC 路径获取 DFS 服务器名称和本地路径

Get DFS Server name and local path from UNC path

我正在开发 Windows Server 2012,它默认带有各种 DFS CmdLets

我想要做的是获取域上其他 DFS 服务器 (Win Srv 2008 R2) 托管的特定 UNC 共享的 ComputerNamelocal path

例子:

Get-DfsnFolderTarget -Path '\domain.net\share\folder\'

预期结果:

ComputerName = 'Server1'
Path         = 'E\Home\folder'

我不是真正的网络工程师,但我似乎无法找到一种方法来根据 UNC 路径检索此信息。每次我尝试上面的 CmdLet 时,我都会收到错误消息:

Get-DfsnFolderTarget : Cannot get DFS folder properites on "\domain.net\share\folder\"
At line:1 char:1
+ Get-DfsnFolderTarget -Path '\domain.net\share\folder\'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (MSFT_DfsNamespaceFolderTarget:ROOT\Microsoft\...aceFolderTarget) [Ge 
   t-DfsnFolderTarget], CimException
    + FullyQualifiedErrorId : Windows System Error 1168,Get-DfsnFolderTarget

Get-DfsnFolderTarget : The requested object could not be found.
At line:1 char:1
+ Get-DfsnFolderTarget -Path '\domain.net\share\folder\'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (MSFT_DfsNamespaceFolderTarget:ROOT\Microsoft\...aceFolderTarget) [Ge 
   t-DfsnFolderTarget], CimException
    + FullyQualifiedErrorId : MI RESULT 6,Get-DfsnFolderTarget

当尝试 Test-Path \domain.net\share\folder\ 时,它确实说可以找到它。所以我不是很明白。

我正在尝试检索此信息(ComputerNamelocal path):

我通过谷歌搜索和调整一些东西解决了我自己的问题。对于其他感兴趣的人,这就是我最终得到的结果:

Function Get-DFSDetails {
<# 
    .SYNOPSIS   
        Gets DFS details for a UNC path.
    
    .DESCRIPTION
        The Get-DFSDetails CmdLet gets DFS details like DFS Server name, DFS Share name and the local path on the DFS Server for a specific UNC path.
    
    .PARAMETER Credentials 
        PowerShell credential object used to connect to the DFS Server to retrieve the local path on the server.
    
    .PARAMETER Path 
        Specifies a UNC path for the folder.
    
    .EXAMPLE
        Get-DFSDetails -Path '\domain.net\HOME\Bob' -Credentials $Credentials
        Gets the DFS details for the UNC path '\domain.net\HOME\Bob'
    
        Path         : \domain.net\HOME\Bob
        ComputerName : SERVER1.DOMAIN.NET
        ComputerPath : E:\HOME\Bob
        ShareName    : HOME
    
    .EXAMPLE
        '\domain.net\HOME\Mike', '\domain.net\HOME\Jake' | Get-DFSDetails -Credentials $Credentials
        Gets the DFS details for the UNC paths '\domain.net\HOME\Mike' and '\domain.net\HOME\Jake'
    
        Path         : \domain.net\HOME\Mike
        ComputerName : SERVER1.DOMAIN.NET
        ComputerPath : E:\HOME\Mike
        ShareName    : HOME 
            
        Path         : \domain.net\HOME\Jake
        ComputerName : SERVER2.DOMAIN.NET
        ComputerPath : E:\HOME\Jake
        ShareName    : HOME    
    
    .NOTES
        CHANGELOG
        2015/10/27 Function born #>
    
    [CmdLetBinding()]
    Param (
        [Parameter(Mandatory, Position=0)]
        [PSCredential]$Credentials,
        [Parameter(Mandatory, ValueFromPipeline, Position=1)]
        [ValidateScript({
            if (Test-Path -LiteralPath $_ -PathType Container) {$true}
            else {throw "Could not find path '$_'"}
        })]
        [String[]]$Path
    )
    
    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<PSObject> NetDfsGetClientInfo(string DfsPath)
    {
        IntPtr buffer = new IntPtr();
        List<PSObject> returnList = new List<PSObject>();
    
        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 {
                # State 6 notes that the DFS path is online and active
                $DFS = [Win32Api]::NetDfsGetClientInfo($P) | Where-Object { $_.State -eq 6 } | 
                    Select-Object ServerName, ShareName
    
                $SessionParams = @{
                    Credential    = $Credentials
                    ComputerName  = $DFS.ServerName
                    SessionOption = New-CimSessionOption -Protocol Dcom
                }
                $CimParams = @{
                    CimSession = New-CimSession @SessionParams
                    ClassName  = 'Win32_Share'
                }
                $LocalPath = Get-CimInstance @CimParams | Where-Object Name -EQ $DFS.ShareName | 
                    Select-Object -ExpandProperty Path
    
                [PSCustomObject][Ordered]@{
                    Path         = $P
                    ComputerName = $DFS.ServerName
                    ComputerPath = $LocalPath + ($P -split $DFS.ShareName, 2)[1]
                    ShareName    = $DFS.ShareName
                }
            }
            Catch {
                Write-Error $Error[0].Exception.Message
                $Global:Error.Remove($Global:Error[0])
            }
        }
    }
}