
그것을 해결하려면 :나는 이것에 대해 다음과 같은 다양한 방법이 있다는 것을 이해합니다 Get-ChildItem
.
따라서 일부 .Net 클래스뿐만 아니라 PowerShell cmdlet의 오버헤드 중 일부를 제거하기 위해 정의하는 사용자 지정 클래스가 있습니다. 이 함수는 로컬에서는 잘 실행되지만 Invoke-Command
원격 컴퓨터에 대해 스크립트 블록 정의로 사용하려고 하면 바로 중단됩니다.내 컴퓨터에 대해 호출하더라도. 다음을 위해 생성된 프로세스가 있습니다.WinRM 플러그인작업 관리자에 표시되지만 그게 전부입니다. 다음은 몇 가지 실제 사례입니다.
PS C:\Users\Abraham> Get-FolderSize -Path C:\Users\Abraham
143.98GB
PS C:\Users\Abraham> Invoke-Command -ScriptBlock ${Function:Get-FolderSize} -ArgumentList C:\Users\Abraham
143.98GB
위에 표시된 대로 이것은 잘 작동하고 모든 파일의 합계를 반환합니다. 그런 다음 원격 실행을 위해 컴퓨터 이름을 전달하면 Invoke-Command
그냥 중단됩니다.
Invoke-Command -ScriptBlock ${Function:Get-FolderSize} -ArgumentList C:\Users\Abraham -ComputerName $env:COMPUTERNAME
PSSession
a 도 작동하지 않는다는 것은 말할 필요도 없습니다 . 이것이 함수를 실행하는 기본 방법이 됩니다.오픈으로 전달PSSession
.
내 질문은 도대체 무엇이 잘못되었나요? ㅋㅋㅋ. 사용을 허용하지 않는 뒤에서 무슨 일이 벌어지고 있는 걸까요?P/호출떨어져서?
실제 기능은 다음과 같습니다.
Function Get-FolderSize ([parameter(Mandatory)][string]$Path) {
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace ProfileMethods
{
public class DirectorySum
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct WIN32_FIND_DATA
{
public uint dwFileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll")]
private static extern bool FindClose(IntPtr hFindFile);
public long GetFolderSize(string path)
{
long size = 0;
List<string> dirList = new List<string>();
WIN32_FIND_DATA fileData;
IntPtr hFile = FindFirstFile(path + @"\*.*", out fileData);
if (hFile != IntPtr.Zero)
{
do
{
if (fileData.cFileName == "." || fileData.cFileName == "..")
{
continue;
}
string fullPath = path + @"\" + fileData.cFileName;
if ((fileData.dwFileAttributes & 0x10) == 0x10)
{
dirList.Add(fullPath);
}
else
{
size += ((long)fileData.nFileSizeHigh * (long)uint.MaxValue + (long)fileData.nFileSizeLow);
}
} while (FindNextFile(hFile, out fileData));
FindClose(hFile);
foreach (string dir in dirList)
{
size += GetFolderSize(dir);
}
}
return size;
}
}
}
"@
$program = [ProfileMethods.DirectorySum]::new()
switch ($program.GetFolderSize($Path))
{
{$_ -lt 1GB} { '{0}MB' -f [math]::Round($_/1MB,2); Continue }
{$_ -gt 1GB -and $_ -lt 1TB} { '{0}GB' -f [math]::Round($_/1GB,2); Continue }
{$_ -gt 1TB} { '{0}TB' -f [math]::Round($_/1TB,2); Continue }
}
}
편집하다:업데이트- 따라서 하위 폴더에서는 작동하지만 루트 폴더에서는 작동하지 않습니다. 예:
$path = 'C:\Users\Abraham\Desktop' #works
Invoke-Command -ScriptBlock ${Function:Get-FolderSize} -ArgumentList $path -ComputerName $env:COMPUTERNAME
...작동하지만 루트 폴더는 C:\Users\Abraham
작동하지 않습니다.
메모:UNC 경로를 함수/메서드에 전달하면 작동합니다.
답변1
아무것도 조사하지 않았으므로 정확한 답변을 제공할 정보가 거의 없기 때문에 이는 추측입니다.
그러나 루트 폴더 C:\Users\Abraham은 그렇지 않습니다.
if ((fileData.dwFileAttributes & 0x10) == 0x10)
최신 Windows 시스템에서는 여기서 추가 확인이 필요할 수 있습니다.재분석 포인트,이는 다양한 유형(symlink, 접합, 탑재 지점, OneDrive 자리 표시자...)으로 제공되며 "ReparsePoint" 플래그(0x400) 외에 "Directory" 플래그를 가질 수도 있습니다.
특히 Vista에서는 이전 "~\Local 설정" 디렉터리를 ~\AppData\Local로 이동했기 때문에 호환성을 위해 "~\AppData\Local\Application Data"에 디렉터리 접합을 배치합니다. 이 디렉터리는... 동일한 " ~\AppData\로컬".
접합은 심볼릭 링크보다 약간 더 특별하며 자체 ACL을 가질 수 있으므로 일반적으로 이 접합에는 작업을 중지하는 Deny ACE가 있습니다 FindFirstFile(@"Application Data\*.*")
(즉, 알려진 경로에 대한 직접 액세스만 허용합니다). 그러나 ACL이 재설정된 경우 AppData의 콘텐츠를 열거하려는 모든 프로그램은 결국 무한 루프를 따라가며 동일한 교차점으로 영원히 내려갑니다(경로 길이 제한을 초과할 때까지).
FindFirstFile(path + @"\*.*", out fileData);
파일 이름에 를 포함할 필요는 없다는 점을 기억하십시오 .
. FindFirstFile()은 "8.3 filename.ext" 시대에 여전히 멈춰 있는 프로그램을 돕기 위해 의도적으로 이 작업(빈 문자열 일치를 허용함으로써 .*
)을 수행하지만 자체 와일드카드 확장을 구현하는 프로그램의 경우에는 해당되지 않습니다.