【问题标题】:Powershell returns different information using remote connectionPowershell 使用远程连接返回不同的信息
【发布时间】:2020-08-03 15:57:25
【问题描述】:

在 PowerShell 中的目标计算机上,我运行命令 $FolderSize =(Get-ChildItem "C:\Users\JDoe" -force -Recurse -ErrorAction SilentlyContinue | Measure-Object length -sum).sum

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

$folderSize = Invoke-Command -ComputerName "computername" {(Get-ChildItem -Path "C:\Users\JDoe" -Recurse -force -ErrorAction SilentlyContinue | Measure-Object -Property Length -sum).sum} 我得到了一个不同的、更大的数字,17 GB。

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

psexec \\\computername powershell "(Get-ChildItem "C:\Users\JDoe" -force -Recurse -ErrorAction SilentlyContinue | Measure-Object length -sum).sum" 但仍然得到更大的数字。

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

【问题讨论】:

    标签: powershell get-childitem


    【解决方案1】:

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

    您似乎可以远程访问此交汇点(甚至可以从使用 \\COMPUTER01\C$\Users\JDoe\AppData\Local\Application Data 的资源管理器中访问)所以这就是 为什么您会得到不同的大小,因为它递归地计算相同的东西直到 @ 987654321@ 限制。

    比较以下命令在远程和本地的输出:
    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
    

    您需要使用类似于this answer 中的递归函数,从Get-ChildItem 单独递归。

    【讨论】:

    • 有趣。虽然我熟悉符号链接,但我从未遇到过连接。所以我需要排除“应用程序数据”。我会尝试一下,看看我得到了什么结果。谢谢!
    • 我不知道其他类似的情况,但您应该能够在其他文件夹上本地运行它而不会抑制错误并且很容易检测到它。 (您会收到 Could not find a part of the path 'C:\Users\JDoe\AppData\Local\Application Data\Application Data\Application Data\Application Data\Application Data\... 之类的错误,不客气,祝您好运!
    • 我取得了一点成功,我添加了“where {$_.attributes -notlike "ReparsePoint"}”,但它似乎只是将它们排除在完整报告之外名称,它仍在计算大小。我是否需要创建一个子例程来排除具有该属性的那些文件夹?
    • 优秀的侦探;这种差异应该被认为是一个错误;您可以使用以下命令cmd /c dir /s /ashld $env:USERPROFILE(在用户的配置文件中)或`cmd /c dir /s /ashld C:`(整个C:驱动器)找到所有这些隐藏的连接点,这些连接点仅用于向后兼容。背景资料:svrops.com/svrops/articles/jpoints.htm
    • 这太疯狂了,尽管排除了它仍然将字节数添加到总数中。我尝试过远程运行 powershell dir 命令,无论如何我远程执行的所有操作都遵循连接点/符号链接。它总是通过网络外壳运行。我想解决它的唯一方法是严格在本地运行一些东西,例如通过计划任务,除非我找到一些第 3 方应用程序。我会继续努力的。谢谢!
    【解决方案2】:

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

    再次感谢!

    【讨论】:

      【解决方案3】:

      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 中,您的远程执行代码因此会计算某些目录中的文件(至少)两次 - 一次作为隐藏的连接点,并在实际目录中再次指向。


      因此,有两种可能的解决方案

      • 如果目标机器安装了PowerShell [Core] v6+并启用了远程处理,使用您的远程处理命令定位it strong>(即使在从 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
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-05
        • 1970-01-01
        • 2016-06-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多