CrookedJ's helpful answer 提供关键指针:
由于 PowerShell 远程处理使用的 网络类型登录 - 请参阅 this GitHub issue - 远程运行的 PowerShell 代码 意外地具有递归到所需的权限隐藏的系统连接。但是,这些隐藏连接的存在仅是为了向后兼容 Vista 之前的 Windows 版本,并且不打算遍历它们自己:它们只是重定向到它们所代表的知名文件夹的当前位置。 p>
例如,隐藏的 "$HOME\My Documents" 连接点指向 "$HOME\Documents" - 有关背景信息,请参阅 this article。
本地执行代码 - 即使以管理员身份运行 - 在设计上不允许访问这些隐藏连接的内容。。 p>
当你使用Get-ChildItem -Recurse:
-
Windows PowerShell 在递归遍历期间遇到这些隐藏的联结时会报告拒绝访问错误,因为它会尝试递归到这些联结中。
-
PowerShell [Core] v6+ 在递归遍历期间更明智地安静地跳过这些联结 - 在本地和远程执行中,因此不会出现您的问题。一般情况下,目录符号链接/连接默认后面是不,除非指定了-FollowSymlink;然而,即便如此,也不会发生 error - 每个隐藏的连接只会发出 warning,以识别重定向到的真实目录已经被遍历。
在 Windows PowerShell 中,您的远程执行代码因此会计算某些目录中的文件(至少)两次 - 一次作为隐藏的连接点,并在实际目录中再次指向。
因此,有两种可能的解决方案:
# Note:
# * Hidden items other than the hidden junctions are invariably included.
# * (Other, non-system) directory reparse points are reported, but not recursed into.
# * Supports only a subset of Get-ChildItem functionality, notably NOT wildcard patterns
# and filters.
function Get-ChildItemExcludeHiddenJunctions {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param(
[Parameter(ValueFromPipelineByPropertyName, Position = 0)] [Alias('lp', 'PSPath')]
[string] $LiteralPath,
[Parameter(ParameterSetName = 'DirsOnly')]
[switch] $Directory,
[Parameter(ParameterSetName = 'FilesOnly')]
[switch] $File,
[switch] $Recurse
)
# Get all child items except for the hidden junctions.
# Note: Due to the -Attributes filter, -Force is effectively implied.
# That is, hidden items other than hidden junctions are invariably included.
$htLitPathArg = if ($LiteralPath) { @{ LiteralPath = $LiteralPath } } else { @{ } }
$items = Get-ChildItem @htLitPathArg -Attributes !Directory, !Hidden, !System, !ReparsePoint
# Split into subdirs. and files.
$dirs, $files = $items.Where( { $_.PSIsContainer }, 'Split')
# Output the child items of interest on this level.
if (-not $File) { $dirs }
if (-not $Directory) { $files }
# Recurse on subdirs., if requested
if ($Recurse) {
$PSBoundParameters.Remove('LiteralPath')
foreach ($dir in $dirs) {
if ($dir.Target) { continue } # Don't recurse into (other, non-system) directory reparse points.
Get-ChildItemExcludeHiddenJunctions -LiteralPath $dir.FullName @PSBoundParameters
}
}
}
要在 remote 脚本块中使用此函数,您(还)必须在 那里 定义它:
# Assuming the Get-ChildItemExcludeHiddenJunctions function is already defined as above:
# Get a string representation of its definition (function body).
$funcDef = "${function:Get-ChildItemExcludeHiddenJunctions}"
$folderSize = Invoke-Command -ComputerName "computername" {
# Define the Get-ChildItemExcludeHiddenJunctions function in the remote sesson.
${function:get-ChildItemExcludeHiddenJunctions} = $using:funcDef
(Get-ChildItemExcludeHiddenJunctions "C:\Users\JDoe" -Recurse -File |
Measure-Object -Property Length -Sum).Sum
}