My folder structure: C:\example\latest.
I want to check if the subfolder latest already exists or not. If it does, I want to rename it as latest_MMddyyyy and then create a new folder called latest.
If it does not have latest already, then simple create the folder.
This is what I have:
param (
$localPath = "c:\example\latest\" #"
)
#Creating a new directory if does not exist
$newpath = $localPath+"_"+((Get-Date).AddDays(-1).ToString('MM-dd-yyyy'))
If (test-path $localPath){
Rename-Item -path $localpath -newName $newpath
}
New-Item -ItemType -type Directory -Force -Path $localPath
It is doing two things:
Rename my latest folder as _MM-dd-yyyy but I want it to rename as "latest_MM-dd-yyyy"
Throw an error: Missing an argument for parameter 'ItemType'. Specify a parameter of type 'System.String' and try again.
what am I doing wrong?
Throws an error: Missing an argument for parameter 'ItemType'. Specify a parameter of type 'System.String' and try again.
As Deadly-Bagel's helpful answer points out, you're missing an argument to -ItemType and instead follow it with another parameter, -Type, which, in fact, is an alias for -ItemType - so removing either -ItemType or -Type will work.
To find a parameter's aliases, use something like (Get-Command New-Item).Parameters['ItemType'].Aliases
Renames my latest folder to _MM-dd-yyyy, but I want latest_MM-dd-yyyy.
You append the date string directly to $localPath, which has a trailing \, so $newPath looks something like 'c:\example\latest\_02-08-2017', which is not the intent.
Ensuring that $localPath has no trailing \ fixes the problem, but do note that Rename-Item generally only accepts a file/directory name as a -NewName argument, not a full path; you can only get away with a full path if its parent path is the same as the input item's - in other words, you can only specify a path if it wouldn't result in a different location for the renamed item (you'd need the Move-Item cmdlet to achieve that).
Split-Path -Leaf $localPath offers a convenient way of extracting the last path component, whether or not the input path has a trailing \.
In this case: latest
Alternatively, $localPath -replace '\\$' would always return a path without a trailing \.
In this case: c:\example\latest
If we put it all together:
param (
$localPath = "c:\example\latest\" #"# generally, consider NOT using a trailing \
)
# Rename preexisting directory, if present.
if (Test-Path $localPath) {
# Determine the new name: the name of the input dir followed by "_" and a date string.
# Note the use of a single interpolated string ("...") with 2 embedded subexpressions,
# $(...)
$newName="$(Split-Path -Leaf $localPath)_$((Get-Date).AddDays(-1).ToString('MM-dd-yyyy'))"
Rename-Item -Path $localPath -newName $newName
}
# Recreate the directory ($null = ... suppresses the output).
$null = New-Item -ItemType Directory -Force -Path $localPath
Note that if you run this script more than once on the same day, you'll get an error on renaming (which could easily be handled).
try this
$localPath = "c:\temp\example\latest"
#remove last backslash
$localPath= [System.IO.Path]::GetDirectoryName("$localPath\") #"
#create new path name with timestamp
$newpath ="{0}_{1:MM-dd-yyyy}" -f $localPath, (Get-Date).AddDays(-1)
#rename old dir if exist and recreate localpath
Rename-Item -path $localpath -newName $newpath -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $localPath
New-Item -ItemType -type Directory -Force -Path $localPath
You're using -ItemType but not providing it a value, use this:
New-Item -ItemType Directory -Force -Path $localPath
To rename a folder, use the command: Rename-Item e.g
Rename-Item Old_Folder_Name New_Folder_Name
Related
I am in need of some assistance, I am new to PowerShell and am trying to use it to make some of my work easier. I am writing a PowerShell script to copy JPG files from one location (C:\Pictures\People\People) and moving them to a new location.
The issue is that in this new location I need to create a folder with the same name as the JPG and then another subfolder with the same name again as the JPG.
So I need to move images from C:\Pictures\People\People which I will call JPG_Image to C:\Pictures\JPG_Name\JPG_Name\'JPG_Image'
So far I found and have been working with this:
$SourceFolder = "C:\Pictures\People\People"
$TargetFolder = "C:\Pictures\"
# Find all files matching *.JPG in the folder specified
Get-ChildItem -Path $SourceFolder -Filter *.jpg |
ForEach-Object {
$ChildPath = Join-Path -Path $_.Name.Replace('.jpg','') -ChildPath $_.Name
[System.IO.FileInfo]$Destination = Join-Path -Path $TargetFolder -ChildPath $ChildPath
# Create the directory if it doesn't already exits
if( -not ( Test-Path -Path $Destination.Directory.FullName ) ){
New-Item -ItemType Directory -Path $Destination.Directory.FullName
}
Copy-Item -Path $_.FullName -Destination $Destination.FullName
}
You are making this harder on yourself than needs be.
Some enhancements to your code:
Add switch -File to the Get-ChildItem cmd so you do not also get DirectoryInfo objects
To get the filename without extension, there is a property .BaseName
Join-Path returns a string, no need to cast that into a [System.IO.FileInfo] object
If you add -Force to the New-Item cmd, there is no need to check if a folder already exists, because that will make the cmdlet either create a new folder or return the existing DirectoryInfo object.
Because we don't need that object (and the console output from it), we can just throw that away using $null = New-Item ...
Putting it all together:
$SourceFolder = "C:\Pictures\People\People"
$TargetFolder = "C:\Pictures"
# Find all files matching *.JPG in the folder specified
Get-ChildItem -Path $SourceFolder -Filter '*.jpg' -File |
ForEach-Object {
# Join-Path simply returns a string containing the combined path
# The BaseName property is the filename without extension
$ChildPath = Join-Path -Path $_.BaseName -ChildPath $_.BaseName
$Destination = Join-Path -Path $TargetFolder -ChildPath $ChildPath
# Create the directory if it doesn't already exits
# Using -Force will not give an error if the folder already exists
$null = New-Item -Path $Destination -ItemType Directory -Force
$_ | Copy-Item -Destination $Destination
}
How can I search for a specific file extension recursively through out the entire directory structure, for each file/extension found create a folder at the file location using each file's name, and move the file/s to its own folder (that matches the files name)?
Thank you #Alex_P: The following code creates only one folder, and moves ALL the files found into this folder. Is there a way to make it create a folder for each item and then move each item to its corresponding folder. Appreciate your help.
$_ = (Get-ChildItem -Path "C:\3\ML\300000-310000S\302355\OLn2" -Recurse -File | Where-Object { $_.Extension -eq '.MCX-5' })
ForEach-Object {
New-Item -Path $_[0].PSParentPath -Name $_[0].BaseName -ItemType Directory
$newpath = Join-Path -Path $_[0].PSParentPath -ChildPath $_[0].BaseName
Move-Item -Path $_.FullName -Destination $newpath -Force
}
Get-ChildItem returns System.IO.FileInfo objects. You can use their property 'Extension' to filter for file extensions.
This example will give you all PDF files:
$files = Get-ChildItem -Path .\Documents\ -Recurse -File | Where-Object { $_.Extension -eq '.pdf' }
In order to move the files you can use some other, useful properties of the object. .PSParentPath gives you the path up to the directory of your object. .BaseName gives you the file name, excluding the extension.
New-Item -Path $files[0].PSParentPath -Name $files[0].BaseName -ItemType Directory
Now, in order to move your item, you need to concatenate your path with your new directory and then you can move the item to your new directory. .Fullname gives you the full path of the object.
$newpath = Join-Path -Path $files[0].PSParentPath -ChildPath $files[0].BaseName
Move-Item -Path $files[0].FullName -Destination $newpath
In my case, I only moved one item but you need to add these to your foreach loop.
I have a function that looks at some registry settings for SQL Server which just pulls put the data and log location and puts them in variables. But I run into an issue when I pass them into Move-Item. Basically:
fnGetDataNLog
Returns $datalocation, $loglocation
When I run Move-Item -Path $datalocaton -Destination $loglocation I get
Cannot bind argument to parameter 'path' because it does not exist.
Is that due to its passing a runtime variable? Is there another way to do that then.
You can run a Test-Path to ensure the location exists.
If you $Datalocation is a UNC path to a directory you can do the below. eg. $Datalocation = '\\UNC\Path\To\Folder'
If(-not (Test-Path -Path $Datalocation)) {
New-Item -Path $Datalocation -ItemType Directory
}
Move-Item -Path $Datalocation-Destination $loglocation
This will test if the path at $Datalocation exists, if -not then it will create it.
if the UNC path is a string that goes to a file, ie. not an object result from a Get-ChildItem, then you can use a bit of regex to get the parent folder and then do the below. The regex will remove everything after the last \.
eg. \\UNC\Path\To\Folder\File.txt becomes \\UNC\Path\To\Folder\
If(-not (Test-Path -Path ($Datalocation -replace '[^\\]+$'))) {
New-Item -Path $Datalocation -ItemType Directory
}
Move-Item -Path $Datalocation -Destination $loglocation
the paths are like this and none of these directory exist:
"D:\temp\test\abc.txt"
"D:\temp2\test2\abc2.txt"
"D:\temp1\abc.txt"
I am trying to split the path and create directories only.
I am trying below:
New-Item -Path "D:\temp\testing\abc.txt" -ItemType file
Split-Path -Path "D:\temp\testing\abc.txt" -Resolve –IsAbsolute
[edit - didn't see the comment by Tuttu. [*blush*] i will leave this here, but that one is the 1st answer.]
i think what you are looking for is the Split-Path cmdlet. [grin] something like this ...
$PathList = #(
'c:\temp\test1\abc.txt'
'c:\temp\test2\subtest2-1\abc2.txt'
'c:\temp\test3\subtest3-1\subtest3-1-1\abc.txt'
)
foreach ($PL_Item in $PathList)
{
$NewDir = Split-Path -Path $PL_Item -Parent
if (-not (Test-Path -LiteralPath $NewDir))
{
$Null = New-Item -Path $NewDir -ItemType Directory -Force
}
}
that made 3 new directories, two of them with sub-directories.
note that this does NOT take into account any input path that has no terminating file ... you will always get the parent path.
I am trying to write powershell Script which will create backupfolder on same Path where Application exist and need to copy the folders & files into backupfolder before deploying. Below are the command was using to perform but am getting error
$Source = "C:\XYZ"
$BackupFolder = New-Item -ItemType Directory -Force -Path $source_$(Get-Date)
Copy-Item -Path $Source\* $BackupFolder -Force
Error: Cannot copy item C:\XYZ\Backup_18-02-2017 on to itself
Try:
Copy-Item $Source\* $BackupFolder -Exclude $BackupFolder
That will eliminate the folder that you are copying into as a source that is being copied from.
Variables can contain underscores. The following works and displays the string "asdf"
$a_ = "adsf"; $a_
Your New-Item cmdlet call should have failed since $source_ is not a variable and would return null. This is default behavior for PowerShell. When I run your code as is I get the following:
New-Item : Cannot find drive. A drive with the name '02/18/2017 22' does not exist.At line:1 char:1
+ New-Item -ItemType Directory -Force -Path "$source_$(Get-Date)" -what ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (02/18/2017 22:String) [New-Item], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.NewItemCommand
So I would have expected your folder variable to be null. wOxxOm brings this up in comment as well
Several options to address what I am sure is the partial source of your issue.
$BackupFolder = New-Item -ItemType Directory -Force -Path "$source`_$(Get-Date)"
$BackupFolder = New-Item -ItemType Directory -Force -Path "$($source)_$(Get-Date)"
$BackupFolder = New-Item -ItemType Directory -Force -Path ("{0}_{1} -f "$source, Get-Date)
You will still have to try and exclude this folder from the copy as well like Keith Hill's answer is telling you
Copy-Item $Source\* $BackupFolder -Exclude $BackupFolder
try Something like this
$Source = "C:\XYZ"
$Destination="{0}{1:yyyyMMdd}" -f $source, (Get-Date)
New-Item -ItemType Directory -Force -Path $Destination
Copy-Item -Path $Source\* $Destination -Recurse -Force
If I understand the question correctly. You want to take "C:\XYZ" and backup into the same directory called "C:\XYZ\backup_$DATE". What you will actually do is create a loop that will break once it reaches the max 248 characters. If we use the -exclude option then we can exclude the backup directory "C:\XYZ\backup_$DATE".
This function will do the trick and also gives you error handling.
Function Get-CopyDirectory{
#####################
# Dynamic Variables #
#####################
$Date = Get-Date -format ddMM-yyyy
$Exclude="Backup*"
####################
# Static Variables #
####################
$AppPath = "F:\Test\"
$BackupPath = "$AppPath\BACKUP_$Date\"
if (Test-Path $BackupPath) {
Write-Host "Backup Exist" -f Cyan
}
else
{
Copy-Item "$AppPath\*" $BackupPath -Exclude $Exclude -recurse -verbose
}
}
CLS
Get-CopyDirectory