MartinGC94 / DisplayConfig

PowerShell module for configuring Windows display settings
MIT License
42 stars 2 forks source link

Copy-DisplaySource : The parameter is incorrect #6

Closed jmccaull closed 1 month ago

jmccaull commented 2 months ago

I'm trying to clone a display created for a HDMI sound bar to another, to prevent mousing over to it by accident. I thought I had this working at some point but I'm not sure now. I've tried tons of different combinations but I can't seem to get Copy-DisplaySource to work at all. From powershell 5 and 7, running: "Copy-DisplaySource -DisplayId 3 -DestinationDisplayId 1" gives the error. Here is my DisplayInfo:

 DisplayId DisplayName      Active  Primary Position    Mode                  ConnectionType
 --------- -----------      ------  ------- --------    ----                  --------------
         1 VIZIO              True    False -1920 0     1920x1080@59.9400...            HDMI
         2 U28E590            True     True 0 0         3840x2160@60 Hz                  DVI
         3 HP 2311            True    False 3840 0      1920x1080@60 Hz                  DVI
         4 SAMSUNG            True    False -5760 0     3840x2160@60 Hz                 HDMI

Any help would be appreciated, thanks!

MartinGC94 commented 2 months ago

Interesting that it reports display 2 and 3 as using DVI (I assume you are not using DVI on these displays). Can you tell me what connection type you are using for each of your displays?

Assuming you can do it manually in the display settings app, can you send me a copy of your displayconfig with your current configuration and then manually change it in the settings app and make a new copy of your displayconfig?

You can export the config like this: Get-DisplayConfig | Export-Clixml -Path $HOME\Desktop\DisplaysBefore.xml just attach both files here and I'll take a look.

jmccaull commented 2 months ago

The sound bar, Vizio, is plugging into my mothboard's hdmi slot, the SAMSUNG is a tv plugging into my graphics card's only hdmi slot, U28E590 is a Samsung monitor plugged into the graphics card with a displayport to hdmi adapter and the hp is the only one using DVI but it's a displayport to DVI cable again from the card. Initially the vizio was being reported as SAMSUNG as well, but I reinstalled some drivers and now its showing up fine. DisplayXML.zip

Yes I can set everything up manually.

MartinGC94 commented 2 months ago

Your after config shows that you are cloning display 3 and 4 (HP and the Samsung) but your initial post said that you were trying to clone from 3 -> 1 (HP and Vizio). Can you check again if the GUI lets you clone from 3 -> 1? I suspect the API won't let you clone from one display adapter to another and that's what you are trying to do in the code, but in the GUI you've stayed on the same adapter.

I unfortunately only have computers with a single graphics adapter each so I haven't been able to test multi adapter scenarios.

jmccaull commented 2 months ago

Sorry was rushing before leaving the house, I forgot the windows numbers don't line up. The ui let's me but I can't get the correct file for a few hours. I had at least tried reversing the numbers, I can't remember if I tried other displays through the api. Will report back when I can test, thanks again for looking into this!

jmccaull commented 2 months ago

Here is the config file after correcting the cloning, no issues through the UI from what I can tell, its zipped because its not letting me attach xml. It looks like the id order may have changed too, I didn't take a before config but I can revert if that helps:

 DisplayId DisplayName      Active  Primary Position    Mode                  ConnectionType
 --------- -----------      ------  ------- --------    ----                  --------------
         1 HP 2311            True    False 3840 0      1920x1080@60 Hz                  DVI
         2 VIZIO              True    False 3840 0      1920x1080@59.9400...            HDMI
         3 U28E590            True     True 0 0         3840x2160@60 Hz                  DVI
         4 SAMSUNG            True    False -3840 0     3840x2160@60 Hz                 HDMI

Interestingly, I was able to use copy display on the monitor and tv, but I'm still not able to use copy display with 3 as the source and 1 as destination "Copy-DisplaySource -DisplayId 3 -DestinationDisplayId 1"

CorrectedHPToVizioSoundbar.zip

Edit: I'm able to clone any combination through the UI, but none through the API so its probably related to the display adapter somehow?

MartinGC94 commented 2 months ago

