Hi this is the first time I create a program using powershell, I created a powershell script to move old files that are not in use to a NAS, the code works as what I want, but I need a Log.txt file for find out what files have been moved. can someone please help me?
$Date = Get-Date -UFormat %d-%m-%Y
$Source = 'C:\Source\'
$Temp = 'C:\Backup-Temp\'
$Nas = 'D:\Destination\'
$Ext = "*.zip","*.rar"
$SetTime = '-5'
New-Item -Path $Temp -Name "Backup-$Date" -ItemType "directory"
Foreach ($Ext in $Ext) {
get-childitem -Path "$Source" -Recurse |
Where-object {$_.LastWriteTime -lt (get-date).AddDays($SetTime) -and $_.name -like "$Ext"} |
Move-item -destination "$Temp\Backup-$Date" |
Compress-Archive -Path "$Temp\Backup-$Date" -DestinationPath "$Nas\Backup-$date.Zip"
}
$Date = Get-Date -UFormat %d-%m-%Y
$Source = 'C:\Source\'
$Temp = 'C:\Backup-Temp\'
$Nas = 'D:\Destination\'
$Ext = "*.zip","*.rar"
$SetTime = '-5'
$LogFileFullName = 'c:\tmp\log.txt'
function Write-Log([string]$msg){
Out-File -FilePath $LogFileFullName -InputObject "$([DateTime]::Now): $msg" -Append
}
New-Item -Path $Temp -Name "Backup-$Date" -ItemType "directory"
Foreach ($Ext in $Ext) {
get-childitem -Path "$Source" -Recurse |
Where-object {$_.LastWriteTime -lt (get-date).AddDays($SetTime) -and $_.name -like "$Ext"} |
ForEach-Object {
Move-item $_.FullName -destination "$Temp\Backup-$Date" |
Compress-Archive -Path "$Temp\Backup-$Date" -DestinationPath "$Nas\Backup-$date.Zip"
Write-Log $_.FullName
}
}
You could just add the following to your chain of piped commands:
Add-Content $logfile "$_.name`n"
where $logfile is set to a static filename prior.
I may be old-fashioned, but having so many commands in one chain is prone to failure. It would be more resilient to break-up the chain so that you can include some error checking along the way.
A better but less desirable option would be to put your chain within a try/catch block.
Best of luck.
Related
I need to make basic / or more advanced backup script that would copy items from folder A to folder B and then log what it did.
This copies the files just fine:
$source = 'path\gamybinis\*'
$dest = 'path\backup'
Get-ChildItem -Path $source -Recurse | Where-Object { $_.LastWriteTime -gt [datetime]::Now.AddMinutes(-5)
}| Copy-Item -Destination $dest -Recurse -Force
Write-Host "Backup started"
Pause
But after this I can't write the log with | Out-File, So I've tried this:
$source = 'path\gamybinis\*'
$dest = 'path\backup'
$logFile = 'path\log.txt'
$items = Get-ChildItem -Path $source -Recurse | Where-Object { $_.LastWriteTime -gt [datetime]::Now.AddMinutes(-5)
}
foreach($item in $items){
Out-File -FilePath $logFile -Append
Copy-Item -Path "$source\$item" -Destination $dest -Recurse -Force
}
Write-Host "Backup started"
Pause
This one does absolutely nothing, what exactly am I doing wrong?
(Advanced script part would be: backing up recently modified files then files should be archived to .rar/.zip, log file have to have structure that is easily readable and log file should have information which user was working on the device during the backup) - For those who are wondering.
If you can't use robocopy, in pure PowerShell code you could do this
$source = 'path\gamybinis' # no need for '\*' because you're specifying -Recurse
$dest = 'path\backup'
$logFile = 'path\log.txt'
# test if the destination path exists. If not, create it first
if (!(Test-Path -Path $dest -PathType Container)) {
$null = New-Item -Path $dest -ItemType Directory
}
Write-Host "Backup started"
Get-ChildItem -Path $source -Recurse |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddMinutes(-5) } |
ForEach-Object {
$_ | Copy-Item -Destination $dest -Recurse -Force
Add-Content -Path $logFile -Value "$((Get-Date).ToString("yyyy-MM-dd HH:mm:ss")) - Copied file '$($_.FullName)'"
}
Write-Host "Backup done"
From your comments, I understand you have problems when using the -Container switch.
Below code does not use that and creates the folder structure of the copied files in the backup folder, strictly using Powershell code:
$source = 'path\gamybinis' # no need for '\*' because you're specifying -Recurse
$dest = 'path\backup'
$logFile = 'path\log.txt'
Write-Host "Backup started"
Get-ChildItem -Path $source -File -Recurse |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddMinutes(-5) } |
ForEach-Object {
$target = Join-Path -Path $dest -ChildPath $_.DirectoryName.Substring($source.Length)
if (!(Test-Path $target -PathType Container)) {
# create the folder if it does not already exist
$null = New-Item -Path $target -ItemType Directory
}
$_ | Copy-Item -Destination $target -Force
Add-Content -Path $logFile -Value "$((Get-Date).ToString("yyyy-MM-dd HH:mm:ss")) - Copied file '$($_.FullName)'"
}
Write-Host "Backup done"
I got a script:
$CopySource = "C:\Source\Qlikview Storage\PrivateData\Gemensamma\Qvd_Raw\Agresso"
$CopyDestination = "C:\Dest\Qlikview Storage\PrivateData\Gemensamma\Qvd_Raw\Agresso"
$files = Get-ChildItem -File "*.qvd" $CopySource -Force
foreach ($file in $files) {
Copy-Item -path $CopySource\$_$file -Destination $CopyDestination -Force
}
$CopySource = "C:\Source\Qlikview Storage\PrivateData\Gemensamma\Qvd_Raw\Agresso"
$CopyDestination = "C:\Dest\Qlikview Storage\PrivateData\Gemensamma\Qvd_Raw\Agresso"
$items = Get-ChildItem -File "*.qvd" $CopyDestination
foreach($I in $Items) {
$newfilename= rename-item -path $I.Name -newname ("Agresso_" + $I.Name)
The problem I have is that I need to copy files from source to destination and once they are over they need to have agresso_ added. Then they day after a batch of files will be copied again and also they need to be renamed to agresso_ and overwrite the old ones, preferably with move-item. I got a problem already, as I am not used with prefixes,
I tried enless of versions with where-object and simular, could not figure out a way to use test-path either.
I did exactly this but with renaming the files, like this for maximo:
$files = Get-ChildItem -File "*.qvd" $CopySource -Force
foreach ($file in $files) {
Copy-Item -path $CopySource\$_$file -Destination $CopyDestination -Force -Verbose 4>&1 |
Out-File -Append $logpath
}
"Klar med Kopiering av .qvd filer $global:currenttime" | Out-File $logpath -Append
"Påbörjar omdöpning av .qvd filer $global:currenttime" | Out-File $logpath -Append
$items = Get-ChildItem -File "*.qvd" $CopyDestination
foreach($I in $Items) {
$newfilename=$I.Name.Replace("QVDLager1","Maximo")
Move-Item -Path $I.FullName -Destination $CopyDestination\$newfilename -Force -Verbose 4>&1 |
Out-File -Append $logpath
If anyone can help me in the right direction it would be highly appriciated.
You can copy (or move) and rename the destination at the same time:
$CopySource = "C:\Source\Qlikview Storage\PrivateData\Gemensamma\Qvd_Raw\Agresso"
$CopyDestination = "C:\Dest\Qlikview Storage\PrivateData\Gemensamma\Qvd_Raw\Agresso"
Get-ChildItem -Path $CopySource -File "*.qvd" -Force | ForEach-Object {
# create the full path for the target file with "Agresso_" prefixed
$target = Join-Path -Path $CopyDestination -ChildPath ('Agresso_{0}' -f $_.Name)
$_ | Copy-Item -Destination $target -WhatIf
}
If satisfied with the results of the code shown in the console, you can remove the -WhatIf switch to really start copying (or moving) the files.
I am fairly new to powershell and have been tasked at cleaning up an archive server. I am trying to create a script to move files into a Year\Month folder structure by looking at it's LastWriteTime in Powershell.
I have the below however I do not know how to get it to look at the month the file was edited?
$Path = "D:\Data"
$NewPath = "D:\ArchiveData"
$Year = (Get-Date).Year
$Month = (Get-Date).Month
New-Item $NewPath\ -name $CurrentYear -ItemType Directory
New-Item $NewPath\$Year -Name $Month -ItemType Directory
Get-ChildItem -path $Path | Where-Object {$_.LastWriteTime -Contains (Get-Date).month} | Move-Item -Destination "$NewPath\$Year\$Month"
Any ideas of how I could do this would be appreciated?
Thanks
-contains is used to see if an array contains an item; it's not suitable here.
-eq is what you need. As per your variable $Month, you will need to get only the part you care about (i.e. the month):
($_.LastWriteTime).Month -eq (Get-Date).month
I think I would approach this from the other end. Directories can be created when needed.
When you are satisfied that the files would be moved correctly, remove the -WhatIf from the Move-Item cmdlet.
$Path = 'C:\src\t'
$NewPath = 'C:\src\tarch'
Get-ChildItem -File -Path $Path |
ForEach-Object {
$Year = $_.LastWriteTime.Year
$Month = $_.LastWriteTime.Month
$ArchDir = "$NewPath\$Year\$Month"
if (-not (Test-Path -Path $ArchDir)) { New-Item -ItemType "directory" -Path $ArchDir | Out-Null }
Move-Item -Path $_.FullName -Destination $ArchDir -WhatIf
}
I am trying to find the path of the object currently being operated on in a for-eachobject loop. Can someone explain how to do this? I am trying to set the path of the source for Copy-Item to whatever path the file is on. This is the first project I have worked with Powershell on. Assume $Src has been properly instantiated.
Get-ChildItem -Path $Src -Recurse -Force | Where-Object {$_.Name -notmatch "Archive" -and ($_.PSIsContainer)}|
ForEach-Object {
$DateStr = $_.BaseName.Substring(0,2)+'/'+$_.BaseName.Substring(3,2)+'/'+$_.BaseName.Substring(6,4)
$FileDate = get-date $DateStr
If ( $FileDate -ge $Date -and !($_.PSIsContainer)) {
$ParentOjbect = $_.Directory
$Parent = $ParentOjbect.Name
Copy-Item -Path (Join-Path -Path $Src -ChildPath '\*.txt' ) #this
#needs to be corrected to only point to the current file
-Dest (Join-Path $Dst ("$($_.Directory.Name) $($_.Name)")) -WhatIf
}
}
Copy-Item -Path (Join-Path -Path $_.FullName -ChildPath '\*.txt' )
I suggest you also use -WhatIf on that also to check it does what you expect first.
$_, or $PSItem (PowerShell 3.0+), accesses the current object in the pipeline. From here, you can access its members.
I have the following powershell code in which,
backup of (original) files in folder1 is taken in folder2 and the files in folder1 are updated with folder3 files.
The concept of hotfix !!
cls
[xml] $XML = Get-content -Path <path of xml>
$main = $XML.File[0].Path.key
$hotfix = $XML.File[1].Path.key
$backup = $XML.File[2].Path.key
Get-ChildItem -Path $main | Where-Object {
Test-Path (Join-Path $hotfix $_.Name)
} | ForEach-Object {
Copy-Item $_.FullName -Destination $backup -Recurse -Container
}
write-host "`nBack up done !"
Get-ChildItem -Path $hotfix | ForEach-Object {Copy-Item $_.FullName -Destination $main -force}
write-host "`nFiles replaced !"
Now, as the backup of files is taken in folder2, I need to create a log file which contains - name of the file whose backup is taken, date and time, location where the backup is taken
Can anyone please help me with this?
I did the following code, but its of no use, as I cannot sync the both.
cls
$path = "C:\Log\Nlog.log"
$numberLines = 25
For ($i=0;$i -le $numberLines;$i++)
{
$SampleString = "Added sample {0} at {1}" -f $i,(Get-Date).ToString("h:m:s")
add-content -Path $path -Value $SampleString -Force
}
Any help or a different approach is appreciated !!
You can use the -PassThru switch parameter to have Copy-Item return the new items it just copied - then do the logging immediately after that, inside the ForEach-Object scriptblock:
| ForEach-Object {
$BackupFiles = Copy-Item $_.FullName -Destination $backup -Recurse -Container -PassThru
$BackupFiles |ForEach-Object {
$LogMessage = "[{0:dd-MM-yyyy hh:mm:ss.fff}]File copied: {1}" -f $(Get-Date),$_.FullName
$LogMessage | Out-File ".\backups.log" -Append
}
}