mkdir vs New-Item , is it the same cmdlets? - powershell

I found that there are two different cmdlets : New-Item and mkdir, firstly I was thinking that mkdir is one of aliases of New-Item, but it is not:
Try to get aliases of it, it is md for mkdir and ni for New-Item :
So I am a little bit confused, what the difference between that cmdlets, because powershell reference gives me almost the same pages: mkdir, New-Item
But New-Item is in Microsoft.PowerShell.Management and mkdir in Microsoft.PowerShell.Core , but the do the same(or not?)! Why there are two same cmdlets in powershell?

New-Item is a cmdlet, defined in an assembly, which creates new objects - both files and directories. mkdir is a function which calls New-Item to create directories specifically. It is provided for convenience to shell users who are familiar with Windows CMD or unix shell command mkdir
To see the definition of mkdir use Get-Content Function:\mkdir. You can see that it calls New-Item under the covers, after some parameter and pipeline management. Using PS 5.0:
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('New-Item', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd -Type Directory #PSBoundParameters }
Both of the following commands will create a new directory named foo in the root of C:\. The second form is familiar to people coming from other shells (and shorter to type). The first form is idiomatic PowerShell.
PS> New-Item -Path C:\foo -Type Directory
PS> mkdir C:\foo
Because mkdir hardcodes the -Type Directory parameter, it can only be used to create directories. There is no equivalent mkfile built-in function. To create files, use New-Item -Type File, or another cmdlet such as Out-File.

Related

powershell equivalent of linux "mkdir -p"?

How can I get the powershell "mkdir" command to act exactly like Linux's mkdir -p command?
Under Linux, mkdir -p will create nested directories, but only if they don't exist already. For example, suppose you have a directory /foo that you have write permissions for. mkdir -p /foo/bar/baz creates bar and baz within bar under existing /foo. You run the same command over again, you will not get an error, but nothing will be created.
You can ignore errors in PowerShell with the -ErrorAction SilentlyContinue parameter (you can shorten this to -ea 0). The full PowerShell command is
New-Item /foo/bar/baz -ItemType Directory -ea 0
You can shorten this to
md /foo/bar/baz -ea 0
(You can also type mkdir instead of md if you prefer.)
Note that PowerShell will output the DirectoryInfo object it creates when using New-Item -ItemType Directory (or the md or mkdir aliases). If you don't want any output, you can pipe to Out-Null.
The PowerShell equivalent of Unix
mkdir -p ...
is
$null = New-Item -Type Directory -Force ...
-Force, like -p, implements desired-state logic, which ensures two things:
It creates intermediate directories in the target directory path that may not exist yet on demand (New-Item -Type Directory, unlike Unix mkdir, even does that by default).
It succeeds if the target directory already exists.
One crucial difference: Unless an error occurs:
mkdir -p produces no output.
By contrast, New-Item -Type Directory outputs a [System.IO.DirectoryInfo] instance representing the target directory. Thus, to emulate the behavior of mkdir -p, this output must be discarded, which is best done by assigning to $null ($null = New-Item ...)
Caveat:
On Windows, mkdir is a built-in wrapper function that passes arguments through to New-Item -Type Directory
On Unix-like platforms - in the cross-platform PowerShell [Core] v6+ edition - mkdir is not a built-in command, and instead defers to the platform-native external mkdir utility.
Thus, if your scripts need to be cross-platform, use New-Item explicitly.
Note: If you omit -Force and simply ignore errors, as shown in Bill Stewart's answer (with -ErrorAction SilentlyContinue or -ErrorAction Ignore), you get similar behavior, except that the output behavior will vary situationally:
If the target directory already exists, no output is produced (because an error occurs that is ignored), whereas if the target directory is created, a [System.IO.DirectoryInfo] instance representing it is returned.
A fundamental difference between New-Item -Type Directory and Unix mkdir is that only the former creates intermediate directories on demand by default.
mkdir only does so with -p.
New-Item -Path "c:\some\folder\path" -ItemType Directory
What about using mkdir with -Force? That seems to work for me, it will create all the directories from the specified path, and won't result in an error if they already exist.
mkdir path/to/my/target/dir -force
Results in:
PS > mkdir path/to/my/target/dir -force
Directory: C:\Users\Sam\path\to\my\target
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 25/09/2020 13:18 dir
# We can check that all directories have been created
PS > tree path
C:\USERS\SAM\PATH
└───to
└───my
└───target
└───dir
# Let's run again now that the directories already exist
PS > mkdir path/to/my/target/dir -force
Directory: C:\Users\Sam\path\to\my\target
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 25/09/2020 13:20 dir
# And check the result of the previous command
PS > $?
True

PowerShell New-Item Positional Parameter Oddities

Given the Microsoft documentation for PowerShell, I can see no reason why the following code should fail with the given error. Then again, PowerShell can fail when a script just gets too long. All the paths are double-quote strings.
##### ALGORITHM Take in keystore path, make a backup in an adjacent directory
$ksPath = $java_store_path.Substring(0, $java_store_path.LastIndexOf('\') + 1)
$backupPath = $ksPath + "backups"
New-Item $backupPath PowerShell -type directory -force
New-Item : A positional parameter cannot be found that accepts argument 'PowerShell'.
https://technet.microsoft.com/en-us/library/ee176914.aspx
New-Item c:\scripts\Windows PowerShell -type directory
If that's valid, mine should be too. I'm running on Server 2012 R2.
The example on that page is just plain wrong. It seems they meant to refer to the path C:\Scripts\WindowsPowerShell or they forgot to quote the directory with spaces in it.
So it should have been one of these:
New-Item c:\scripts\WindowsPowerShell -type directory
New-Item 'c:\scripts\Windows PowerShell' -type directory
New-Item "c:\scripts\Windows PowerShell" -type directory
Ask yourself, what would PowerShell alone have been referring to? What parameter would it have corresponded to?
Edit: as the commenters have pointed out, the example was supposed to show the nameSet parameters, where a separate -Path and -Name are specified, and purportedly PowerShell was supposed to be a value to the -Name parameter. That does look correct. The reason the example didn't work (and yours as well), is because the -Name parameter cannot be specified positionally, which you can see in the MSDN article I linked to below, and in the built-in help:
Type: String
Parameter Sets: nameSet
Aliases:
Required: True
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
In that case, their example should have been something like these:
New-Item c:\scripts\Windows -Name PowerShell -type directory
New-Item -Path c:\scripts\Windows -Name PowerShell -type directory
So reiterating, named parameters would have worked here, and would have avoided confusion.
Generally, you shouldn't be using positional parameters in scripts, unless they're extremely clear (and even then, I'd recommend avoiding).
Using named parameters would have made this easier to figure out. And tab-completion helps with filling in the parameter names and in completing paths (usually with proper quoting too).
I think you should change yours to:
New-Item -Path $backupPath -Type Directory -Force
And looking over that technet article, it's really not so good. The MSDN article on New-Item is better, and this is the information you should see when running Get-Help New-Item as well.
Side question:
Then again, PowerShell can fail when a script just gets too long.
What?

Setting an alias with attributes in PowerShell

I wanted to set an alias for listing files in the directory, but Set-Alias -name lf -value ls -file does not seem to work. I intend to use this the Unix alias way.
An alias can't do that. From the help for Set-Alias:
You can create an alias for a cmdlet, but you cannot create an alias for a command that consists of a cmdlet and its parameters.
However, using a technique called "splatting", a function can do it easily:
function lf {
ls -file #args
}
For more information, see help about_splatting.
Example 5 from Get-Help Set-Alias -Full is what you want:
Function lsfile {Get-Childitem -file}
Set-Alias lf lsfile
Append to the answer from #mike-z .
You can put the function definition into the PowerShell profile so that you can reuse it opening shell again.
test-path $profile
// Ensure it doesn't exists before creating the profile!
new-item -path $profile -itemtype file -force
notepad $profile
Simply put the code into the file:
function lf { ls -file #args }
You can check the details from official documentation.

Create a folder alias in PowerShell

I know that I can create variable that represents a folder path in my profile. For example,
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
Is there an easy way to create an alias to a directory in PowerShell?
Create an alias
PS> Create-FolderAlias -name $foo -path "C:\Program Files"
Create an alias based on another alias
PS> Create-FolderAlias -name $bar -path $foo + "\Microsoft"
Use alias as expected
PS> cd $foo
It would be nice if these aliases would be persisted between sessions.
You can turn a folder into a new powershell drive with New-PSDrive
New-PSDrive foo filesystem 'C:\Program Files'
New-PSDrive bar filesystem 'foo:\Microsoft'
cd foo:
To persist between sessions you could add them to your profile script ($profile).
But of course you can also cd to a folder from a variable
$foo = 'C:\Program Files'
$bar = Join-Path $foo 'Microsoft'
cd $foo
An alternative solution is to write a function that cd's to that directory. For me, this yields the least amount of typing to get where I want. For instance, I put the following function in my profile.ps1:
# quickly cd to folder
function <short name> {
cd <path to directory>
}
Then, in Powershell:
PS> <short name>
I'll just elaborate on #en casa's response and add a concrete example.
Open powershell's equivalent of .bash_profile:
notepad $profile
Add aliases
function code { cd C:\Users\john\code }
function work { cd C:\Users\john\work }
function stuff { cd C:\Users\john\stuff }
Restart PS and type PS> code to get to the code folder.

How to create a Hardlink using the New-Hardlink PowerShell PSCX command

I want to create a new Hardlink with the PowerShell Community Extensions PSCX commandlet New-Hardlink http://pscx.codeplex.com/. I have read the man file and tried almost every combination of commands but it won't work. What am I missing? (I know about fsutil, but I want to use this commandlet/alias)
Here is the directory structure:
E:\Source
E:\Test
Here are some variations of the command that I have tried:
New-Hardlink E:\Test\Source E:\Source
New-Hardlink -Path:"E:\Test\Source" -Target:"E:\Source"
New-Hardlink E:\Source E:\Test\Source
New-Hardlink E:\Source E:\Test\
New-Hardlink -P:"E:\Source" -T:"E:\Test\Source"
Here is the supposed syntax:
New-Hardlink [-Path] <String> [-Target] <String> [<CommonParameters>]
-Path <String>
Path to the new link.
-Target <String>
Target of the link.
The result is always some from of:
New-Hardlink : Unable to find the file 'E:\Source.
Does this command not work with directories but only with files?
I will sheepishly answer my own question.
Yes, indeed Hardlinks refer to files. To accomplish this with directories the New-Junction command should be used like so:
New-Junction E:\Test\Dest E:\Source
The first parameter refers to the location you would like to place the new Junction.
The second parameter refers to the directory you wish to Junction
Powershell 5+ include a native way to create any types of hard-/soft-links and junctions.
For those coming from Google:
PowerShell 5.0 and above have support for creating Symbolic Links and Junctions using the New-Item cmdlet.
In the following, clicking on B.txt will take you to A.txt. Similarly for a directory.
# To create a symbolic link on a file:
New-Item -ItemType SymbolicLink -Name B.txt -Target A.txt
New-Item -ItemType SymbolicLink -Path C:\Temp\B.txt -Value A.txt
# To create a hard-link on a file:
New-Item -ItemType HardLink -Path C:\B.txt -Value C:\A.txt
# To create a symbolic link on a directory:
New-Item -ItemType SymbolicLink -Name B_Directory -Target C:\A_Directory
# To create a junction on a directory:
New-Item -ItemType Junction -Path C:\Junction -Value C:\A_Directory