Are you running version 2.0? My last update was supposed to make the displayId order more consistent on systems with multiple display adapters so it would suck if that's also not working as expected (I assume you haven't physically moved the display cables around either).

Because the displayIds have changed it would be nice with a full before/after set so I can more easily see what values the UI changes that I don't. If you aren't already running 2.0 I'd also prefer if you update the module before you export the new configs.

jmccaull commented 2 months ago

Yes, version 2 per Get-Module. Before cloning, with SAMSUNG disabled:

 DisplayId DisplayName      Active  Primary Position    Mode                  ConnectionType
 --------- -----------      ------  ------- --------    ----                  --------------
         1 VIZIO              True    False 5760 0      1920x1080@59.9400...            HDMI
         2 U28E590            True     True 0 0         3840x2160@60 Hz                  DVI
         3 HP 2311            True    False 3840 0      1920x1080@60 Hz                  DVI
         4 SAMSUNG           False    False 0 0                                         HDMI

Then with HP/Vizio cloned and SAMSUNG still disabled:

 DisplayId DisplayName      Active  Primary Position    Mode                  ConnectionType
 --------- -----------      ------  ------- --------    ----                  --------------
         1 U28E590            True     True 0 0         3840x2160@60 Hz                  DVI
         2 HP 2311            True    False 3840 0      1920x1080@60 Hz                  DVI
         3 VIZIO              True    False 3840 0      1920x1080@59.9400...            HDMI
         4 SAMSUNG           False    False 0 0                                         HDMI

Here are the before and after files: secondTry.zip

I spent a good amount of time trying to get really anything working, including calling the clone and apply methods on the config objects themselves. When using the Get-DisplayConfig version it throws and index out of bounds exception:

DisplayId DisplayName      Active  Primary Position    Mode                  ConnectionType
 --------- -----------      ------  ------- --------    ----                  --------------
         1 VIZIO              True    False 5760 0      1920x1080@59.9400...            HDMI
         2 U28E590            True     True 0 0         3840x2160@60 Hz                  DVI
         3 HP 2311            True    False 3840 0      1920x1080@60 Hz                  DVI
         4 SAMSUNG           False    False 0 0                                         HDMI

Get-DisplayConfig | Copy-DisplaySource -DisplayId 3 -DestinationDisplayId 1 | Use-DisplayConfig
Copy-DisplaySource : Index was outside the bounds of the array.
At line:1 char:21
+ ... layConfig | Copy-DisplaySource -DisplayId 3 -DestinationDisplayId 1 | ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (MartinGC94.Disp...I.DisplayConfig:DisplayConfig) [Copy-DisplaySource], In
   dexOutOfRangeException
    + FullyQualifiedErrorId : CloneConfigError,MartinGC94.DisplayConfig.Commands.CopyDisplaySourceCommand
MartinGC94 commented 2 months ago

I have found the problem and have added a fix for the Index out of bounds error you were getting. It only happens if there's a disabled display.
I have also found out why the DisplayId order gets messed up when you are cloning a display. Apparently the adapterId for the path changes from the original adapter, to the Id of the adapter you are cloning from.
Now I need to either find some way to get the proper adapter Id for cloned displays, or come up with some other method to determine the display Ids. It sure would be nice if MS would document how the Settings app assigns display Ids so third party developers like me could reuse the logic and make things consistent for the users.

I need to think about this for a bit. I'll post another comment when I have news or I need something from you.

jmccaull commented 2 months ago

Thanks for taking the time to figure that out! Could it be passed in by the client?


From: MartinGC94 @.> Sent: Monday, September 9, 2024 6:00:55 PM To: MartinGC94/DisplayConfig @.> Cc: John McCaulley @.>; Author @.> Subject: Re: [MartinGC94/DisplayConfig] Copy-DisplaySource : The parameter is incorrect (Issue #6)

I have found the problem and have added a fix for the Index out of bounds error you were getting. It only happens if there's a disabled display. I have also found out why the DisplayId order gets messed up when you are cloning a display. Apparently the adapterId for the path changes from the original adapter, to the Id of the adapter you are cloning from. Now I need to either find some way to get the proper adapter Id for cloned displays, or come up with some other method to determine the display Ids. It sure would be nice if MS would document how the Settings app assigns display Ids so third party developers like me could reuse the logic and make things consistent for the users.

I need to think about this for a bit. I'll post another comment when I have news or I need something from you.

— Reply to this email directly, view it on GitHubhttps://github.com/MartinGC94/DisplayConfig/issues/6#issuecomment-2339230069, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AFDBBFB5N2UNHFW5LVZHJTTZVYLBPAVCNFSM6AAAAABN2X5MFGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMZZGIZTAMBWHE. You are receiving this because you authored the thread.Message ID: @.***>

MartinGC94 commented 1 month ago

I have found the problem. I need to tell the API that I'm aware of "virtual mode" and of course I have to update the module itself to be virtual mode aware. While I'm at it I also need to look into the virtual refresh rate feature added in Windows 11. So expect a new version with these fixes in the near future.

jmccaull commented 1 month ago

Let me know if you have a branch you want me to try testing out or anything

MartinGC94 commented 1 month ago

Just to give an update since it's been a while. I took a break from working on this because it felt a little daunting but now I'm back.

I'm currently going over the DisplayConfig APIs making the required changes for Virtual mode and I'm almost done. It's just the display position related APIs I need to update now and then I'll push out an update in the next few days.

If you are interested in the technical details, there were 2 issues here.
1: Display cloning fundamentally changed. Instead of having each target (physical display) share 1 source (desktop image from Windows) there's now one source for each display and if you want to clone you just set the source position coordinates to match on each source. This changes the way I have to handle desktop positions, which relates to anything that adds or removes a display from the desktop and of course anything related to moving displays around.
2: The way to do certain things changed and I had to reverse engineer how the display settings app did this because there were no documentation for it (huge shoutout to WinAPIOverride. I couldn't have done it without that tool). For example to Enable a display I previously had to set a unique ID for each sourceInfo. Now I need to assign a CloneGroupId to each display.

MartinGC94 commented 1 month ago

It took a while but it's here: 3.0.zip Extract the zip and either manually import the .psd1 file with import-module C:\PathTo.psd1 or place it in your existing DisplayConfig folder and use it like you normally would.

Feel free to test other scenarios as well. Since this will be a breaking change we might as well go all out and fix every little flaw/annoyance before making a full release.

jmccaull commented 1 month ago

I should be able to try this out tonight and will report back, thanks for all the hard work!

MartinGC94 commented 1 month ago

Sounds good. I have a more up to date version here: 3.0.zip

A new feature that might interest you is the ability to clone displays that are currently disconnected, as well as cloning displays without specifying a source. Enable-Display is used for both, just use the new -AsClone parameter like this: Enable-Display -DisplayId 1,2,3 -AsClone to clone display 1-3. Windows will figure out the best source to use.

jmccaull commented 1 month ago

Was able to do some initial testing with good results! I'm still seeing some info wrong when using


 DisplayId DisplayName      Active  Primary Position    Mode                  ConnectionType
 --------- -----------      ------  ------- --------    ----                  --------------
         1 SAMSUNG            True    False 9600 0      1024x768@60 Hz                  HDMI
         2 U28E590            True     True 0 0         3840x2160@60 Hz                  DVI
         3 HP 2311            True    False 3840 0      1920x1080@60 Hz                  DVI
         4 SAMSUNG            True    False 5760 0      3840x2160@59.9400...            HDMI

but that doesn't seem to be a problem. Cloning across display adapters is working now using

deskMain
2
deskSide
3
souundbar
1
wall
4

Enable-Display -DisplayId $deskSide,$soundBar -AsClone

But trying to run this after causes some issues:

Enable-Display -DisplayId $wall,$soundBar -AsClone
Set-DisplayPrimary -DisplayId $wall
Disable-Display -DisplayId $deskMain,$deskSide

I get the errors:

Enable-Display : The parameter is incorrect
At wall_display_only.ps1:18 char:1
+ Enable-Display -DisplayId $wall,$soundBar -AsClone
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Enable-Display], Win32Exception
    + FullyQualifiedErrorId : FailedToApplyAlternativeConfig,MartinGC94.DisplayConfig.Commands.EnableDisplayCommand

Set-DisplayPrimary : Display ID '4' is not active
At wall_display_only.ps1:19 char:1
+ Set-DisplayPrimary -DisplayId $wall
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Set-DisplayPrimary], Exception
    + FullyQualifiedErrorId : System.Exception,MartinGC94.DisplayConfig.Commands.SetDisplayPrimaryCommand

Disable-Display : Cannot disable display 2 because it is the primary display.
At wall_display_only.ps1:20 char:1
+ Disable-Display -DisplayId $deskMain,$deskSide
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (2:UInt32) [Disable-Display], Exception
    + FullyQualifiedErrorId : ConfigUpdateFailure,MartinGC94.DisplayConfig.Commands.DisableDisplayCommand

If I first enable the displays without cloning, then enable with cloning it works:

Enable-Display -DisplayId $wall,$soundBar
Enable-Display -DisplayId $soundBar,$wall -AsClone

I'm not sure if this is intended, but Windows also seems to keep picking the lowest resolution recommended between the two cloned displays. I should be able to get around this pretty easily though.

Thanks again!

jmccaull commented 1 month ago

Well sorry need a little more help. When running:

Enable-Display -DisplayId $deskMain,$deskSide,$soundBar
Enable-Display -DisplayId $soundBar,$deskSide -AsClone
Set-DisplayResolution -DisplayId $deskSide -Width 1920 -Height 1080

I get:

Set-DisplayResolution : The parameter is incorrect
Atdesk_display_only.ps1:20 char:1
+ Set-DisplayResolution -DisplayId $deskSide -Height 1920 -Width 1080
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (MartinGC94.Disp...I.DisplayConfig:DisplayConfig) [Set-DisplayResolution], Win32Exception
    + FullyQualifiedErrorId : ConfigApplyError,MartinGC94.DisplayConfig.Commands.SetDisplayResolutionCommand

Is there a mode I need to set or anything or could this be something in code? I'm able to set the correct resolution using windows display settings, here are the before and after resolution change exports: resolutions.zip

MartinGC94 commented 1 month ago

What exactly is the wrong info in Get-DisplayInfo ? If it's just the DisplayIds that don't match Windows and the connectiontype not matching the reality then I unfortunately can't do anything about that. I don't know how Windows determines the display Ids and the connection type is just reporting exactly what the API reports.

The error for Enable-Display -DisplayId $wall,$soundBar -AsClone when the devices are disabled surprises me. I'm doing exactly what the display settings app does on my system but it's possible it does something more on certain exotic systems. I would have to find a way to trigger this on my own system to figure this one out.

I'm not sure if this is intended, but Windows also seems to keep picking the lowest resolution recommended between the two cloned displays.

My understanding of those APIs is that Windows will figure out the best settings automatically. I'm not doing anything special with the resolutions there. Though as you've rightfully thought of, you can just script the resolution changes.
Regarding the error you get for Set-DisplayResolution can you try this: Get-DisplayConfig | Set-DisplayResolution -DisplayId $deskSide -Width 1920 -Height 1080 | Use-DisplayConfig -AllowChanges if this works then I just need to add the -AllowChanges parameter to Set-DisplayResolution as well.
It seems the refresh rate slightly changes with the resolution change between the 2 resolutions and it therefore needs to be adjusted in the config.

jmccaull commented 1 month ago

Per the display info, the connection type for the U28E590 and the display name for the sound bar (should be Vizio something) . Do you know where to find what windows thinks it is? U28E590 is using display port to hdmi, the HP is the only one using DVI.

Get-DisplayConfig | Set-DisplayResolution -DisplayId $deskSide -Width 1920 -Height 1080 | Use-DisplayConfig -AllowChanges

Worked once outside of my powershell script but I can't get it to work again, not sure what I did. When I run it as part of the following I have to reset the display adapter caches and restart to get anything on any monitor:

Enable-Display -DisplayId $deskMain,$deskSide,$soundBar
Enable-Display -DisplayId $soundBar,$deskSide -AsClone
Get-DisplayConfig | Set-DisplayResolution -DisplayId $deskSide -Width 1920 -Height 1080 | Use-DisplayConfig -AllowChanges

Set-DisplayPrimary -DisplayId $deskMain

Disable-Display -DisplayId $wall

Removing the resolution from the above and trying to run it manually after is giving the same error as before, "The parameter is incorrect". It also doesn't work for the TV I'm calling wall when it is cloned with the soundbar. What I'm effectively trying to do is have shortcuts for desk mode and couch mode. Here is the error when trying to set the resolution for wall/soundbar:

Use-DisplayConfig : The parameter is incorrect
At wall_display_only.ps1:21 char:87
+ ... ayId $wall -Width 3840 -Height 2160 | Use-DisplayConfig -AllowChanges
+                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (MartinGC94.Disp...I.DisplayConfig:DisplayConfig) [Use-DisplayConfig], Win32Exception
    + FullyQualifiedErrorId : ConfigApplyError,MartinGC94.DisplayConfig.Commands.UseDisplayConfigCommand

I also got a before and after for setting the resolution on that pair with the settings app if that helps: tvResolution attempts.zip

Is there anything else I should test? would trying exporting and importing the configs be worth it? I think I tried that at one point on the previous version and it didn't work

Thanks again

MartinGC94 commented 1 month ago

I get the name and connector type with the APIs https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig and https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-displayconfiggetdeviceinfo
The data is stored in the following structs: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_path_target_info and https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_target_device_name

My understanding is that it tries to get the name from the EDID data encoded into the device but it includes some fallback if the name is invalid. I don't know how it works exactly under the hood.

When I run it as part of the following I have to reset the display adapter caches and restart to get anything on any monitor

When you say cache, are you referring to the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GraphicsDrivers\Configuration registry keys? As for the black screen, that indicates that the configuration was successfully accepted and applied by the system so the APIs are working as they should but of course the end result is undesirable. I don't know what the module can do about that though, I mean the exact same thing can happen in the GUI (I had it happen to me when I tried to set my TV to 120 Hz when I had my second adapter connected + an old Nvidia driver version that could support both my GT710 and RTX 3070.)
I would assume that the "best match" logic it uses with the AllowChanges parameter finds an invalid combination for your system. The workaround for you would be to find out exactly what refresh rate it needs (maybe something like 59.951) and explicitly add it like this:

Get-DisplayConfig |
    Set-DisplayResolution -DisplayId $deskSide -Width 1920 -Height 1080 |
    Set-DisplayRefreshRate -DisplayId $deskSide -RefreshRate 59.951 |
    Use-DisplayConfig

Protip: If you use the -DontSave parameter on Use-DisplayConfig you can roll back your changes. That's hard without any display output but you can bind it to a key like this: Set-PSReadLineKeyHandler -ScriptBlock {Undo-DisplayConfigChanges} -Chord ctrl+p then you just need to press ctrl+p to revert.
You can set it up in the GUI exactly how you like it and then get the exact refresh rate with Get-DisplayInfo.

would trying exporting and importing the configs be worth it? I think I tried that at one point on the previous version and it didn't work

Because of the lack of virtual mode support the previous configs weren't accurate on your system but if you try it with the new version I would imagine it would work as the exported config should have the fully discovered path and mode info.
It would be nice to be able to write a fully deterministic script that does everything the config does though so you can consider the import/export process a workaround.

jmccaull commented 1 month ago

So I found it is windows calling the sound bar SAMSUNG from the display side as it shows up in the UI for advanced display settings, even though its clearly the motherboard adapter which is plugged into the soundbar and shows up in the sound options as Vizio. I've been clearing the cache with some scripts that come with CRU, but they don't seem to work every time, thanks for the tips.

I was only getting the black screen when running the resolution command within a powershell script, when I ran it independently it would complain about the parameter and I would not get to the black screen, maybe a race condition?

I've been testing with export/import config with much more luck but still some odd issues. The configs for "desk mode", 1+3 cloned 2 primary and 4 disabled, and "couch mode", 4 + 1 cloned 2 + 3 disabled seem to work every time without issue.

I was doing some testing with 2 other configurations, the first with 2 primary 4 extended and 1+3 cloned, so everything extended with the sound bar not causing an invisible screen and it seems not able to enable displays. If I run the import with all displays enabled it will work, but if 4 is turned off it stays off and likewise for 2 and 3.

The other config was with 2 primary and 1, 3 and 4 cloned. This seems to work but it does not show up in the windows display app, its like one of the displays disappear. If I import this one, I sometimes get black screens importing one of the others after but I can't figure out if its any specific one or random. I was not able to configure this one strictly with the UI, I had to use Enable-Display with the 3 -AsClone.

I've said it a lot, but thanks again for all the help, this fits what I was looking for perfectly. I can't believe how difficult this is on windows, great work! Do you have a Kofi, Patreon, etc so I can buy you a beer/coffee?

MartinGC94 commented 1 month ago

I was only getting the black screen when running the resolution command within a powershell script, when I ran it independently it would complain about the parameter and I would not get to the black screen, maybe a race condition?

I guess it's possible the API calls return as soon as the command is sent but there are additional adjustments made after the display physically turns on. You could try to add a Start-Sleep 10 after the last Enable-Display and see if that helps, then try to reduce the wait time until it stops working again.

If I run the import with all displays enabled it will work, but if 4 is turned off it stays off and likewise for 2 and 3.

Based on the previous issue it seems like there's something weird going on when you turn on displays in your setup. You can try unplugging some of the displays and see if you can trigger the problem. I would start with the sound bar as that seems the most "exotic".

The other config was with 2 primary and 1, 3 and 4 cloned. This seems to work but it does not show up in the windows display app, its like one of the displays disappear.

Yes that's expected. The display settings app only supports cloning across 2 displays even though the API clearly supports multiple. I guess it's to keep the user interface simple or something.

I've said it a lot, but thanks again for all the help, this fits what I was looking for perfectly. I can't believe how difficult this is on windows, great work! Do you have a Kofi, Patreon, etc so I can buy you a beer/coffee?

I really appreciate the thought but I don't have anything like that and I'm not planning on setting it up at the moment. Maybe I'll do it in the future if it ends up being a common request.

MartinGC94 commented 1 month ago

I've tried to trigger the error you are getting on my own system but nothing I do breaks it like it does on your system. If I can't reproduce the error on my system then I can't debug it so I unfortunately don't think there's anything else I can do to fix this.

I've added the -AllowChanges parameter to Set-DisplayResolution and I've made a new official release of the module with all the changes you've tested so far.

I'm going to close this issue as the original problem with a lack of virtual mode that causes issues when cloning has been resolved but if you have any more questions related to this you can still post them here and I'll respond.

MartinGC94 commented 3 weeks ago

Version 3.0.2 that was just published on the PS gallery fixes an issue with Set-DisplayResolution that caused the "The parameter is incorrect" error. It won't fix the black screen issue but at least the module won't throw that particular error anymore.

MartinGC94 commented 2 weeks ago

Remember this?

The error for Enable-Display -DisplayId $wall,$soundBar -AsClone when the devices are disabled surprises me. I'm doing exactly what the display settings app does on my system but it's possible it does something more on certain exotic systems. I would have to find a way to trigger this on my own system to figure this one out.

Turns out I was actually doing something wrong 😁. For some reason the API generates multiple nearly identical paths to each display where the only difference is the sourceId number. The display settings app ensures there's no duplicate sourceIds while my old logic just took the first available path for each display which could end up with duplicate sourceIds in certain scenarios. Now I also ensure the sourceIds are unique and in my testing so far it seems to work perfectly now.
I don't have my multi display adapter setup anymore though so I'd appreciate it if you could test out the changes as well before I make an official release. You can view the changes here: https://github.com/MartinGC94/DisplayConfig/tree/Dev and you can download an updated version here: 3.1.0.zip

There's also a new DisplayIdToDisable parameter in Enable-Display that makes it a bit more convenient to switch between displays. Previously you had to enable the new display, possibly change the primary display away from whatever display you wanted to disable and then disable the display. Now you can do it all in one go.

-Edit: 3.1.0 has been published to the gallery now.