Can't create a folder, based on file name - powershell

I'm trying to create a script that will copy over specific folders and files in C:\Users\ from three terminal servers, onto a file server.
The problem is, that I create the folders on the file server based on the name of the folder i'm copying. And the script fails when it trys to create a folder on the file server, based on a file instead of a folder.
(Sorry that the text on the image is in Danish! - Hope it still might help.)
I hope the script makes more sense, thanks! :)
Image: http://imgur.com/kxbzXXK
$ServerList = "\\ServerA", "\\ServerB" #Angiv hvilke servere der skal kopires fra, f.eks "\\serverA", "\\serverB".
$FromDir = "\C$\Users\" #Angiv hvilken sti der skal kopires fra, f.eks "\c$\TEST"
$ToDir = "C:\DavidTest_DataMappe\"
foreach ($Server in $ServerList)
{
$RemotePath = $Server + $FromDir
$RemoteDirs = Get-ChildItem $RemotePath |? {$_.mode -match "d"}
foreach($Username in $RemoteDirs | where-object {$_.Name.Length -le 4})
{
$FileList = "\Desktop",
#"\Documents",
#"\Music",
#"\Pictures",
#"\Videos",
#"\Favorites",
#"\Links"#,
"\AppData\Local\Google\Chrome\User Data\Default\Bookmarks",
"\AppData\Roaming\Mozilla\Firefox\Profiles\*.default\places.sqlite"
foreach($File in $FileList)
{
ECHO "Copying folder"
$ToDirPlusUser = $ToDir + $Username + $File
$CopyFile = $RemotePath + $Username + $File
Copy-Item $CopyFile $ToDirPlusUser -Recurse
}
}
}
ECHO "***********"
ECHO "***********"
ECHO "Script Done"
ECHO "***********"
ECHO "***********"

Also add this line above copy-item
Write-Host "Copy-Item $CopyFile $ToDirPlusUser -Recurse"
It will help you zone in on which file/directory is creating the error.

Related

