Disable Exclusive Mode for all audio devices in Windows 10 - windows

I need to configure audio devices a large number of PCs.
I am stuck on how to Disable Exclusive Mode, "allow applications to take exclusive-mode of this device"
I can disable all the media devices:
Get-PnpDevice -class "MEDIA" | ForEach-Object {Disable-PnpDevice -InstanceId $_.InstanceID -Confirm:$false}
I can enable the desired devices:
Get-PnpDevice -Class Media | where FriendlyName -like "*NVIDIA High Definition Audio*" | where Status -eq "OK" | ForEach-Object { Disable-PnpDevice -instanceid $_.instanceid -Confirm:$false }
I can set the default audio device (playback/recording) leveraging AudioDeviceCmdlets.
I can even set the sound reduction to 0 through the registry
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Multimedia\Audio] "UserDuckingPreference"=dword:00000003
But I cannot find an API or a data structure that corresponds to where the state is changed and how?
Can someone point me in the right direction here?

These parameters are available in the registry key:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture\{xxx-xxx-xxx-xxx}\Properties
(change XXX by the GUID of your default record device)
The names of the keys are:
{b3f8fa53-0004-438e-9003-51a46e139bfc},3
{b3f8fa53-0004-438e-9003-51a46e139bfc},4
The value can be 0 or 1.
This correspond to the check box "Allow applications to take exclusive control of this device" and "Give exclusive mode applications priority"
But those key are owned by system account and cant be edited easily with a script.
If you are OK to use external program, a nirsoft sofware utility can do the job:
Nirsoft SoundVolumeView
You can use it from cli:
SoundVolumeView.exe /SetExclusivePriority "XXXXX" 0
SoundVolumeView.exe /SetAllowExclusive "XXXXXX" 0
(XXX can be ID or name of the record device)

Related

Powershell: How can i get the primary screen resolution of a logged in user?

