Powershell使用远程连接返回不同的信息

Powershell使用远程连接返回不同的信息,powershell,get-childitem,Powershell,Get Childitem,在PowerShell中的目标计算机上运行命令 $FolderSize=(获取ChildItem“C:\Users\JDoe”-force-Recurse-ErrorAction SilentlyContinue |测量对象长度-求和)。求和 我得到一个0.76GB的值,它精确地对应于磁盘上文件夹的压缩大小。但是,当我尝试在远程计算机上使用 $folderSize=Invoke命令-ComputerName“ComputerName”{(Get ChildItem-路径“C:\Users\JDo

在PowerShell中的目标计算机上运行命令
$FolderSize=(获取ChildItem“C:\Users\JDoe”-force-Recurse-ErrorAction SilentlyContinue |测量对象长度-求和)。求和

我得到一个0.76GB的值,它精确地对应于磁盘上文件夹的压缩大小。但是,当我尝试在远程计算机上使用

$folderSize=Invoke命令-ComputerName“ComputerName”{(Get ChildItem-路径“C:\Users\JDoe”-递归-强制-ErrorAction SilentlyContinue |度量对象-属性长度-总和)。总和}
我得到一个不同的,更大的数字,17 gb

我尝试在pssession中运行第一个命令,但仍然得到17gb的结果。我也试过使用

psexec\\\computername powershell”(获取子项“C:\Users\JDoe”-强制-递归-错误操作SilentlyContinue |测量对象长度-求和)。求和“
,但仍然获取较大的数字


我不明白为什么远程获得的结果与本地检查时文件夹的实际大小不同。至少所有远程结果都是一致的,这告诉我它们都在测量相同的东西。

这是由于
AppData\Local
中名为
Application Data
的连接点指向
AppData\Local

您似乎可以远程访问此连接(甚至可以使用
\\COMPUTER01\C$\Users\JDoe\AppData\Local\Application Data
)从资源管理器访问),因此这就是为什么您会得到不同大小的连接,因为它会递归地将相同的内容计数到极限

比较远程和本地上以下命令的输出:
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
单独递归。

提供了关键指针:

由于PowerShell远程处理使用的网络类型登录-请参阅-远程意外运行的PowerShell代码具有递归到隐藏系统连接所需的权限。然而,这些隐藏连接的存在仅仅是为了与Vista之前的Windows版本向后兼容,并不意味着要自己遍历:它们只是重定向到它们所表示的已知文件夹的当前位置

例如,隐藏的
“$HOME\My Documents”
连接点指向
“$HOME\Documents”
——请参阅以获取背景信息

本地执行的代码(即使以管理员身份运行)在设计上不允许访问这些隐藏连接的内容

使用
获取子项-递归时

  • Windows PowerShell在递归遍历期间遇到这些隐藏连接时报告拒绝访问错误,因为它试图递归到这些连接中

  • PowerShell[Core]v6+在递归遍历过程中(无论是在本地还是远程执行中)更明智地悄悄跳过这些连接,这样就不会出现问题。通常,除非指定了
    -FollowSymlink
    ,否则默认情况下不遵循目录符号链接/连接;然而,即使这样,也不会发生错误——只会对每个隐藏的连接发出警告,以确认重定向到实际目录的连接已经被遍历

因此,在Windows PowerShell中,远程执行的代码会将某些目录中的文件(至少)计数两次——一次作为隐藏连接的内容,另一次作为指向的实际目录


因此,有两种潜在的解决方案

  • 如果目标计算机安装了PowerShell[Core]v6+,并启用了远程处理,则使用远程处理命令将其定位(即使从Windows PowerShell调用,也可以执行此操作:

    • 只需将
      -ConfigurationName PowerShell.
      参数添加到您的
      Invoke命令
      调用中,例如,对于PowerShell[Core]7.x版本,将
      -ConfigurationName PowerShell.7
      添加到调用中即可
  • 否则-如果必须以Windows PowerShell为目标,则需要一个解决方案,在您的情况下,这是使用一个自定义
    Get ChildItem
    变量,该变量在递归过程中显式跳过隐藏的连接

要在远程脚本块中使用此函数,还必须在其中定义它:


感谢所有的建议!最终,我选择使用Sysinternals“du”应用程序,并在远程作业中捕获输出,从而最大限度地减少网络流量


再次感谢!

很有意思。虽然我熟悉符号链接,但我从未遇到过连接。因此我需要排除“应用程序数据”。我将尝试一下,看看我得到了什么结果。谢谢!我不知道还有其他类似的情况,但您应该能够在其他文件夹上本地运行它,而不会抑制错误,并且可以很容易地检测到它。(您会遇到类似
找不到路径'C:\Users\JDoe\AppData\Local\Application Data\Application Data\Application Data\Application Data\Application Data\……
不客气,祝您好运!我取得了一点成功,我添加了“where{$\ attributes-不像“ReparsePoint”}”,但它似乎只是将它们从报告全名中排除,它仍然在计算大小。我是否需要创建一个子例程来排除具有该属性的文件夹?出色的搜索;这种差异应被视为一个错误;您可以找到所有这些隐藏的连接,这些连接仅用于向后兼容,具有以下command
cmd/c dir/s/ashld$env:USERPROFILE
(在用户配置文件中)或`cmd/c dir/s/ashld c:`(整个c:drive)。背景信息:这太疯狂了,尽管排除了它,它仍然是一个
# 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
    }
  }

}
# 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

}