Convierta un script pequeño de PS en una línea larga en un archivo .BATch

Tengo este código de PowerShell que obtuve de la respuesta a esta pregunta ; muestra la ubicación / dimensiones de la ventana cmd.exe donde se ejecuta el código PS:

$WindowFunction,$RectangleStruct = Add-Type -MemberDefinition @' [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } '@ -Name "type$([guid]::NewGuid() -replace '-')" -PassThru $MyWindowHandle = (Get-Process -Id (Get-WmiObject Win32_Process -Filter "ProcessId=$PID").ParentProcessId).MainWindowHandle $WindowRect = New-Object -TypeName $RectangleStruct.FullName $null = $WindowFunction::GetWindowRect($MyWindowHandle,[ref]$WindowRect) Write-Host $WindowRect.Left $WindowRect.Top $WindowRect.Right $WindowRect.Bottom 

Cuando ejecuto este código en un script .ps1 desde la línea de comandos, funciona correctamente:

 C:\Users\Antonio\Documents\test> powershell Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process; .\test.ps1 26 -7 943 738 

Quiero insertar este código en un archivo .BATch para no tener un archivo .ps1 separado, así que debo escribir el mismo código en una línea larga como parámetros para el comando de powershell . Sin embargo, para mantener la legibilidad, quiero usar líneas separadas en el archivo .bat y terminar cada una con el carácter de continuación de lote ^ ; Este fue mi primer bash:

 @echo off PowerShell ^ $WindowFunction,$RectangleStruct = Add-Type -MemberDefinition '^ [DllImport("user32.dll", SetLastError = true)] ^ [return: MarshalAs(UnmanagedType.Bool)] ^ public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); ^ [StructLayout(LayoutKind.Sequential)] ^ public struct RECT ^ { ^ public int Left; ^ public int Top; ^ public int Right; ^ public int Bottom; ^ } ^ ' -Name "type$([guid]::NewGuid() -replace '-')" -PassThru; ^ $MyWindowHandle = (Get-Process -Id (Get-WmiObject Win32_Process -Filter "ProcessId=$PID").ParentProcessId).MainWindowHandle; ^ $WindowRect = New-Object -TypeName $RectangleStruct.FullName; ^ $null = $WindowFunction::GetWindowRect($MyWindowHandle,[ref]$WindowRect); ^ Write-Host $WindowRect.Left $WindowRect.Top $WindowRect.Right $WindowRect.Bottom %End PowerShell% 

