从 UNC 路径获取 DFS 服务器名称和本地路径
Get DFS Server name and local path from UNC path
我正在开发 Windows Server 2012,它默认带有各种 DFS CmdLets。
我想要做的是获取域上其他 DFS 服务器 (Win Srv 2008 R2) 托管的特定 UNC 共享的 ComputerName
和 local 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\
时,它确实说可以找到它。所以我不是很明白。
我正在尝试检索此信息(ComputerName
和 local 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])
}
}
}
}
我正在开发 Windows Server 2012,它默认带有各种 DFS CmdLets。
我想要做的是获取域上其他 DFS 服务器 (Win Srv 2008 R2) 托管的特定 UNC 共享的 ComputerName
和 local 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\
时,它确实说可以找到它。所以我不是很明白。
我正在尝试检索此信息(ComputerName
和 local 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])
}
}
}
}