Dürfen über P/Invoke definierte Klassen nicht remote ausgeführt werden?

Dürfen über P/Invoke definierte Klassen nicht remote ausgeführt werden?

Um es gleich klarzustellen:Mir ist bewusst, dass es hierfür verschiedene Möglichkeiten gibt, wie zum Beispiel Get-ChildItem.

Ich definiere also eine benutzerdefinierte Klasse, um den Overhead einiger PowerShell-Cmdlets und einiger .Net-Klassen zu beseitigen. Die Funktion läuft lokal einwandfrei, aber sobald ich versuche, sie als Skriptblockdefinition auf Invoke-Commandeinem Remotecomputer zu verwenden, bleibt sie einfach hängen.selbst wenn ich es gegen meinen eigenen Computer anwendeEs gibt einen Prozess, der für eineWinRM-PluginDas wird im Task-Manager angezeigt, aber das ist alles. Hier sind einige funktionierende Beispiele:

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

Wie oben gezeigt funktioniert das einwandfrei und gibt die Summe aller Dateien zurück. Wenn ich dann einen Computernamen Invoke-Commandzur Remote-Ausführung übergebe, bleibt es einfach hängen:

Invoke-Command -ScriptBlock ${Function:Get-FolderSize} -ArgumentList C:\Users\Abraham -ComputerName $env:COMPUTERNAME

Es versteht sich von selbst, dass a PSSessionauch nicht funktioniert. Dies wird die primäre Methode zum Ausführen der Funktion sein -Weitergabe an ein offenesPSSession.

Meine Frage ist, was zum Teufel ist los? lol. Geht hinter den Kulissen etwas vor sich, das die Verwendung vonP/Aufrufenaus der Ferne?

Hier ist die eigentliche Funktion:

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

BEARBEITEN:Aktualisieren- Es funktioniert also bei Unterordnern, aber nicht beim Stammordner. Beispiel:

$path = 'C:\Users\Abraham\Desktop' #works
Invoke-Command -ScriptBlock ${Function:Get-FolderSize} -ArgumentList $path -ComputerName $env:COMPUTERNAME

...funktioniert, aber der Stammordner C:\Users\Abrahamnicht.


Notiz:Die Übergabe des UNC-Pfads an die Funktion/Methode funktioniert.

Antwort1

Dies ist eine Vermutung, da Sie nicht versucht haben, Nachforschungen anzustellen und daher bei weitem nicht genügend Informationen vorhanden sind, um eine genaue Antwort zu geben.

Der Stammordner C:\Users\Abraham ist jedoch nicht vorhanden.

if ((fileData.dwFileAttributes & 0x10) == 0x10)

Moderne Windows-Systeme benötigen hier möglicherweise zusätzliche Überprüfungen – achten Sie dabei aufAnalysepunkte,die in verschiedenen Typen vorkommen (symlogische Links, Junctions, Einhängepunkte, OneDrive-Platzhalter...) und neben dem Flag „ReparsePoint“ (das 0x400 ist) auch das Flag „Directory“ haben können.

Insbesondere da Vista das alte Verzeichnis „~\Local Settings“ nach ~\AppData\Local verschoben hat, wird aus Kompatibilitätsgründen bei „~\AppData\Local\Application Data“ eine Verzeichnisverknüpfung eingefügt, die... zurück auf dasselbe „~\AppData\Local“ verweist.

Junctions sind etwas spezieller als Symlinks und können ihre eigenen ACLs haben, sodass diese Junction normalerweise einen Deny ACE hat, der Sie daran hindert FindFirstFile(@"Application Data\*.*")(d. h. sie erlaubt nur den direkten Zugriff auf bekannte Pfade). Wenn die ACLs darauf jedoch jemals zurückgesetzt wurden, gerät jedes Programm, das versucht, den Inhalt von AppData aufzulisten, in eine Endlosschleife und landet für immer in derselben Junction (bis die Pfadlängenbeschränkung überschritten ist).

FindFirstFile(path + @"\*.*", out fileData);

Denken Sie daran, dass Dateinamen kein Platzhalterzeichen enthalten müssen .. FindFirstFile() ermöglicht dies absichtlich (indem es .*die Übereinstimmung mit einer leeren Zeichenfolge ermöglicht), um Programmen zu helfen, die noch in der Ära „8.3 filename.ext“ stecken geblieben sind. Dies gilt jedoch nicht für Programme, die ihre eigene Platzhaltererweiterung implementieren.

verwandte Informationen