Полезный ответ CrookedJ предоставляет важный указатель:
Из-за входа в систему сетевого типа , которые использует удаленное взаимодействие PowerShell - см. эту проблему GitHub - Код PowerShell, который запускается удаленно , неожиданно получает необходимые привилегии для рекурсии в скрытые системные соединения . Однако эти скрытые переходы существуют исключительно для обратной совместимости с версиями Windows до Vista и не предназначены для обхода самих : они просто перенаправляют на текущие местоположения хорошо известных папок, которые они представляют. 1015 *
Например, скрытое соединение "$HOME\My Documents"
указывает на "$HOME\Documents"
- дополнительную информацию см. в этой статье .
Локально код выполнения - даже если запускаться от имени администратора - по дизайну не разрешен доступ к содержимому этих скрытых переходов .
При использовании Get-ChildItem -Recurse
:
Windows PowerShell сообщает об ошибках отказа в доступе при обнаружении этих скрытых соединений во время рекурсивного обхода, потому что пытается рекурсивно в них .
PowerShell [Core] v6 + более разумно незаметно пропускает эти соединения во время рекурсивного обхода - как при локальном, так и при удаленном выполнении, поэтому ваша проблема не возникнет. Как правило, символические ссылки / соединения каталогов: не , за которыми следует значение по умолчанию, если не указано -FollowSymlink
; даже тогда, однако, не возникает ошибка - только предупреждение выдается для каждого скрытого соединения, в знак признания того, что перенаправленные на реальные каталоги уже были пройдены.
В Windows PowerShell ваш удаленно выполняемый код считает файлы в определенных каталогах (как минимум) дважды - один раз как содержимое скрытого соединения и снова в указанном фактическом каталоге.
Следовательно, есть два возможных решения :
Если на целевой машине есть PowerShell [Core] v6 + установлен и удаленное взаимодействие включено, цель это с вашей командой удаленного взаимодействия (что вы можете сделать даже при вызове из Windows PowerShell :
- Просто добавьте аргумент
-ConfigurationName PowerShell.<majorVersion>
в вызов Invoke-Command
, например, -ConfigurationName PowerShell.7
для версий PowerShell [Core] 7.x.
В противном случае - , если вы должны настроить таргетинг на Windows PowerShell - вам нужен обходной путь , который в вашем случае должен использовать настраиваемый вариант Get-ChildItem
, который явно пропускает скрытые соединения во время рекурсии :
# 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
}