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?
Asked
Active
Viewed 77 times
1

Nawad-sama
- 151
- 2
- 12
-
As I see it, your sub-threads should interact with the main thread using a [Synchronized Hashtable](https://learn.microsoft.com/dotnet/api/system.collections.hashtable.synchronized) and your main thread should than update the clipboard. – iRon Feb 23 '23 at 10:02
-
I am aware of Synchronized Hashtbles, used then with GUI forms. What I don't understand how to do is how to initiate function based on hashtable value changed. Any ideas? – Nawad-sama Feb 23 '23 at 11:30
-
You might find some examples in [Powershell pass variable to start-job](https://stackoverflow.com/a/57281995/1701026) and [Access current PowerShell instance](https://stackoverflow.com/q/71141243/1701026). If that doesn't work for you, I suggest that you add the attempt to your question with more details about the specific issues and expectations. – iRon Feb 23 '23 at 12:12
1 Answers
1
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

Santiago Squarzon
- 41,465
- 5
- 14
- 37
-
1THIS IS GOLD. Solution and explanation in one. Added apartment state property and now it works. – Nawad-sama Feb 23 '23 at 13:46