Created
March 9, 2021 20:30
-
-
Save mgraeber-rc/da0f9966b56ae25daa5f0790f032d1ec to your computer and use it in GitHub Desktop.
A simple CreateProcess wrapper for demonstrating starting a process with custom command-line arguments.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Start-ProcessWithCommandLine { | |
<# | |
.SYNOPSIS | |
A simple CreateProcess wrapper for demonstrating starting a process with custom command-line arguments. | |
Author: Matt Graeber | |
Company: Red Canary, Inc. | |
.PARAMETER ApplicationName | |
Specifies the path to the executable to start. | |
.PARAMETER CommandLine | |
Specifies a custom command-line for the application. | |
.EXAMPLE | |
Start-ProcessWithCommandLine | |
Starts a notepad.exe process with a "CustomCommandLineTest" command-line. | |
.EXAMPLE | |
Start-ProcessWithCommandLine -ApplicationName "$Env:windir\System32\WindowsPowerShell\v1.0\powershell.exe" -CommandLine 'Foo' | |
#> | |
param ( | |
[Parameter(Position = 0)] | |
[String] | |
[ValidateNotNullOrEmpty()] | |
$ApplicationName = "$Env:windir\System32\notepad.exe", | |
[Parameter(Position = 0)] | |
[String] | |
[ValidateNotNullOrEmpty()] | |
$CommandLine = 'CustomCommandLineTest' | |
) | |
$Source = @' | |
using System; | |
using System.Runtime.InteropServices; | |
using Microsoft.Win32.SafeHandles; | |
namespace CommandLineTest { | |
public class NativeMethods { | |
[StructLayout(LayoutKind.Sequential)] | |
public class PROCESS_INFORMATION | |
{ | |
public IntPtr hProcess = IntPtr.Zero; | |
public IntPtr hThread = IntPtr.Zero; | |
public int dwProcessId; | |
public int dwThreadId; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public class STARTUPINFO | |
{ | |
public int cb; | |
public IntPtr lpReserved; | |
public IntPtr lpDesktop; | |
public IntPtr lpTitle; | |
public int dwX; | |
public int dwY; | |
public int dwXSize; | |
public int dwYSize; | |
public int dwXCountChars; | |
public int dwYCountChars; | |
public int dwFillAttribute; | |
public int dwFlags; | |
public short wShowWindow; | |
public short cbReserved2; | |
public IntPtr lpReserved2; | |
public IntPtr hStdInput; | |
public IntPtr hStdOutput; | |
public IntPtr hStdError; | |
} | |
[DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)] | |
public static extern bool CreateProcess( | |
string lpApplicationName, | |
string lpCommandLine, | |
IntPtr lpProcessAttributes, | |
IntPtr lpThreadAttributes, | |
bool bInheritHandles, | |
int dwCreationFlags, | |
IntPtr lpEnvironment, | |
string lpCurrentDirectory, | |
STARTUPINFO lpStartupInfo, | |
PROCESS_INFORMATION lpProcessInformation); | |
} | |
} | |
'@ | |
if (-not ('CommandLineTest.NativeMethods' -as [Type])) { | |
Add-Type -TypeDefinition $Source | |
} | |
$StartupInfo = New-Object -TypeName CommandLineTest.NativeMethods+STARTUPINFO | |
$StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][CommandLineTest.NativeMethods+STARTUPINFO]) | |
$ProcessInformation = New-Object -TypeName CommandLineTest.NativeMethods+PROCESS_INFORMATION | |
$Result = [CommandLineTest.NativeMethods]::CreateProcess( | |
$ApplicationName, # lpApplicationName | |
$CommandLine, # lpCommandLine | |
[IntPtr]::Zero, # lpProcessAttributes | |
[IntPtr]::Zero, # lpThreadAttributes | |
$True, # bInheritHandles | |
0x10, # dwCreationFlags - CREATE_NEW_CONSOLE | |
[IntPtr]::Zero, # lpEnvironment | |
$PWD.Path, # lpCurrentDirectory | |
$StartupInfo, # lpStartupInfo | |
$ProcessInformation # lpProcessInformation | |
);$LastError = [ComponentModel.Win32Exception][Runtime.InteropServices.Marshal]::GetLastWin32Error() | |
if ($Result) { | |
$RunningProcessInfo = Get-CimInstance -ClassName Win32_Process -Property 'ExecutablePath', 'CommandLine' -Filter "ProcessId = $($ProcessInformation.dwProcessId)" | |
[PSCustomObject] @{ | |
ProcessId = $ProcessInformation.dwProcessId | |
ExecutablePath = $RunningProcessInfo.ExecutablePath | |
CommandLine = $RunningProcessInfo.CommandLine | |
} | |
} else { | |
Write-Error -Exception $LastError | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment