Convertire un piccolo script PS in una lunga fila in un file .BATch

Ho questo codice PowerShell che ho ricevuto dalla risposta a questa domanda ; mostra la posizione / le dimensioni della finestra di cmd.exe in cui viene eseguito il codice 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 

Quando eseguo questo codice in uno script .ps1 dalla riga di comando, funziona correttamente:

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

Voglio inserire questo codice in un file .BATch per non avere un file .ps1 separato, quindi devo scrivere lo stesso codice in una lunga riga come parametri per il comando di powershell . Tuttavia, per mantenere la leggibilità, voglio usare righe separate nel file .bat e terminare ognuna con il carattere di continuazione Batch ^ ; questo era il mio primo tentativo:

 @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% 

Quando eseguo questo file Batch, vengono segnalati diversi errori:

 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 compilación. En línea: 1 Carácter: 36 + $WindowFunction,$RectangleStruct = Add-Type -MemberDefinition ' [DllImport(user3 ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ and a long et cetera.... 

Ho provato a passare l’apostrofo alla riga sottostante, ho cambiato gli apostrofi tra virgolette e viceversa, eliminato spazi aggiuntivi all’inizio di ogni riga e diverse altre modifiche, ma non sono riuscito a trovare il modo giusto per scrivere questo codice. Ho scritto diversi segmenti di codice PS prima molto più grandi di questo nello stesso modo senza problemi. Sebbene io sia un programmatore esperto, sono un principiante di PowerShell e le sue molteplici idiosincrasie mi hanno sempre confuso …

Qual è il modo giusto per scrivere questo codice PS in un file batch? Lo apprezzerò se è inclusa anche una semplice spiegazione della causa del problema …

I valori letterali dei doppi apici devono essere sottoposti a escape come \"

 @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 

C’è stato un argomento su DosTips qualche tempo fa che ha affrontato questo. È ansible creare un ibrido Powershell / batch con un’intestazione semplice:

 <# : :: 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 #> 

Basta lanciare il codice Powershell dopo il #> e salvare il file come normale script .bat. Nel tuo 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 

Vorrei andare per l’opzione -EncodedCommand qui. Basterà Base64 codificare l’intero script di PowerShell e quindi passare la stringa Base64 come argomento a powershell.exe :

(supponendo che lo script sia qui: 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 ora contiene il comando codificato Base64, pronto per l’uso in cmd.exe (o il tuo file batch):

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