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
To access or make changes to registry in a windows machine by powershell, I see two ways
cd HKLM:\ (or set-location -path
HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion)
Get-childitem
or
Get-Item -path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Get-ItemProperty , New-ItemProperty , Set-ItemProperty
When to use one over the other?
They are both necessary, because the property values aren't accessible on the Item objects (and you can't see the nested "child" container items with the ItemProperty commands).
My 2c: the registry provider was written by someone as a demo, and then shipped and now they're afraid to change it ... it's the only way to explain the whole "ItemProperty" thing.
Basically, when they mapped the registry to the PowerShell Provider semantics, instead of having "Container" and "Leaf" items, there are only containers, and each container has properties (and/or child containers).
So if you do Get-ChildItem HKCU:\SOFTWARE\Microsoft you get a response back listing the "Name" of each of the child containers (which the Registry Editory (Regedit.exe) would show as folders), and listing the values in them under the heading "Property" -- but that listing is purely in the display, and the Property field on the object you got back is actually just a string array listing the names of the properties so you know what you can do next:
If you want to actually read the values in a way that makes them accessible to your script, you need to use Get-ItemProperty
If you want to change the value, you need to use Set-ItemProperty
To create new ones, you need to use New-ItemProperty
In your example, for instance, you might see SecurityHealth:
But it's like the screenshot above, as a human, you can see the value, but your script can't read the value...
You have to use Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run to get an object back that actually has the SecurityHealth property with the C:\WINDOWS\System32\SecurityHealthSystray.exe value...
My script is supposed to rename c:\myfolder\myfile.txt to myfile.bak
Rename-Item "c:\myfolder\myfile.txt" -NewName "myfile.bak"
However, it leaves myfile.txt in place and creates a new file called myfile.bak instead
Does anyone know why?
If its a hidden or read-only file, you have to add the -force parameter:
Forces the cmdlet to rename items that cannot otherwise be changed,
such as hidden or read-only files or read-only aliases or variables.
The cmdlet cannot change constant aliases or variables. Implementation
varies from provider to provider. For more information, see
about_Providers.
I was used to a few command line tricks in Windows that increased my productivity a lot.
Now I am told that I should move to PowerShell because it's more POWERful. It took me a while to get a little bit hang of it (objects, piping, etc.), and there are a lot of great tutorials on how to get a few things done.
However, some (relatively) basic trick still puzzle me. For instance, what is the equivalent of the FOR structure in PowerShell?
For example,
FOR %i IN (*.jpg) DO Convert %i -resize 800x300 resized/%i
The above line takes all of photos in a folder and uses the ImageMagick's Convert tool to resize the images and restores the resized imaged in a sub-folder called RESIZED.
In PowerShell I tried the command:
Dir ./ | foreach {convert $_.name -resize 800x300 resized/$_name}
This can't work despite all of the googling around I did. What is missing?
Note that / rather than \ is used as the path separator in this answer, which works on Windows too and makes the code compatible with the cross-platform PowerShell Core editions.
tl;dr:
$convertExe = './convert' # adjust path as necessary
Get-ChildItem -File -Filter *.jpg | ForEach-Object {
& $convertExe $_.Name -resize 800x300 resized/$($_.Name)
}
Read on for an explanation and background information.
The equivalent of:
FOR %i IN (*.jpg)
is:
Get-ChildItem -File -Filter *.jpg
or, with PowerShell's own wildcard expressions (slower, but more powerful):
Get-ChildItem -File -Path *.jpg # specifying parameter name -Path is optional
If you're not worried about restricting matches to files (as opposed to directories), Get-Item *.jpg will do too.
While dir works as a built-in alias for Get-ChildItem, I recommend getting used to PowerShell's own aliases, which follow a consistent naming convention; e.g., PowerShell's own alias for Get-ChildItem is gci
Also, in scripts it is better to always use the full command names - both for readability and robustness.
As you've discovered, to process the matching files in a loop you must pipe (|) the Get-ChildItem command's output to the ForEach-Object cmdlet, to which you pass a script block ({ ... }) that is executed for each input object, and in which $_ refers to the input object at hand.
(foreach is a built-in alias for ForEach-Object, but note that there's also a foreach statement, which works differently, and it's important not to confuse the two.)
There are 2 pitfalls for someone coming from the world of cmd.exe (batch files):
In PowerShell, referring to an executable by filename only (e.g., convert) does not execute an executable by that name located in the current directory, for security reasons.
Only executables in the PATH can be executed by filename only, and unless you've specifically placed ImageMagick's convert.exe in a directory that comes before the SYSTEM32 directory in the PATH, the standard Windows convert.exe utility (whose purpose is to convert FAT disk volumes to NTFS) will be invoked.
Use Get-Command convert to see what will actually execute when you submit convert; $env:PATH shows the current value of the PATH environment variable (equivalent of echo %PATH%).
If your custom convert.exe is indeed in the current directory, invoke it as ./convert - i.e., you must explicitly reference its location.
Otherwise (your convert.exe is either not in the PATH at all or is shadowed by a different utility) specify the path to the executable as needed, but note that if you reference that path in a variable or use a string that is single- or double-quoted (which is necessary if the path contains spaces, for instance), you must invoke with &, the call operator; e.g.,
& $convertExe ... or & "$HOME/ImageMagic 2/convert" ...
PowerShell sends objects through the pipeline, not strings (this innovation is at the heart of PowerShell's power). When you reference and object's property or an element by index as part of a larger string, you must enclose the expression in $(...), the subexpression operator:
resized/$($_.Name) - Correct: property reference enclosed in $(...)
resized/$_.Name - !! INCORRECT - $_ is stringified on its own, followed by literal .Name
However, note that a stand-alone property/index reference or even method call does not need $(...); e.g., $_.Name by itself, as used in the command in the question, does work, and retains its original type (is not stringified).
Note that a variable without property / index access - such as $_ by itself - does not need $(...), but in the case at hand $_ would expand to the full path. For the most part, unquoted tokens that include variable references are treated like implicitly double-quoted strings, whose interpolation rules are summarized in this answer of mine; however, many additional factors come into play, which are summarized here; edge cases are highlighted in this question.
At the end of the day, the safest choice is to double-quote strings that contain variable references or subexpressions:
"resized/$($_.Name)" - SAFEST
Use:
Get-ChildItem | foreach {convert $_.name -resize 800x300 resized/$($_.name)}
Or, perhaps, you need to pass the full name (with path), also showing a shorter syntax (using aliases):
gci | % {convert $_.fullname -resize 800x300 resized/$($_.name)}
Also, you might want to supply the full path to the executable.
Revised based on comments given below
There are many applications with the name "Convert". If I do
Get-Command Convert
on my computer. It shows me an app that is part of the Windows system. If PowerShell is running the wrong app on you, it's never going to work.
The solution will be to point PowerShell at the convert tool inside the ImageMagick program folder. A Google search on "ImageMagick PowerShell" will lead you to lots of people who have faced the same problem as you.
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"