Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically Removing a PowerShell Job when it has finished (asynchronously)

I have a PowerShell cmdlet which I use to simplify connecting to another computer with RDP.

Within that cmdlet I run do the following:

    if ($null -ne $Username -and $null -ne $Password) {
        Start-Process -FilePath "cmdkey.exe" -ArgumentList @("/generic:`"TERMSRV/$ComputerName`"", "/user:`"$Username`"", "/pass:`"$Password`"") -WindowStyle Hidden
    }

    Start-Job -ScriptBlock {
        param($InstallPath, $ComputerName, $Port, $Username, $Password)

        $arguments = @("`"$(Join-Path $InstallPath '\Support Files\MSTSC\Default.rdp')`"")
        if ($null -ne $Port) {
            $arguments += "/v:`"$($ComputerName):$($Port)`""
        } else {
            $arguments += "/v:`"$($ComputerName)`""
        }

        Start-Process -FilePath "mstsc.exe" -ArgumentList $arguments -Wait

        if ($null -ne $Username -and $null -ne $Password) {
            Start-Process -FilePath "cmdkey.exe" -ArgumentList @("/delete:`"TERMSRV/$ComputerName`"") -WindowStyle Hidden
        }
    } -ArgumentList @($InstallPath, $ComputerName, $Port, $Username, $Password)

As you can see I add the credentials used to connect to the remote machine, then start a job which executes mstsc.exe, waits for it to finish then removes the credentials.

The problem is I have to wait for mstsc to close before deleting the credentials, as otherwise they get removed before mstsc has a chance to establish the connection and I want this cmdlet to be self contained - returning control immediately to the users command prompt so I can run other commands while I am also using the RDP session which means I can't wait for the job to finish as that mean I am stuck waiting until I disconnect from the remote session:

| Wait-Job | Remove-Job

What I want to do is to be able to Remove-Job once it has completed, perhaps using some kind of callback so I don't have to manually run another command to clean up the Job once I log out of the RDP session and the Job isn't left in a Completed state (which is what I am currently doing but obviously this isn't 'clean).

For the full cmdlet you can see it here for more context:

https://github.com/paulmarsy/Console/blob/master/AdvancedPowerShellConsole/Exports/Functions/Connect-Remote.ps1

like image 460
Paul Avatar asked Oct 20 '22 01:10

Paul


2 Answers

I know this is a very old question... You can use Register-ObjectEvent to clean up after jobs. Jobs have a StateChanged event that has an EventSubscriber parameter passed to it containing details of the event and the source job.

Here's an example. Once the job completes the callback will remove both itself and the source job.

$job = Start-Job { Start-Sleep -Seconds 2 }
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
    Unregister-Event $EventSubscriber.SourceIdentifier
    Remove-Job $EventSubscriber.SourceIdentifier
    Remove-Job -Id $EventSubscriber.SourceObject.Id
} | Out-Null
like image 154
antonyoni Avatar answered Oct 24 '22 00:10

antonyoni


So register a scheduledjob to run in 5 minutes that will remove the completed job. I am pretty sure that you can do something like:

Register-ScheduledJob -ScriptBlock {param($computername); Wait-Job -Name $ComputerName|remove-job} -Trigger @{Frequency="Once";At=(get-date).AddMinutes(5).ToString("h:MM tt")} -argumentlist $computername

Then just give your connection a name when you do your Start-Job by appending -Name $ComputerName to the end of the command. That way 5 minutes after you launch it a scheduled task kicks off that finds and clears out that job by name.

like image 34
TheMadTechnician Avatar answered Oct 24 '22 01:10

TheMadTechnician