Powershell возвращает различную информацию с помощью удаленного подключения - PullRequest
3 голосов
/ 03 августа 2020

На моем целевом компьютере в PowerShell я запускаю команду $FolderSize =(Get-ChildItem "C:\Users\JDoe" -force -Recurse -ErrorAction SilentlyContinue | Measure-Object length -sum).sum

и получаю значение 0,76 ГБ, что точно соответствует сжатому размеру папки на диске. Однако, когда я пытаюсь запустить команду на удаленном компьютере, используя

$folderSize = Invoke-Command -ComputerName "computername" {(Get-ChildItem -Path "C:\Users\JDoe" -Recurse -force -ErrorAction SilentlyContinue | Measure-Object -Property Length -sum).sum}, я получаю другое, НАМНОГО большее число, 17 ГБ.

Я пробовал запустить первую команду в сеансе ps но все равно получить результат 17 ГБ. Я также пробовал использовать

psexec \\\computername powershell "(Get-ChildItem "C:\Users\JDoe" -force -Recurse -ErrorAction SilentlyContinue | Measure-Object length -sum).sum", но все равно получил большее число.

Я не понимаю, почему результаты, полученные удаленно, отличаются от фактического размера папки, когда я просматриваю ее локально . По крайней мере, все удаленные результаты согласованы, что говорит мне о том, что все они измеряют одно и то же.

Ответы [ 3 ]

1 голос
/ 04 августа 2020

Полезный ответ 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

}
1 голос
/ 05 августа 2020

Спасибо за все предложения! В конечном итоге я решил использовать приложение Sysinternals "du" и захватывать выходные данные в удаленном задании, чтобы минимизировать сетевой трафик c.

Еще раз спасибо!

1 голос
/ 03 августа 2020

Это связано с перекрестком в AppData\Local с именем Application Data, который указывает на AppData\Local

Похоже, что вы можете получить доступ к этому перекрестку удаленно (даже из проводника, использующего \\COMPUTER01\C$\Users\JDoe\AppData\Local\Application Data), так что это это , почему вы получаете разные размеры, так как он рекурсивно подсчитывает одни и те же данные до предела MAX_PATH .

Сравните выходные данные следующей команды на удаленном и локальном: Get-ChildItem 'C:\Users\JDoe\AppData\Local\Application Data' -Force

Локальный

PS C:\> Get-ChildItem 'C:\Users\JDoe\AppData\Local\Application Data' -Force
Get-ChildItem : Access to the path 'C:\Users\JDoe\AppData\Local\Application Data' is denied.
At line:1 char:1
+ Get-ChildItem 'C:\Users\JDoe\AppData\Local\Application Data' -Forc ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : PermissionDenied: (C:\users\JDoe\A...plication Data\:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand

Удаленный

PS C:\> Invoke-Command -ComputerName COMPUTER01 -ScriptBlock { Get-ChildItem 'C:\Users\JDoe\AppData\Local\Application Data' -Force }


    Directory: C:\Users\JDoe\AppData\Local\Application Data


Mode                LastWriteTime         Length Name                        PSComputerName
----                -------------         ------ ----                        --------------
d--hsl        4/16/2020   4:46 PM                Application Data            COMPUTER01
d-----       10/31/2019   9:43 AM                ConnectedDevicesPlatform    COMPUTER01
d-----       10/31/2019   9:52 AM                ElevatedDiagnostics         COMPUTER01
d-----       10/31/2019   9:43 AM                Google                      COMPUTER01
d--hsl        4/16/2020   4:46 PM                History                     COMPUTER01
d-----        4/16/2020   4:50 PM                Microsoft                   COMPUTER01
d-----        9/16/2019   8:14 PM                Microsoft Help              COMPUTER01
d-----       10/31/2019   9:43 AM                MicrosoftEdge               COMPUTER01
d-----       10/31/2019   9:53 AM                OpenShell                   COMPUTER01
d-----        4/16/2020   4:47 PM                Packages                    COMPUTER01
d-----       10/31/2019   9:43 AM                PlaceholderTileLogoFolder   COMPUTER01
d-----       10/31/2019   9:43 AM                Publishers                  COMPUTER01
d-----        3/18/2019  11:52 PM                Temp                        COMPUTER01
d--hsl        4/16/2020   4:46 PM                Temporary Internet Files    COMPUTER01
d-----       10/31/2019   9:43 AM                VirtualStore                COMPUTER01

Вам потребуется рекурсивно отдельно от Get-ChildItem с помощью рекурсивной функции, подобной той, что приведена в этом ответе .

...