Cuando ejecuto este archivo por lotes, se informan varios errores:

 C:\Users\Antonio\Documents\test> test.bat Add-Type : c:\Users\Antonio\AppData\Local\Temp\yhd4ckqv.0.cs(8) : El nombre 'user32' no existe en el contexto actual c:\Users\Antonio\AppData\Local\Temp\yhd4ckqv.0.cs(7) : { c:\Users\Antonio\AppData\Local\Temp\yhd4ckqv.0.cs(8) : >>> [DllImport(user32.dll, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } c:\Users\Antonio\AppData\Local\Temp\yhd4ckqv.0.cs(9) : En línea: 1 Carácter: 36 + $WindowFunction,$RectangleStruct = Add-Type -MemberDefinition ' [DllImport(user3 ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ + CategoryInfo : InvalidData: (c:\Users\Antoni...contexto actual: CompilerError) [Add-Type], Exception + FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands. AddTypeCommand Add-Type : No se puede agregar el tipo. Hubo errores de comstackción. En línea: 1 Carácter: 36 + $WindowFunction,$RectangleStruct = Add-Type -MemberDefinition ' [DllImport(user3 ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ and a long et cetera.... 

Traté de pasar el apóstrofo a la línea de abajo, cambié los apóstrofos por comillas y viceversa, eliminé espacios adicionales al principio de cada línea y varias otras modificaciones, pero no encontré la manera correcta de escribir este código. Escribí varios segmentos de código PS antes mucho más grandes que este de la misma manera sin ningún problema. Aunque soy un progtwigdor experimentado, soy un novato de PowerShell y sus múltiples idiosincrasias siempre me han confundido …

¿Cuál es la forma correcta de escribir este código de PS en un archivo por lotes? Lo agradeceré si también se incluye una explicación simple de la causa del problema …

Los literales de comillas dobles deben escaparse como \"

 @echo off PowerShell^ $WindowFunction,$RectangleStruct = Add-Type -MemberDefinition '^ [DllImport(\"user32.dll\", SetLastError = true)]^ [return: MarshalAs(UnmanagedType.Bool)]^ public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);^ [StructLayout(LayoutKind.Sequential)]^ public struct RECT^ {^ public int Left;^ public int Top;^ public int Right;^ public int Bottom;^ }^ ' -Name \"type$([guid]::NewGuid() -replace '-')\" -PassThru;^ $MyWindowHandle = (Get-Process -Id (^ Get-WmiObject Win32_Process -Filter \"ProcessId=$PID\"^ ).ParentProcessId).MainWindowHandle;^ $WindowRect = New-Object -TypeName $RectangleStruct.FullName;^ $null = $WindowFunction::GetWindowRect($MyWindowHandle,[ref]$WindowRect);^ Write-Host $WindowRect.Left $WindowRect.Top $WindowRect.Right $WindowRect.Bottom 

Hubo un tema en DosTips hace un tiempo que abordó esto. Puede hacer un híbrido por lotes / Powershell con un encabezado simple:

 <# : :: Header to create Batch/PowerShell hybrid @echo off setlocal set "POWERSHELL_BAT_ARGS=%*" if defined POWERSHELL_BAT_ARGS set "POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%" endlocal & powershell -NoLogo -NoProfile -Command "$_ = $input; Invoke-Expression $( '$input = $_; $_ = \"\"; $args = @( &{ $args } %POWERSHELL_BAT_ARGS% );' + [String]::Join( [char]10, $( Get-Content \"%~f0\" ) ) )" :: Any batch code that gets run after your PowerShell goes here goto :EOF #> 

Simplemente arroje su código de Powershell después del #> y guarde el archivo como un script .bat. En tu caso:

 <# : :: Header to create Batch/PowerShell hybrid @echo off setlocal set "POWERSHELL_BAT_ARGS=%*" if defined POWERSHELL_BAT_ARGS set "POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%" endlocal & powershell -NoLogo -NoProfile -Command "$_ = $input; Invoke-Expression $( '$input = $_; $_ = \"\"; $args = @( &{ $args } %POWERSHELL_BAT_ARGS% );' + [String]::Join( [char]10, $( Get-Content \"%~f0\" ) ) )" goto :EOF #> $WindowFunction,$RectangleStruct = Add-Type -MemberDefinition @' [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } '@ -Name "type$([guid]::NewGuid() -replace '-')" -PassThru $MyWindowHandle = (Get-Process -Id (Get-WmiObject Win32_Process -Filter "ProcessId=$PID").ParentProcessId).MainWindowHandle $WindowRect = New-Object -TypeName $RectangleStruct.FullName $null = $WindowFunction::GetWindowRect($MyWindowHandle,[ref]$WindowRect) Write-Host $WindowRect.Left $WindowRect.Top $WindowRect.Right $WindowRect.Bottom 

Me gustaría ir por la opción -EncodedCommand aquí. Simplemente Base64 codifica todo el script de powershell y luego pasa la cadena Base64 como argumento a powershell.exe :

(suponiendo que el script esté aquí: C:\Path\To\Script.ps1 )

 PS C:\> $ScriptText = Get-Content C:\Path\To\Script.ps1 -Raw PS C:\> $ScriptBytes = [System.Text.Encoding]::Unicode.GetBytes($ScriptText) PS C:\> $EncCommand = [System.Convert]::ToBase64String($ScriptBytes) 

$EncCommand ahora contiene el comando codificado Base64, listo para usar dentro de cmd.exe (o su archivo por lotes para el caso):

 C:\>powershell -EncodedCommand JABXAGkAbgBkAG8AdwBGAHUAbgBjAHQAaQBvAG4ALAAkAFIAZQBjAHQAYQBuAGcAbABlAFMAdAByAHUAYwB0ACAAPQAgAEEAZABkAC0AVAB5A HAAZQAgAC0ATQBlAG0AYgBlAHIARABlAGYAaQBuAGkAdABpAG8AbgAgAEAAJwANAAoAWwBEAGwAbABJAG0AcABvAHIAdAAoACIAdQBzAGUAcgAzADIALgBkAGwAbAAiACwAIABTAGUAd ABMAGEAcwB0AEUAcgByAG8AcgAgAD0AIAB0AHIAdQBlACkAXQANAAoAWwByAGUAdAB1AHIAbgA6ACAATQBhAHIAcwBoAGEAbABBAHMAKABVAG4AbQBhAG4AYQBnAGUAZABUAHkAcABlA C4AQgBvAG8AbAApAF0ADQAKAHAAdQBiAGwAaQBjACAAcwB0AGEAdABpAGMAIABlAHgAdABlAHIAbgAgAGIAbwBvAGwAIABHAGUAdABXAGkAbgBkAG8AdwBSAGUAYwB0ACgASQBuAHQAU AB0AHIAIABoAFcAbgBkACwAIAByAGUAZgAgAFIARQBDAFQAIABsAHAAUgBlAGMAdAApADsADQAKAFsAUwB0AHIAdQBjAHQATABhAHkAbwB1AHQAKABMAGEAeQBvAHUAdABLAGkAbgBkA C4AUwBlAHEAdQBlAG4AdABpAGEAbAApAF0ADQAKAHAAdQBiAGwAaQBjACAAcwB0AHIAdQBjAHQAIABSAEUAQwBUAA0ACgB7AA0ACgAgACAAIAAgAHAAdQBiAGwAaQBjACAAaQBuAHQAI ABMAGUAZgB0ADsADQAKACAAIAAgACAAcAB1AGIAbABpAGMAIABpAG4AdAAgAFQAbwBwADsADQAKACAAIAAgACAAcAB1AGIAbABpAGMAIABpAG4AdAAgAFIAaQBnAGgAdAA7AA0ACgAgA CAAIAAgAHAAdQBiAGwAaQBjACAAaQBuAHQAIABCAG8AdAB0AG8AbQA7AA0ACgB9AA0ACgAnAEAAIAAtAE4AYQBtAGUAIAAiAHQAeQBwAGUAJAAoAFsAZwB1AGkAZABdADoAOgBOAGUAd wBHAHUAaQBkACgAKQAgAC0AcgBlAHAAbABhAGMAZQAgACcALQAnACkAIgAgAC0AUABhAHMAcwBUAGgAcgB1AA0ACgANAAoAJABNAHkAVwBpAG4AZABvAHcASABhAG4AZABsAGUAIAA9A CAAKABHAGUAdAAtAFAAcgBvAGMAZQBzAHMAIAAtAEkAZAAgACgARwBlAHQALQBXAG0AaQBPAGIAagBlAGMAdAAgAFcAaQBuADMAMgBfAFAAcgBvAGMAZQBzAHMAIAAtAEYAaQBsAHQAZ QByACAAIgBQAHIAbwBjAGUAcwBzAEkAZAA9ACQAUABJAEQAIgApAC4AUABhAHIAZQBuAHQAUAByAG8AYwBlAHMAcwBJAGQAKQAuAE0AYQBpAG4AVwBpAG4AZABvAHcASABhAG4AZABsA GUADQAKAA0ACgAkAFcAaQBuAGQAbwB3AFIAZQBjAHQAIAA9ACAATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAJABSAGUAYwB0AGEAbgBnAGwAZQBTAHQAc gB1AGMAdAAuAEYAdQBsAGwATgBhAG0AZQANAAoAJABuAHUAbABsACAAPQAgACQAVwBpAG4AZABvAHcARgB1AG4AYwB0AGkAbwBuADoAOgBHAGUAdABXAGkAbgBkAG8AdwBSAGUAYwB0A CgAJABNAHkAVwBpAG4AZABvAHcASABhAG4AZABsAGUALABbAHIAZQBmAF0AJABXAGkAbgBkAG8AdwBSAGUAYwB0ACkADQAKAA0ACgBXAHIAaQB0AGUALQBIAG8AcwB0ACAAJABXAGkAb gBkAG8AdwBSAGUAYwB0AC4ATABlAGYAdAAgACQAVwBpAG4AZABvAHcAUgBlAGMAdAAuAFQAbwBwACAAJABXAGkAbgBkAG8AdwBSAGUAYwB0AC4AUgBpAGcAaAB0ACAAJABXAGkAbgBkA G8AdwBSAGUAYwB0AC4AQgBvAHQAdABvAG0A 100 -2 1257 748