
それを邪魔にならないようにするために:これには次のようなさまざまな方法があることは理解していますGet-ChildItem
。
そこで、PowerShell コマンドレットのオーバーヘッドの一部と .Net クラスを取り除くために、カスタム クラスを定義しています。関数はローカルでは問題なく実行されますが、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
言うまでもなく、aもPSSession
機能しません。これが関数を実行する主な方法になります。オープンに渡す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システムでは、ここで追加のチェックが必要になる場合があります。注意すべき点は次のとおりです。再解析ポイント、さまざまなタイプ (シンボリックリンク、ジャンクション、マウント ポイント、OneDrive プレースホルダーなど) があり、「ReparsePoint」フラグ (0x400) に加えて「Directory」フラグを持つ場合もあります。
特に、Vista では古い「~\Local Settings」ディレクトリが ~\AppData\Local に移動されたため、互換性のために「~\AppData\Local\Application Data」にディレクトリ ジャンクションが配置され、同じ「~\AppData\Local」を指すようになります。
ジャンクションはシンボリックリンクよりも少し特殊で、独自の ACL を持つことができるため、通常、このジャンクションには、実行を阻止する Deny ACE がありますFindFirstFile(@"Application Data\*.*")
(つまり、既知のパスへの直接アクセスのみを許可します)。ただし、ジャンクションの ACL がリセットされた場合、AppData の内容を列挙しようとするプログラムは、無限ループに陥り、パスの長さの制限に達するまで、同じジャンクションに永遠に陥ります。
FindFirstFile(path + @"\*.*", out fileData);
ファイル名には が含まれている必要がないことに注意してください.
。FindFirstFile() は、.*
まだ「8.3 filename.ext」時代にとどまっているプログラムを支援するために、意図的にこれを機能させます (空の文字列に一致できるようにすることで)。ただし、独自のワイルドカード拡張を実装しているプログラムの場合はそうではありません。