Set new defaults for PowerShell commands - powershell

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

Related

Change Default Windows Sound With Powershell

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.

Microsoft's Consistency in PowerShell CmdLet Parameter Naming

Let's say I wrote a PowerShell script that includes this commmand:
Get-ChildItem -Recurse
But instead I wrote:
Get-ChildItem -Re
To save time. After some time passed and I upgraded my PowerShell version, Microsoft decided to add a parameter to Get-ChildItem called "-Return", that for example returns True or False depending if any items are found or not.
In that virtual scenario, do I have I to edit all my former scripts to ensure that the script will function as expected? I understand Microsoft's attempt to save my typing time, but this is my concern and therefore I will probably always try to write the complete parameter name.
Unless of course you know something I don't. Thank you for your insight!
This sounds more like a rant than a question, but to answer:
In that virtual scenario, do I have I to edit all my former scripts to ensure that the script will function as expected?
Yes!
You should always use the full parameter names in scripts (or any other snippet of reusable code).
Automatic resolution of partial parameter names, aliases and other shortcuts are great for convenience when using PowerShell interactively. It lets us fire up powershell.exe and do:
ls -re *.ps1|% FullName
when we want to find the path to all scripts in the profile. Great for exploration!
But if I were to incorporate that functionality into a script I would do:
Get-ChildItem -Path $Home -Filter *.ps1 -Recurse |Select-Object -ExpandProperty FullName
not just for the reasons you mentioned, but also for consistency and readability - if a colleague of mine comes along and maybe isn't familiar with the shortcuts I'm using, he'll still be able to discern the meaning and expected output from the pipeline.
Note: There are currently three open issues on GitHub to add warning rules for this in PSScriptAnalyzer - I'm sure the project maintainers would love a hand with this :-)

How to change default output Formatting of Powershell to use Format-Table -autosize?

How can I enforce powershell to use
Format-Table -auto
as a default formatting when writing a returned array of objects to the console?
Thanks
If you are OK calling the cmdlet every time and if you have at least PowerShell v3.0 then you can set a $PSDefaultParameterValues which you can read more about at about_Parameters_Default_Values.
The syntax that would satisfy your need would be:
$PSDefaultParameterValues=#{"<CmdletName>:<ParameterName>"="<DefaultValue>"}
So we add in the switch by setting it to $true.
$PSDefaultParameterValues = #{"Format-Table:Autosize"=$true}
To remove this you would have to do it much the same as you would a hashtable element
$PSDefaultParameterValues.Remove("Format-Table:Autosize")
From the aforementioned article here is some pertinent information as to how to deal with these.
$PSDefaultParameterValues is a preference variable, so it exists only in the session
in which it is set. It has no default value.
To set $PSDefaultParameterValues, type the variable name and one or more key-value pairs
at the command line.
If you type another $PSDefaultParameterValues command, its value replaces the original
value. The original is not retained.
To save $PSDefaultParameterValues for future sessions, add a $PSDefaultParameterValues
command to your Windows PowerShell profile. For more information, see about_Profiles.
Outside of that I am not sure as it would be difficult to change in a dynamic sense. You would want to be sure that data sent to the stream appears on screen in the same way that format-table -auto does but you would have to make sure that it does not affect data so that you could not capture it or send it down the pipe.
You are looking at creating custom output format files, like Frode F. talks about, then you would need to consider looking at about_Format.ps1xml but you would need to configure this for every object that you would want to display this way.
FileSystem.format.ps1xml, for example, would govern the output from Get-ChildItem. Format-Table is more dynamic and I don't think you can say just use Format-Table in that file.

How to Remove the Hidden attribute from a text file

Powershell Version: 4.0
Operating System: Windows 7
"Error Report" | Set-Content $errorText
$getError = Get-Item $errorText
$getError.Attributes ="Hidden"
I've created an error log file which will remain hidden unless their is an error. How would I remove the hidden attribute so that I could see my file? In other words what is the equivalent of right clicking the file, selecting properties, and unchecking hidden attribute in powershell?
Attributes property is of type [System.IO.FileAttributes]. Looking at TechNet you can see the valid options for setting attributes on file. As per the comments one option you have is no remove all attributes from the file/folder.
Normal - The file is a standard file that has no special attributes. This attribute is valid only if it is used alone.
Be aware that this would potentially remove other attributes like read-only or system. In your case that might not be a concern but we need to be aware of the possibility.
The related second issue about using Get-Item on hidden files is solved by using the switch -Force and explained on TechNet as well.
Allows the cmdlet to get items that cannot otherwise be accessed, such as hidden items.
Knowing that we could do something like this:
$getError = Get-Item $errorText -Force
$getError.Attributes ="Normal"

Windows Powershell directory specific functions

How I can create functions inside my $profile file that will be executed only if I am inside some specific path when trying to execute them?
There is nothing built into PowerShell to effectively hide a command based on any sort of context (e.g. your current directory.)
In PowerShell V3 or greater, there are some event handlers around command lookup that you could use. One solution would look something like this:
$ExecutionContext.InvokeCommand.PreCommandLookupAction = {
param([string]$commandName,
[System.Management.Automation.CommandLookupEventArgs]$eventArgs)
if ($commandName -eq 'MyCommand' -and $pwd -eq 'some directory')
{
$eventArgs.StopSearch = $true
}
}
Your profile is evaluated at PowerShell start up so current directory doesn't really come into play. Any function inside the profile will be available as soon as your able to use the PowerShell console. You could re-implement the tabexpansion2 function to not tab-complete certain functions based on the current directory but that seems a bit over-the-top. Another option would be to override the prompt function and depending on the current directory, set the function's visibility to either public or private. If they are private, they won't show up in tab expansion e.g.:
$func = Get-Command MyFunc
$func.Visibility = 'private' # or 'public'