I would like to find a way to change the windows default sound with powershell.
In vbs it is written like this:
WshShell.RegWrite "HKCU\AppEvents\Schemes\Apps\.Default\.Default\.Current\","c:\windows\media\horn.wav","REG_SZ"
I tried invoking the command but did not know the correct way to do it.
There are (at at least) two pretty simple ways to do this in PowerShell. The first is to use the WShell from within PowerShell (at least in Windows PowerShell 5.1 - unsure about Core):
$wshell = New-Object -ComObject WScript.Shell
$wshell.RegWrite("HKCU\AppEvents\Schemes\Apps\.Default\.Default\.Current\","c:\windows\media\horn.wav","REG_SZ")
The second is a more built-in way using PowerShell's Set-ItemProperty cmdlet - which should work in Core versions.
$SetItemProperty = #{
Path = "HKCU:\AppEvents\Schemes\Apps\.Default\.Default\.Current\"
Name = "(default)"
Value = "c:\windows\media\horn.wav"
}
Set-ItemPoperty #SetItemProperty
(Note: using the hashtable variable with the # symbol instead of the common $ symbol is called Splatting; it's effectively just matching up parameter names to values so I don't have to write out a really (horizontally) long command.)
Powershell does not have a native cmdlets for that, beside you would have to use C# to get that functionality in powershell.
Luckily, someone did the hardwork and put that in to a module, check the following repo :
https://github.com/frgnca/AudioDeviceCmdlets
There are detailed instructions on how to install the module, once you done that you can see all devices
Get-AudioDevice -List
Index : 1
Default : True
Type : Playback
Name : Speakers (2- Jabra EVOLVE LINK)
ID : {0.0.0.00000000}.{8c58263c-e6a0-4c7b-8e51-5231f04cbcb9}
Device : CoreAudioApi.MMDevice
From there you can see the current Default device and change it however you like.
Related
Is it possible to set default values for existing commands in PowerShell?
What I specifically want to do is to tell the Get-ChildItem command to show both normal and hidden files (Get-ChildItem -Force).
I know I can write a function where I can add this option and use whatever else is specified on the command line. But then I lose the auto-completion functionality for all parameters and options.
You should be able to do so using $PSDefaultParameterValues. Has worked from 3.0+.
Microsoft's documentation:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters_default_values?view=powershell-7.1
Here is a set of examples directly from that documentation:
$PSDefaultParameterValues=#{"CmdletName:ParameterName"="DefaultValue"}
$PSDefaultParameterValues=#{ "CmdletName:ParameterName"={{ScriptBlock}} }
$PSDefaultParameterValues["Disabled"]=$True | $False
I have a bunch of .lnk files and need to treat them differently depending on the target that the shortcut points to. I've found very little of how to this with other languages, but nothing about doing this with powershell.
I've tried this:
$sh = New-Object -COM WScript.Shell
$target = $sh.CreateShortcut('<path>').Target
But this returns an empty string even though I can see in the .lnk properties that the Target is specified.
Any idea on how to accomplish this?
You have made an error in the property; as wOxxOm suggests, you should be using TargetPath rather than Target:
$sh = New-Object -ComObject WScript.Shell
$target = $sh.CreateShortcut('<full-path-to-shortcut>').TargetPath
Google and MSDN were indeed helpful here; additionally, piping objects to Get-Member can often be useful and educational. This question also shows how to manipulate shortcuts using PowerShell, and uses the same technique as seen here.
If you want the arguments to the executable as well, those are stored separately:
$arguments = $sh.CreateShortcut('<full-path-to-shortcut>').Arguments
Again, piping objects to Get-Member - in this case, the object returned by WScript.Shell.CreateShortcut() - provides useful information.
It should be noted that there are issues with using this technique and these calls when the path contains Unicode emoji characters; there is a workaround for this case in this StackOverflow question.
It may seem obvious to experts but to us simpletons there seems to be a key lightbulb moment here:
<full-path-to-shortcut> = the Full Name! Doh!
Make sure you use .FullName if you use Get_ChildItem | ForEach-Object, etc. with the Shell .CreateShortcut call if you want the current target of a shortcut. For me:
.CreateShortcut($_.FullName) returned an appropriate value; whereas
.CreateShortcut($_) returned 'null'
I have a bunch of .lnk files and need to treat them differently depending on the target that the shortcut points to. I've found very little of how to this with other languages, but nothing about doing this with powershell.
I've tried this:
$sh = New-Object -COM WScript.Shell
$target = $sh.CreateShortcut('<path>').Target
But this returns an empty string even though I can see in the .lnk properties that the Target is specified.
Any idea on how to accomplish this?
You have made an error in the property; as wOxxOm suggests, you should be using TargetPath rather than Target:
$sh = New-Object -ComObject WScript.Shell
$target = $sh.CreateShortcut('<full-path-to-shortcut>').TargetPath
Google and MSDN were indeed helpful here; additionally, piping objects to Get-Member can often be useful and educational. This question also shows how to manipulate shortcuts using PowerShell, and uses the same technique as seen here.
If you want the arguments to the executable as well, those are stored separately:
$arguments = $sh.CreateShortcut('<full-path-to-shortcut>').Arguments
Again, piping objects to Get-Member - in this case, the object returned by WScript.Shell.CreateShortcut() - provides useful information.
It should be noted that there are issues with using this technique and these calls when the path contains Unicode emoji characters; there is a workaround for this case in this StackOverflow question.
It may seem obvious to experts but to us simpletons there seems to be a key lightbulb moment here:
<full-path-to-shortcut> = the Full Name! Doh!
Make sure you use .FullName if you use Get_ChildItem | ForEach-Object, etc. with the Shell .CreateShortcut call if you want the current target of a shortcut. For me:
.CreateShortcut($_.FullName) returned an appropriate value; whereas
.CreateShortcut($_) returned 'null'
I need to run some PowerShell scripts across various operating systems. Most of them are in English version, however, some are localized for example German, French, Spanish, etc. The problem is local system administrators mostly do not now PowerShell and in the case the script fails and throws an error at them, instead of reading it they just send screenshots of such error messages to me and if the cause to this error is not obvious I am stuck with typing it to g. translate to find out what is going on.
Is there a switch I can run the whole script or single command with or a parameter or any other way to force errors in PowerShell to be displayed in English instead of the language that is default for that particular machine?
You can change the pipeline thread's CurrrentUICulture like so:
[Threading.Thread]::CurrentThread.CurrentUICulture = 'fr-FR'; Get-Help Get-Process
I'm on an English system but before I executed the line above, I updated help like so:
Update-Help -UICulture fr-FR
With that, the Get-Help call above gave me French help on my English system. Note: if I put the call to Get-Help on a new line, it doesn't work. Confirmed that PowerShell resets the CurrentUICulture before the start of each pipeline which is why it works when the commands are in the same pipeline.
In your case, you would need to have folks install English help using:
Update-Help -UICulture en-US
And then execute your script like so:
[Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'; .\myscript.ps1
[Threading.Thread]::CurrentThread.CurrentUICulture only affects to current one-liner, so you can use it for execution of single .ps1 file.
If you want to change messages to English throughout every command in a PowerShell window, you have to change the culture setting cached in PowerShell runtime with reflection like this:
# example: Set-PowerShellUICulture -Name "en-US"
function Set-PowerShellUICulture {
param([Parameter(Mandatory=$true)]
[string]$Name)
process {
$culture = [System.Globalization.CultureInfo]::CreateSpecificCulture($Name)
$assembly = [System.Reflection.Assembly]::Load("System.Management.Automation")
$type = $assembly.GetType("Microsoft.PowerShell.NativeCultureResolver")
$field = $type.GetField("m_uiCulture", [Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Static)
$field.SetValue($null, $culture)
}
}
(from https://gist.github.com/sunnyone/7486486)
I am trying to generate a shortcut for every printer I have on a print server. The idea is to be able to email these shortcuts to people and when they click on them, it automatically installs that printer for them.
I've populated an array from a list of printer names exported from the print server:
$list = #((get-contnet $home\dekstop\plist.txt))
I then created a method to create a shortcut:
function Make-Shortcut
{
param ([string]$dest, [string]$source)
$WshShell = New-Object -comObject Wscript.Shell
$Shortcut = $WshShell.CreateShortcut($dest)
$Shortcut.TargetPath = $Source
$Shortcut.Save()
}
The function works fine. I was able to create standard shortcuts with no problem.
This next part is where I am getting stuck:
foreach ($i in $list)
{
Make-Shortcut "C:\pshort\$i.lnk" "C:\Windows\System32\rundll32.exe
printui.dll,PrintUIEntry /in /q /n\\printserver\$i"
}
When this runs, it does generate a shortcut with the same name as the printer for each printer on the list. However, the problem comes in at the target path. Instead of
C:\Windows\System32\rundll32.exe printui.dll,PrintUIEntry /in /q /n\\printserver\printername
it changes it to:
C:\Windows\System32\rundll32.exe printui.dll,PrintUIEntry \in \q \n\printserver\printername
The three problems with this are:
It is reversing the forward slash for the parameters
It is removing one of the backslashes preceding the server name
It is adding quotes to both sides. I need the quotes to come off for the shortcut to work properly.
I assume this is happening because Powershell thinks I am trying to make a standard shortcut and thinks I made mistakes while typing out the path.
I have tried putting a ` in front of each forward slash hoping the escape character would prevent it from reversing it, but no luck. I also tried using a hyphen for each parameter but that did not work either.
Is there anyway to stop this from happening? Or is there perhaps a better way to try to accomplish what I am trying to do?
You need to add arguments to the com object
Try adding a new param $arguments to your Make-Shortcut function and do:
Make-Shortcut "C:\pshort\$i.lnk" "C:\Windows\System32\rundll32.exe"
"printui.dll,PrintUIEntry /in /q /n\\printserver\$i"
add this in your function:
$Shortcut.Arguments = $arguments
So the link is created successfully ... but I have no idea if it works :)
Completely different answer but in a standard windows environment simply clicking a hyperlink to \printserver\printer will add a shared printer to someone's system?
So an email that simply lists :
\\PrintServer\Printer01
\\PrintServer\Printer02
\\PrintServer\Printer03
Would probably do the job just as well.