diff --git a/Invoke-CommandAs/Private/Invoke-ScheduledTask.ps1 b/Invoke-CommandAs/Private/Invoke-ScheduledTask.ps1 index 48e205f..238a815 100644 --- a/Invoke-CommandAs/Private/Invoke-ScheduledTask.ps1 +++ b/Invoke-CommandAs/Private/Invoke-ScheduledTask.ps1 @@ -10,7 +10,8 @@ function Invoke-ScheduledTask { [Parameter(Mandatory = $false)][Switch]$AsSystem, [Parameter(Mandatory = $false)][String]$AsInteractive, [Parameter(Mandatory = $false)][String]$AsGMSA, - [Parameter(Mandatory = $false)][Switch]$RunElevated + [Parameter(Mandatory = $false)][Switch]$RunElevated, + [Parameter(Mandatory = $false)][Switch]$HideWindow ) @@ -79,6 +80,14 @@ function Invoke-ScheduledTask { Write-Verbose "$(Get-Date): ScheduledJob: Register" $ScheduledJob = Register-ScheduledJob @JobParameters -ScriptBlock $JobScriptBlock -ArgumentList $JobArgumentList -ErrorAction Stop + $ExecPath = $ScheduledJob.PSExecutionPath + $ExecArgs = $ScheduledJob.PSExecutionArgs + + if ($HideWindow) { + $ExecPath = "conhost.exe" + $ExecArgs = "--headless $($ScheduledJob.PSExecutionPath) $($ScheduledJob.PSExecutionArgs)" + } + If ($AsSystem -or $AsInteractive -or $AsUser -or $AsGMSA) { # Use ScheduledTask to execute the ScheduledJob to execute with the desired credentials. @@ -89,7 +98,7 @@ function Invoke-ScheduledTask { Write-Verbose "$(Get-Date): ScheduledTask: Register" $TaskParameters = @{ TaskName = $ScheduledJob.Name } - $TaskParameters['Action'] = New-ScheduledTaskAction -Execute $ScheduledJob.PSExecutionPath -Argument $ScheduledJob.PSExecutionArgs + $TaskParameters['Action'] = New-ScheduledTaskAction -Execute $ExecPath -Argument $ExecArgs $TaskParameters['Settings'] = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries If ($AsSystem) { $TaskParameters['Principal'] = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest @@ -125,8 +134,8 @@ function Invoke-ScheduledTask { $TaskDefinition = $ScheduleService.NewTask(0) $TaskDefinition.Principal.RunLevel = $RunElevated.IsPresent $TaskAction = $TaskDefinition.Actions.Create(0) - $TaskAction.Path = $ScheduledJob.PSExecutionPath - $TaskAction.Arguments = $ScheduledJob.PSExecutionArgs + $TaskAction.Path = $ExecPath + $TaskAction.Arguments = $ExecArgs If ($AsUser) { $Username = $AsUser.GetNetworkCredential().UserName diff --git a/Invoke-CommandAs/Public/Invoke-CommandAs.ps1 b/Invoke-CommandAs/Public/Invoke-CommandAs.ps1 index 6b79cc6..e0add2a 100644 --- a/Invoke-CommandAs/Public/Invoke-CommandAs.ps1 +++ b/Invoke-CommandAs/Public/Invoke-CommandAs.ps1 @@ -39,6 +39,13 @@ function Invoke-CommandAs { Type a user name, such as User01 or Domain01\User01. Or, enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, this cmdlet prompts you for a password. + + .PARAMETER HideWindow + + ScheduledJob will be executed with the special hack to ensure that no window is shown when the task is executed. + + This is done by using conhost.exe as the executable for the ScheduledTask, and passing the actual ScheduledJob as arguments to conhost.exe with the --headless flag. + #> #Requires -Version 3 @@ -294,7 +301,11 @@ function Invoke-CommandAs { [Parameter(Mandatory = $false)] [Alias("Elevated")] [switch] - ${RunElevated} + ${RunElevated}, + + [Parameter(Mandatory = $false)] + [switch] + ${HideWindow} ) @@ -304,7 +315,7 @@ function Invoke-CommandAs { # Collect all the parameters, and prepare them to be splatted to the Invoke-Command [hashtable]$CommandParameters = $PSBoundParameters - $ParameterNames = @('AsSystem', 'AsInteractive', 'AsUser', 'AsGMSA', 'RunElevated', 'FilePath','ScriptBlock', 'ArgumentList') + $ParameterNames = @('AsSystem', 'AsInteractive', 'AsUser', 'AsGMSA', 'RunElevated', 'HideWindow', 'FilePath','ScriptBlock', 'ArgumentList') ForEach ($ParameterName in $ParameterNames) { $CommandParameters.Remove($ParameterName) } @@ -366,6 +377,7 @@ function Invoke-CommandAs { If ($Using:AsInteractive) { $Parameters['AsInteractive'] = $Using:AsInteractive } If ($Using:AsGMSA) { $Parameters['AsGMSA'] = $Using:AsGMSA } If ($Using:RunElevated) { $Parameters['RunElevated'] = $Using:RunElevated } + If ($Using:HideWindow) { $Parameters['HideWindow'] = $Using:HideWindow } If ($Using:IsVerbose) { $Parameters['Verbose'] = $Using:IsVerbose } Invoke-ScheduledTask @Parameters @@ -394,6 +406,7 @@ function Invoke-CommandAs { If ($AsInteractive) { $Parameters['AsInteractive'] = $AsInteractive } If ($AsGMSA) { $Parameters['AsGMSA'] = $AsGMSA } If ($RunElevated) { $Parameters['RunElevated'] = $RunElevated.IsPresent } + If ($HideWindow) { $Parameters['HideWindow'] = $HideWindow.IsPresent } If ($IsVerbose) { $Parameters['Verbose'] = $IsVerbose } Invoke-ScheduledTask @Parameters diff --git a/README.md b/README.md index eb8aae0..8203676 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,9 @@ Invoke-CommandAs -ScriptBlock { Get-Process } -AsUser $Credential # Execute As Interactive session of another user. Invoke-CommandAs -ScriptBlock { Get-Process } -AsInteractive 'username' +# Execute without showing a console window. +Invoke-CommandAs -ScriptBlock { Get-Process } -AsInteractive 'username' -HideWindow + ``` ### You can execute all the same commands as above against a remote machine. ### Use -ComputerName/Credential or -Session to authenticate