¿No se permite ejecutar de forma remota las clases definidas a través de P/Invoke?

¿No se permite ejecutar de forma remota las clases definidas a través de P/Invoke?

Para sacarlo del camino:Entiendo que hay diferentes maneras de hacerlo, como por ejemplo Get-ChildItem.

Entonces, tengo una clase personalizada que estoy definiendo para deshacerme de algunos de los cmdlets generales de PowerShell, así como algunas clases .Net. La función se ejecutará bien localmente, pero tan pronto como intente usarla como definición de bloque de script en Invoke-Commanduna computadora remota, simplemente se bloqueará;incluso si lo invoco contra mi propia computadora. Hay un proceso que se crea para unComplemento WinRMeso se muestra en el Administrador de tareas pero eso es todo. Aquí hay algunos ejemplos de trabajo:

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

Como se muestra arriba, esto funcionará bien y devolverá la suma de todos los archivos. Luego, cuando paso el nombre de una computadora Invoke-Commandpara ejecución remota, simplemente se cuelga:

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

No hace falta decir que a PSSessiontampoco funciona; este será el método principal para ejecutar la función:pasándolo a un abiertoPSSession.

Mi pregunta es, ¿qué diablos pasa? jajaja. ¿Hay algo detrás de escena que no permitirá el uso deP/Invocarremotamente?

Aquí está la función real:

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

EDITAR:Actualizar- Entonces, funciona en subcarpetas, pero no en la carpeta raíz. Ejemplo:

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

...funciona, pero la carpeta raíz C:\Users\Abrahamno.


Nota:Pasar la ruta UNC a la función/método funcionará.

Respuesta1

Esto es una suposición porque no has intentado investigar nada, por lo que no hay suficiente información para proporcionar una respuesta precisa.

pero la carpeta raíz C:\Users\Abraham no.

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

Los sistemas Windows modernos pueden necesitar comprobaciones adicionales aquí; debe prestar atención apuntos de análisis,que vienen en varios tipos (enlaces simbólicos, uniones, puntos de montaje, marcadores de posición de OneDrive...) y también pueden tener el indicador "Directorio" además del indicador "ReparsePoint" (que es 0x400).

En particular, como Vista movió el antiguo directorio "~\Local Settings" a ~\AppData\Local, por compatibilidad coloca una unión de directorio en "~\AppData\Local\Application Data" que apunta... de nuevo al mismo " ~\AppData\Local".

Los cruces son un poco más especiales que los enlaces simbólicos y pueden tener sus propias ACL, por lo que normalmente este cruce tendrá un Deny ACE que le impedirá hacerlo FindFirstFile(@"Application Data\*.*")(es decir, solo permitirá el acceso directo a rutas conocidas). Pero si alguna vez se restablecen las ACL, cualquier programa que intente enumerar el contenido de AppData terminará siguiendo un bucle infinito, descendiendo al mismo cruce para siempre (hasta que se agote el límite de longitud de la ruta).

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

Recuerde que no es necesario que los nombres de archivos contengan un .símbolo. FindFirstFile() hace que esto funcione deliberadamente (al permitir hacer .*coincidir una cadena vacía) para ayudar a los programas que aún están atrapados en la era "8.3 filename.ext", pero ese no será el caso para los programas que implementen su propia expansión comodín.

información relacionada