Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@mgraeber-rc
Created March 9, 2021 20:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mgraeber-rc/da0f9966b56ae25daa5f0790f032d1ec to your computer and use it in GitHub Desktop.
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.
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