Powershell returns 使用远程连接的不同信息
Powershell returns different information using remote connection
在我的目标计算机上的 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"
但仍然得到更大的数字。
我不明白为什么远程获得的结果与我在本地检查时文件夹的实际大小不同。至少所有的远程结果都是一致的,这告诉我他们都在测量同样的东西。
这是由于 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
您需要使用 this answer.
中的递归函数,与 Get-ChildItem
分开递归
提供关键指针:
由于 PowerShell 远程处理使用 network-type 登录 - 请参阅 this GitHub issue - PowerShell 代码 运行s 远程 意外地具有递归到隐藏系统连接 所需的权限。但是,这些隐藏连接的存在仅仅是为了与 pre-Vista Windows 版本向后兼容,并不意味着要遍历 自身 :它们只是重定向到well-known 个它们代表的文件夹。
例如,隐藏的 "$HOME\My Documents"
连接点指向 "$HOME\Documents"
- 请参阅 this article 了解背景信息。
本地 执行代码 - 即使 运行 作为管理员 - 是设计 不允许 访问这些隐藏路口的内容.
当你使用Get-ChildItem -Recurse
时:
Windows PowerShell 在递归遍历期间遇到这些隐藏连接时报告 access-denied 错误,因为 它会尝试递归到它们.
PowerShell [Core] v6+ 更明智地 安静地跳过 在递归遍历期间的这些连接点 - 无论是本地还是远程执行,所以你的问题不会出现。一般情况下,目录symlinks/junctions是而不是,除非指定了-FollowSymlink
;然而,即便如此,也不会发生 error - 每个隐藏的结点只会发出 warning,以识别 redirected-to 真实目录已经遍历了
在 Windows PowerShell 中,您的远程执行代码因此对某些目录中的文件计数(至少)两次 - 一次作为隐藏结点的内容,再次在指向的实际目录中。
因此,有两种可能的解决方案:
如果 目标机器安装了 PowerShell [Core] v6+ 并启用了远程处理,使用远程命令 定位 it(即使从 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 脚本块中使用此函数,您(还)必须在 there:
# 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
}
谢谢大家的建议!最终,我选择使用 Sysinternals“du”应用程序并在远程作业中捕获输出,以最大限度地减少网络流量。
再次感谢!
在我的目标计算机上的 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"
但仍然得到更大的数字。
我不明白为什么远程获得的结果与我在本地检查时文件夹的实际大小不同。至少所有的远程结果都是一致的,这告诉我他们都在测量同样的东西。
这是由于 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
您需要使用 this answer.
中的递归函数,与Get-ChildItem
分开递归
由于 PowerShell 远程处理使用 network-type 登录 - 请参阅 this GitHub issue - PowerShell 代码 运行s 远程 意外地具有递归到隐藏系统连接 所需的权限。但是,这些隐藏连接的存在仅仅是为了与 pre-Vista Windows 版本向后兼容,并不意味着要遍历 自身 :它们只是重定向到well-known 个它们代表的文件夹。
例如,隐藏的 "$HOME\My Documents"
连接点指向 "$HOME\Documents"
- 请参阅 this article 了解背景信息。
本地 执行代码 - 即使 运行 作为管理员 - 是设计 不允许 访问这些隐藏路口的内容.
当你使用Get-ChildItem -Recurse
时:
Windows PowerShell 在递归遍历期间遇到这些隐藏连接时报告 access-denied 错误,因为 它会尝试递归到它们.
PowerShell [Core] v6+ 更明智地 安静地跳过 在递归遍历期间的这些连接点 - 无论是本地还是远程执行,所以你的问题不会出现。一般情况下,目录symlinks/junctions是而不是,除非指定了
-FollowSymlink
;然而,即便如此,也不会发生 error - 每个隐藏的结点只会发出 warning,以识别 redirected-to 真实目录已经遍历了
在 Windows PowerShell 中,您的远程执行代码因此对某些目录中的文件计数(至少)两次 - 一次作为隐藏结点的内容,再次在指向的实际目录中。
因此,有两种可能的解决方案:
如果 目标机器安装了 PowerShell [Core] v6+ 并启用了远程处理,使用远程命令 定位 it(即使从 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 脚本块中使用此函数,您(还)必须在 there:
# 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
}
谢谢大家的建议!最终,我选择使用 Sysinternals“du”应用程序并在远程作业中捕获输出,以最大限度地减少网络流量。
再次感谢!