Our current scenario is this:
We have more than 80 tablet computers (running Windows 10) in our network that run under the same user (DefaultUser). In order to verify that the display settings are correctly set, we would like to use a powershell script to automatically check the used resolution remotely with a support user account.
So far, we know how to get the primary screen resolution for the user under which the script gets executed (which is rather easy):
// get primary screen width
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width // height accordingly
In case we execute this script on one of the tablets using the support account, we get the primary screen resolution for the support account user - but not for the desired user DefaultUser.
How can we get the resolution for the DefaultUser?
The only solution that easily comes to my mind is a rather ugly thing:
Using the windows task scheduler i could create a task that executes the script (under the defaultUser) to get the screen resolution and write the result(s) into a file that can be accessed by the support user account. But i am looking for something more elegant.
It sounds like you're looking for the screen scaling values, based on your code checking the PrimaryScreen values:
# My monitor resolution is 3000x2000
Add-Type -AssemblyName System.Windows.Forms
# [Screen] returns screen size AFTER scaling (200% here)
[System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height
1000
# [SystemInformation] returns the hardware screen resolution (applies to all users)
[System.Windows.Forms.SystemInformation]::VirtualScreen.Height
2000
Scaling can be set on a per-user basis, though there is a machine-wide "Default" setting. Screen scaling is weird, and gets done differently depending on what version of windows you have. Here's how it works in Windows 10 at least.
You can check the current values like so:
# AllUsers setting, which shows as (default)
Get-ItemProperty -path "HKCU:\Control Panel\Desktop\WindowMetrics" | fl AppliedDPI
# User's current scaling setting (I use a * instead of the per-monitor ID)
Get-ItemProperty -path "HKCU:\Control Panel\Desktop\PerMonitorSettings\*" | fl DpiValue
# AppliedDPI shows the "Default" scaling setting on a system level like:
96 : 100%
120 : 125%
144 : 150%
192 : 200% (my default)
# DpiValue shows how many steps up or down the current user's scaling setting is. For example on my machine:
#250%
DpiValue : 2 # +2
#200% (default)
DpiValue : 0
#150%
DpiValue : 4294967294 # -1
#100%
DpiValue : 4294967292 # -3
Finding and overriding scaling for other user profiles is pretty involved, but has been done by other people. I found this script and usage details by user romaliceishimwe2. I have not tested, but it does show how to look at and change other users' profiles:
#First we configure the default, later we will configure any existing users.
#Load the ntuser.dat of the default user
REG LOAD HKU\Default_User C:\users\default\ntuser.dat
#Assign new registry keys
New-ItemProperty -path registry::"HKU\Default_User\Control Panel\Desktop" -Name LogPixels -Value 120 -Type DWord
New-ItemProperty -path registry::"HKU\Default_User\Control Panel\Desktop" -Name Win8DpiScaling -Value 1 -Type DWord
#unload default user ntuser.dat
REG UNLOAD HKU\Default_User
#Here we configure any eixting users
# Regex pattern for SIDs
$PatternSID = 'S-1-5-21-\d+-\d+\-\d+\-\d+$'
# Get Username, SID, and location of ntuser.dat for all users
$ProfileList = gp 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*' | Where-Object {$_.PSChildName -match $PatternSID} |
Select #{name="SID";expression={$_.PSChildName}},
#{name="UserHive";expression={"$($_.ProfileImagePath)\ntuser.dat"}},
#{name="Username";expression={$_.ProfileImagePath -replace '^(.*[\\\/])', ''}}
# Get all user SIDs found in HKEY_USERS (ntuder.dat files that are loaded)
$LoadedHives = gci Registry::HKEY_USERS | ? {$_.PSChildname -match $PatternSID} | Select #{name="SID";expression={$_.PSChildName}}
# Get all users that are not currently logged
$UnloadedHives = Compare-Object $ProfileList.SID $LoadedHives.SID | Select #{name="SID";expression={$_.InputObject}}, UserHive, Username
# Loop through each profile on the machine
Foreach ($item in $ProfileList) {
# Load User ntuser.dat if it's not already loaded
IF ($item.SID -in $UnloadedHives.SID) {
reg load HKU\$($Item.SID) $($Item.UserHive) | Out-Null
}
#####################################################################
# This is where you can read/modify a users portion of the registry
"{0}" -f $($item.Username) | Write-Output
New-ItemProperty -path registry::"HKU\$($Item.SID)\Control Panel\Desktop" -Name LogPixels -Value 120 -Type DWord -force
New-ItemProperty -path registry::"HKU\$($Item.SID)\Control Panel\Desktop" -Name Win8DpiScaling -Value 1 -Type DWord -force
#####################################################################
# Unload ntuser.dat
IF ($item.SID -in $UnloadedHives.SID) {
### Garbage collection and closing of ntuser.dat ###
[gc]::Collect()
reg unload HKU\$($Item.SID) | Out-Null
}
}
You may be able to use CIM or WMI to get from point a to b.
CIM_VideoController is the class that would contain the resolution.
Using PowerShell Core:
Get-CimInstance CIM_VideoController | Select SystemName, CurrentHorizontalResolution, CurrentVerticalResolution
Using Windows PowerShell:
Get-WmiObject Win32_VideoController | Select SystemName, CurrentHorizontalResolution, CurrentVerticalResolution
You should be able to open the proper ports to use either of these options remotely (though you could also probably get away with using Invoke-Command to run them, as long as you use CredSSP or Kerberos Delegation to take the 2nd hop problem into account).

How to get Bluetooth device battery percentage using PowerShell on windows?

I am trying to plot a graph for Bluetooth headphone battery discharge. For that I need to read battery percentage of the connected device. I can see power information is available on GUI for the device. Is there any way to get the battery percentage info for connected Bluetooth device using PowerShell? (like using wmi or anything else)
In my findings, you can get information on Bluetooth devices using the Get-PnpDevice cmdlet. This should return a list of PnP Devices, their Status, Class, FriendlyName and InstanceID.
Get-PnpDevice
You can filter the results with -Class parameter. To specify Bluetooth PnP devices, you can enter "Bluetooth" as a string value for the -Class parameter.
Get-PnpDevice -Class 'Bluetooth'
You can then specify the device you have in mind from this list by their FriendlyName using the -FriendlyName parameter and enter the desired device's FriendlyName as a string value for the parameter.
Get-PnpDevice -Class 'Bluetooth' -FriendlyName 'Device FriendlyName'
Note: You can also specify the device using the -InstanceId parameter and providing the device's InstanceId as a string value for the parameter.
If you then pipe the previous command to the Get-PnpDeviceProperty cmdlet, it will return a list of the device's properties, including its InstanceId, KeyName, Type and Data.
Get-PnpDevice -Class 'Bluetooth' -FriendlyName 'Device FriendlyName' |
Get-PnpDeviceProperty
Beyond this point, I was able to further filter the results of the command by using the -KeyName parameter and entering the KeyName of the property that (I assume) contains Device Power Data as a string value for the parameter.
Get-PnpDevice -Class 'Bluetooth' -FriendlyName 'Device FriendlyName' |
Get-PnpDeviceProperty -KeyName 'PropertyKeyName'
Unfortunately this is as far as I've gotten to solving the problem. Hopefully my contribution helps.
As far as I am aware, there is no way to poll bluetooth device data beyond what you would get with Get-WmiObject, since the battery status seen in Windows Settings -> Bluetooth Devices is something coming from the vendors/devices driver and seems to, as of now, be inaccessible by PowerShell, unless there is some exotic snapin I am not aware of.
You can get all possible device information via this command:
Get-WmiObject -Query "select * from win32_PnPEntity" | Where Name -like "MyDeviceName"
Or if you are unsure how the device is named as of now, this would return a complete list of "devices":
Get-WmiObject -Query "select * from win32_PnPEntity" | Select Name
Additionally, I couldn't find battery information in the registry - maybe someone more knowledge can expand on that because the registry probably contains the necessary information as it must be stored somewhere on the device.
Paulo Amaral's comment above is indeed the answer.
The code below will provide you with a command you can reuse to query the battery state of your device:
Get-PnpDevice -FriendlyName "*<Device Name>*" | ForEach-Object {
$local:test = $_ |
Get-PnpDeviceProperty -KeyName '{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2' |
Where Type -ne Empty;
if ($test) {
"To query battery for $($_.FriendlyName), run the following:"
" Get-PnpDeviceProperty -InstanceId $($test.InstanceId) -KeyName '{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2' | % Data"
""
"The result will look like this:";
Get-PnpDeviceProperty -InstanceId $($test.InstanceId) -KeyName '{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2' | % Data
}
}
For my <Headset> device, the output looked similar to:
To query battery for <Headset>, run the following:
Get-PnpDeviceProperty -InstanceId BTHENUM\{0000####-0000-####-####-############}_VID&########_PID&####\#&########&#&############_######### -KeyName '{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2'
The result will look like this:
90

How to list bluetooth devices near me using PowerShell

How to list all Bluetooth devices paired or currently near me and particullary MAC adress ? I want the equivalent of the command :
netsh wlan show network mode=bssid
I am able to list all Bluetooth devices and characteristics but not MAC adress with the command :
Get-PnpDevice | Where-Object {$_.Class -eq "Bluetooth"}
foreach ($device in $devices) { echo $device.InstanceId }
Note it is not a problem if I need to manually shrink results and if the list is not in a perfect layout.
The PowerShell command :
Get-ChildItem -Path HKLM:\SYSTEM\ControlSet001\Services\DeviceAssociationService\State\Store\ | Select-String -Pattern Bluetooth
will print devices already paired :
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\DeviceAssociationService\State\Store\Bluetooth#BluetoothXX:XX:XX:XX:XX:b2-YY:YY:YY:YY:YY:YY
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\DeviceAssociationService\State\Store\Bluetooth#BluetoothXX:XX:XX:XX:XX:b2-ZZ:ZZ:ZZ:ZZ:ZZ:ZZ
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\DeviceAssociationService\State\Store\BluetoothLE#BluetoothLEXX:XX:XX:XX:XX:b2-WW:WW:WW:WW:WW:WW
The XX:XX:XX:XX:XX values is your Bluetooth MAC adress.

Win32_PnPEntity not getting hidden devices

I'm using the Win32_PnPEntity class to get all the devices in a computer, but the Win32_PnPEntity class does not list the hidden devices. Hidden devices in the Windows device manager have a status "Currently, this hardware device is not connected to the computer. (Code 45)" and can be shown by clicking the menu option in Device Manager: View > Show hidden devices (Windows 10).
Does anyone know how to get the hidden devices?
You can do it using the command:
Get-PnpDevice -class "Ports"
Status Class FriendlyName
------ ----- ------------
OK Ports Communications Port (COM1)
Unknown Ports Silicon Labs Dual CP2105 USB to UART Bridge: Enhanced
Unknown Ports Arduino Uno (COM5)
Unknown Ports Silicon Labs Dual CP2105 USB to UART Bridge: Standard
OK Ports Prolific USB-to-Serial Comm Port (COM6)
Here you can see my COM ports that have been disconnected (status: unknown)
You can make use of ConfigManagerErrorCode. Refer Win32_PnPEntity and Win32_PnPEntity MSDN. You have not mentioned if you are using powershell or C# for scripting, i am assuming powershell.
$result = #{Expression = {$_.Name}; Label = "Device Name"},
#{Expression = {$_.ConfigManagerErrorCode} ; Label = "Status Code" }
Get-WmiObject -Class Win32_PnpEntity -ComputerName localhost -Namespace Root\CIMV2 | Where-Object {$_.ConfigManagerErrorCode -gt 0 } | Format-Table $result

PowerShell Script Running as a Service Behaves Strangely

PowerShell Script Running as a Service Behaves Strangely
The Project:
Create a background process that determines if the on board network card is connected. If it is connected, disable the wireless network card. When the onboard network card is not connected, re-enable the wireless card.
Why:
Users hot-dock all the time, getting funky routing tables OR get bound to the wrong DNS servers. When they attempt to access a local resource, say printers, they aren’t able to and then are in my cube (they would file a ticket, but that too would be a local resource). Trying to convince users to disable their own wireless (via switch on laptop) or not hot dock has met with limited success.
The Problem:
The PowerShell script below does run, and does work under my testing conditions. Likely under most testing conditions as the code and wmi queries are pretty generic. Running the script manually yields the expected results, HOWEVER running the script as a service via the only method I could find, srvany.exe, yielded unexpected results and “broke stuff”.
Details:
Running the script as a service, via srvany.exe, works ONCE. When the loop comes back around to test the network connection or tries the method to enable or disable it. The errors indicate that “get-wmiobject” is not a proper Cmdlet. Huh? It works, manually, it works once, but a second time after it disabled the wireless network card it does not. Worse yet MY shell , outside of the service, suddenly can’t do a get-wmiobject, until…. until you go into Device Manager and re-enable the wireless network card yourself.
Debugging attempts:
I rewrote the script and cleaned it up a little to allow for it to get the objects outside of the Do While loop. Nothing changed, but I left the script that way as it seems cleaner anyhow. I enabled “Interact with Desktop” in the service properties and sure enough you can see the script trying to work and getting the before mentioned errors.
Please help. Again the object here is to run a background process, one with enough privileges in Vista or 7 to disable and enable the wireless network card.
#***********************************************************************
# "switch-wifi-srv.ps1"
# This script attempts to identify if a wired network card is in use if
# one is, the Wireless network card is disabled, until the wired network
# card is no longer in use.
#
# Written by Aaron Wurthmann - aaron (AT) wurthmann (DOT) com
#
# 2010.02.10 ver 2 (Service Version)
# If you edit please keep my name or at the very least original author's.
# As of this writing I am unsure if script will work with all scenarios,
# however it has worked for me on Dell laptops running Windows 7 x64.
# -----------------------------------------------------------------------
# This script comes with ABSOLUTELY NO WARRANTY.
# You may redistribute copies of the script under
# the terms of the GNU General Public License.
# -----------------------------------------------------------------------
# Service Installation:
# Aquire and install the Windows 2003 Resource Kit OR the srvany.exe.
# Use sc.exe and srvany.exe to create a service....
# sc create SwitchWifiAuto binPath= "C:\Program Files (x86)\Windows Resource Kits\Tools\srvany.exe" DisplayName= "Switch Wifi Automatically"
# Edit registry entry for SwitchWifiAuto, add a key and a string value...
# HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\SwitchWifiAuto\Parameters]
# "Application"="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy RemoteSigned -File C:\\SwitchWifiAuto\\switch-wifi-srv.ps1"
#************************************************************************
$state=""
$wireStatus=""
$wifiStatus=""
# Get Wired and Wireless Card Objects
$objWire=get-wmiobject -class win32_networkadapter -namespace root\CIMV2 | Where-Object {$_.Name -notmatch "Wireless" -and $_.Name -notmatch "Virtual" -and $_.PhysicalAdapter -eq "True"}
$objWifi=get-wmiobject -class win32_networkadapter -namespace root\CIMV2 | where-object {$_.Name -match "Wireless"}
# Get Name of Service to be Used in totally useless Do While Loop
$objService=get-service -display "Switch Wifi Automatically"
# Begin Do While Loop
Do {
# Get status of wired network card. If enabled and connected set $state to Disable (which will later Disable the Wifi network card)
[string]$wireStatus=$objWire | % {$_.NetEnabled}
if($wireStatus -eq "True") {
$state="Disable"
}
# Get Status of wireless card.
if($objWifi){
[string]$wifiStatus=$objWifi | % {$_.NetEnabled}
# If $state is not set to disable and if the wireless card is currently disabled, enable it.
if($state -ne "Disable") {
if($wifiStatus -eq "False") {
Out-Null -InputOject ($objWifi | % {$_.Enable()})
}
# If $state is set to Disable and if wireless card is currently enabled, disable it.
} else {
if($wifiStatus -eq "True") {
Out-Null -InputOject ($objWifi | % {$_.Disable()})
}
}
}
# Reset Checked Variables for good measure
$state=""
$wireStatus=""
$wifiStatus=""
# Sleep for 120 seconds (two minutes)
Start-Sleep -s 120
# Continuing looping (do while) until the service is not running.
# This is of course technically useless as when the service is not running neither is the script to check if the service is not running.
# I made it this way however because I don't like infinite loops and I thought it would be funny to it this way instead of while $var=0
} while ($objService.Status -eq "Running")
Try to remove any output. Service don't have stdout stream. And when the buffer is full strange thing happens. Just a guess ( I never used powershell ).
Debugging attempts: I rewrote the script and cleaned it up a little to
allow for it to get the objects outside of the Do While loop.
You need to include these within the loop or you will not get updated values and the loop will do nothing.

Resources