Unable to delete or rename directories or Files with Multiple Square ([[...]] brackets in Path [duplicate]

This question already has answers here:
How can I make PowerShell handle [ or ] in file name well?
(2 answers)
Error "Could not find a part of the path" while setting attributes on an existing file
(2 answers)
Closed 4 months ago.
This post was edited and submitted for review 4 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I have regular Jobs to clean up old User Windows-Profile directories on a central NAS.
Last time I had Directories containing double square Brackets in the path (Import from Macromedia or so). This looks like:
\server.ad.local\HOME1\Username\System\Anwendungsdaten\Macromedia\FlashPlayer\SharedObjects\G5EUZBX2\www.daserste.de\[[IMPORT]]\players.edgesuite.net\flash\plugins\osmf\advanced-streaming-plugin\v3.4\osmf2.0\AkamaiAdvancedStreamingPlugin.swf\HDCore.sol
As this Job should run automatically with Powershell I tired various things:
Tried to replace the brackets an rename the folder - no success
Tried LiteralPath for Remove-Item - no success
Tried to Deleted with Scripting.FileSystemObject - no success
I always get the following error Message:
The Element ... cannot be removed: A part of the Path "HDCore.sol" cannot be found.
Are there any ideas?
Tried to rename the Folder, tried remove-item with -LiteralPath, tried to use FileSystemObject.
All of the actions gave the same result: Error
Just to complete: here are the functions I used last:
Function RemoveChar
{
Param ($Path)
$Pattern = '#|&|%|\[{1,}|\]{1,}|\^|\s|\.{2,}'
if ($Path -imatch $Pattern){
Rename-Item -Path $Path -NewName ($Path -replace $Pattern,'') -ErrorAction SilentlyContinue
return ($Path -replace $Pattern,'')
} else {
return $Path
}
}
Function Truncate
{
Param ($Path)
$total_path_length_threshold = 248 # maximal erlaubte Zeichenzahl (248 für Verzeichnisse, 260 für Dateien)
$characters_to_truncate = 60 # Anzahl der zeichen, um die der name zu kürzen ist. Ein eindeutiger Index wird angehangen
$virtual_drive = "v:" # Für temp. Prozessing muss das Format "v:" haben
$collection = cmd /c dir $Path /s /b |? {$_.length -gt $total_path_length_threshold }
$count_paths = ($collection | measure).count - 1
foreach ($pathlong in $collection) {
$parent_path = Split-path -path $pathlong
subst $virtual_drive $parent_path
$leaf = split-path -leaf $pathlong
$short_virtual_path = join-path $virtual_drive $leaf
$item = Get-Item -LiteralPath $short_virtual_path
if (Test-Path -LiteralPath $item) {
$filename = $item.name
$filename_extension = $item.Extension
$basename = $item.BaseName
$basename_length = $basename.length
$new_index = "X" + $counter + "X"
$adjusted_characters_to_truncate = $characters_to_truncate + $new_index.length
if ( $basename_length -gt $adjusted_characters_to_truncate ) {
$length_to_use = $basename_length - $adjusted_characters_to_truncate
$new_filename = $basename.substring(0, $length_to_use ) + $new_index + $filename_extension
$new_path = $parent_path + $new_filename
$Path = $new_path
Rename-Item -LiteralPath $short_virtual_path -NewName $new_filename
}
}
subst v: /d
}
return $Path
}
Function removeRecursive
{
param([String] $Path)
$fso = new-object -com "Scripting.FileSystemObject"
function proc {
param($folder)
$folder.Files | foreach-object {
RemoveChar $_
}
$folder.Files | foreach-object {
$short = $fso.GetFile($_.FullName).ShortPath
LogWrite "$FullDate : Processing: $short"
$fso.DeleteFile($short,$true)
}
$folder.SubFolders | foreach-object {
proc $_
}
}
proc $fso.GetFolder($Path)
}
The function I call from main code is removeRecursive. And yes I tried Remove-Item -LiteralPath SomePath -Recursive -Force too but no success as well.

Move Folders and files from folders/subfolders with same name (copies to be renamed)

(I have tried to rewrite this to be more clear)
I have a problem with having hundreds of folders and files (each start with ABC and then numbers 001-936) that need to be moved to a single folder with the same name. For example:
C:\folders\ABC001
C:\folders\random\ABC001\
C:\folders\files\ABC001.pdf
C:\folders\ABC002.pdf
C:\folders\ABC002\
C:\folders\needs sorting\ABC002\
That I would like to move all files and folders to a folder with the same name:
C:\folders\ABC\ABC001\
C:\folders\ABC\ABC002\
and so on...
However, sometimes the orginal folder and/or file will have a duplicate in the destination folder(or may already have since folders already exist), so I want it to add to the name (1), (2), etc.
C:\folders\ABC\ABC001\ABC001\
C:\folders\ABC\ABC001\ABC001 (1)\
C:\folders\ABC\ABC001\ABC001.pdf
C:\folders\ABC\ABC002\ABC002.pdf
C:\folders\ABC\ABC002\ABC002\
C:\folders\ABC\ABC002\ABC002 (1)\
Any help would be greatly appreciated, I have been trying to solve this for weeks (everytime I needed the files) but am new to scripting/code. I started with:
for /R "C:\folders" %x in (*abc123*.*) do move "%x" "D:\folders\abc\abc123"
Closest attempt (minor edits to another code):
function MoveFileToFolder ([string]$source,[string]$destination){
# get a list of source files
$files = Get-ChildItem -Path $source -Recurse | ?{($_.PSIsContainer)}
# verify if the list of source files is empty
if ($files -ne $null) {
foreach ($file in $files) {
$filename = $file.Name
$filebase = $file.BaseName
$fileext = $file.Extension
# verify if destination file exists
$filenameNU = $filename
if (Test-Path (Join-Path $destination $filename)) {
$n = 0
while ((Test-Path (Join-Path $destination $filenameNU)) -eq $true)
{
$filenameNU = $filebase + "(" + ++$n + ")" + $fileext
}
}
Move-Item $file.FullName (Join-Path $destination $filenameNU)
}
}
}
MoveFileToFolder C:\folders\ C:\folders\abc\abc123
(I would try and run this in Powershell for each subfolder, but it became very hard to keep up with)
Thank you for reading.

Monitor Azure Files in Storage Account for event : file creation

I know I could use System.IO.FileSystemWatcher in a Powershell script to detect when a file is created in Azure files (in my storage account). Is there a better way to detect a file being created than this method ?
I can't seem to find any logs that I could perhaps parse ?
Thanks
This could do you if you really didn't want to use the FileSystemWatch
$Files = Get-ChildItem -file -Recurse "C:\Temp"
$IfOlderThan = 60
$NewlyCreated = #()
$OldCreated = #()
$Count = 0
Foreach ($file in $files){
if($file.CreationTime -gt (Get-Date).AddMinutes(-$IfOlderThan)){
$NewlyCreated += $file
} Else {
$OldCreated += $file
}
}
Write-Host "Found " -NoNewline;Write-host $($NewlyCreated.Count) -NoNewline -ForegroundColor Green; Write-Host " file\s that have been created in the last $IfOlderThan minutes"
$NewlyCreated | select Name, Fullname, CreationTime

Powershell output formatting?

I have a script that scans for a specific folder in users AppData folder. If it finds the folder, it then returns the path to a txt file. So we can see the computer name and username where it was found.
I would like to be able to format the what is actually written to the text file, so it removes everything from the path except the Computer and User names.
Script:
foreach($computer in $computers){
$BetterNet = "\\$computer\c$\users\*\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm"
Get-ChildItem $BetterNet | ForEach-Object {
$count++
$betternetCount++
write-host BetterNet found on: $computer
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" $_`n
write-host
}
}
The text files contain information like this
\\computer-11-1004S10\c$\users\turtle\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-24S\c$\users\camel\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-23S\c$\users\rabbit\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
If you have each line in a form of the string $string_containing_path then it is easy to split using split method and then add index(1) and (4) that you need:
$afterSplit = $string_containing_path.Split('\')
$stringThatYouNeed = $afterSplit[1] + " " + $afterSplit[4]
You can also use simple script that will fix your current logs:
$path_in = "C:\temp\list.txt"
$path_out= "C:\temp\output.txt"
$reader = [System.IO.File]::OpenText($path_in)
try {
while($true){
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$line_after_split_method = $line.Split('\')
$stringToOutput = $line_after_split_method[1] + " " + $line_after_split_method[4] + "`r`n"
add-content $path_out $stringToOutput
}
add-content $path_out "End"
}
finally {
$reader.Close()
}
If you split your loop into two foreach loops, one for computer and user directory it would be easier to output the name of the user directory.
$output = foreach($computer in $computers){
$UserDirectories = Get-ChildItem "\\$computer\c$\users\" -Directory
foreach ($Directory in $UserDirectories) {
$BetterNet = Get-ChildItem (Join-Path $Directory.fullname "\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm")
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" "$computer $($Directory.name)`r`n"
write-host BetterNet found on: $computer
$BetterNet
}
}
$output.count

Compare two Directories in Powershell and work with the incomparisons

I try to compare 2 Folders. A and B.
B is a Backup Folder of A. Firstly I want to check if any Files have been deleted in Folder A, if so, I want to take that corresponding File from B and move it. Then I can go ahead and RoboCopy /mir A again which will create the Backup.
My issue is how to compare the two directories (A and B have subfolders etc), and then move the Deleted File. Here is the Code which is supposed to do this task.
#region | Global Variables
$backupFolder = "Sandbox_Backup"
$UsbDisk = "C:\Users\pullrich\Desktop"
#endregion
$date = Get-Date -Format G
# Create Log that Script has been started
MyLog "--- Script has been started at $date ---" 0
$testfolder = Test-Path "$UsbDisk\$backupFolder"
# If a Backup folder already exist then Compare files and see if any changes have been made
if ( $testfolder -eq $true ) { #IF_2
# Copy deleted files to BackUp Folder
MyLog "Check for Deleted Files on Data_01:\" 0
$source = $testfolder + "\Data_01"
$sourcelist = Get-ChildItem $source -Recurse
$destination = "$UsbDisk\$backupFolder\Data_01\_DeletedFiles"
$testDestination = Test-Path $destination
if ( $testDestination -eq $false ){
mkdir $destination
}
foreach ($file in $sourcelist){
$result = test-path -path "C:\Users\pullrich\Desktop\Sandbox\Data_01*" -include $file.Name
if ( -not $result ){
$CopyFile = $file.DirectoryName + "\" + $file.Name
Copy-Item $CopyFile -Destination $destination
Remove-Item $CopyFile
}
}
# Start Synchronizing Data_01:\
MyLog "Start Synchronizing Data_01:\" 0
Robocopy "C:\Users\pullrich\Desktop\HP-Sandbox\Data_01" "$UsbDisk\$backupFolder\Data_01" /mir /r:2 /w:3 /M /XD VM_*
MyLog "Data_01:\ is up to Date" 0
} #IF_2
UPDATE 1
I kept working on the Code and figured out that the issue seems to be here:
$result = test-path -path "C:\Users\pullrich\Desktop\Sandbox\Data_01*" -include $file.Name
It will always return false, because it is not really doing what I intended it to do I guess. It's supposed to go through every File in the B folder and check if that File exists in A.
Answer
I was able to get the Script done with latkins' answer.
For reference, here is the Full script.
#region | Global Variables
$backupFolder = "Sandbox_Backup"
$UsbDisk = "C:\Users\pullrich\Desktop"
#endregion
$date = Get-Date -Format G
# Create Log that Script has been started
MyLog "--- Script has been started at $date ---" 0
$testfolder = Test-Path "$UsbDisk\$backupFolder"
# If a Backup folder already exist then Compare files and see if any changes have been made
if ( $testfolder -eq $true ) { #IF_2
# Copy deleted files to BackUp Folder
MyLog "Check for Deleted Files on Data_01:\" 0
# Set Data_01 as Source
$source = "$UsbDisk\$backupFolder\Data_01"
# Get all Items
$sourcelist = Get-ChildItem $source -Recurse
# Choose as Destination the DeletedFiles Folder
$destination = "C:\Users\pullrich\Desktop\Sandbox\Data_01\_DeletedFiles"
mkdir $destination
# Check if a File or Folder exists in the BackUp folder but not on the Server
foreach ($file in $sourcelist){
# First we have to check if the File we have in the Backup still exists on the Server; however, we do not care about the DeletedFiles Folder
if ( -not ($file.Name -eq "_DeletedFiles" )){
$fullPath = "C:\Users\pullrich\Desktop\Sandbox\Data_01" + $file.FullName.Substring($source.Length)
$result = test-path $fullPath
# If it doesn't exist then we go ahead and Copy the File to the DeletedFiles Folder on the Server,
# which will later be copied to the BackUp and then deleted of the Server
if(-not $result ){
$CopyFile = $source + $file.FullName.Substring($source.Length)
Copy-Item $CopyFile -Destination $destination -force
}
}
}
# Start Synchronizing Data_01:\
MyLog "Start Synchronizing Data_01:\" 0
Robocopy "C:\Users\pullrich\Desktop\Sandbox\Data_01" "$UsbDisk\$backupFolder\Data_01" /mir /r:2 /w:3 /M /XD VM_*
#Delete the DeletedFiles Folder from Server and keep it only on the BackUp
Remove-Item $destination
MyLog "Data_01:\ is up to Date" 0
} #IF_2
else { #Else_2
mkdir "$UsbDisk\$backupFolder"
# Start Copying Data
MyLog "Start Backing up Data_01:\" 0
Robocopy "C:\Users\pullrich\Desktop\Sandbox\Data_01" "$UsbDisk\$backupFolder\Data_01" /mir /r:2 /w:3 /XD VM_*
}
# Delete All Files in _DeleteFiles Folder which are Older than 60 Days
You could construct the full path for each potential file, rather than relying on a potentially costly recursive wildcard search.
Each $file comes from some subdirectory of $source, so the full path (given by $file.FullName) can be shortened to the "relative" path by dropping the first $source.Length chars from $file.FullName. Take your new root path and add it to this relative path, and you've got the new full path.
$fullPath = "C:\Users\pullrich\Desktop\Sandbox\Data_01" + $file.FullName.Substring($source.Length)
$result = Test-Path $fullPath