I've recently gotten around to using runspaces
, but I've a wall of sorts.
I had this little script where one of the functions sets clipboard to a predefined text.
When run in default runspace it works perfectly. As soon as I placed the script in a runspace, it fails to execute the way I want. I assume that each runspace has its own clipboard. Is there a way to interact with default runspace clipboard from within another one or call a function outside runspace from within it?
In PowerShell 7+ something like this would work out of the box:
$ps = [powershell]::Create().AddScript{
Set-Clipboard 'foo bar baz'
Start-Sleep 5
}
$async = $ps.BeginInvoke()
$ps.EndInvoke($async)
$ps.Dispose()
(Get-Clipboard) -eq 'foo bar baz' # True
In Windows PowerShell its a bit more trickier, you must use a Runspace
setting the Runspace.ApartmentState
Property to STA
:
$rs = [runspacefactory]::CreateRunspace()
$rs.ApartmentState = [System.Threading.ApartmentState]::STA
$rs.Open()
$ps = [powershell]::Create().AddScript{
Set-Clipboard 'foo bar baz'
Start-Sleep 5
}
$ps.Runspace = $rs
$async = $ps.BeginInvoke()
$ps.EndInvoke($async)
$ps, $rs | ForEach-Object Dispose
(Get-Clipboard) -eq 'foo bar baz' # True
Inspecting the Error
stream before disposing can always give you a good hint of what could've gone wrong, i.e. using Clipboard.SetText
method if not using STA we would get this error:
Exception calling "SetText" with "1" argument(s): "Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it."
Same goes for Set-Clipboard
which uses the same API, different method, behind the scenes:
Message : Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure
that your Main function has STAThreadAttribute marked on it.
Data : {}
InnerException :
TargetSite : Void SetDataObject(System.Object, Boolean, Int32, Int32)
StackTrace : at System.Windows.Forms.Clipboard.SetDataObject(Object data, Boolean copy, Int32 retryTimes, Int32
retryDelay)
at Microsoft.PowerShell.Commands.SetClipboardCommand.SetClipboardContent(List`1 contentList,
Boolean append, Boolean asHtml)
at Microsoft.PowerShell.Commands.SetClipboardCommand.EndProcessing()
at System.Management.Automation.CommandProcessorBase.Complete()
HelpLink :
Source : System.Windows.Forms
HResult : -2146233056