I'm actually doing a script to replace every "o" into my folder/files names into "0"
Here is my simple script :
Get-ChildItem -recurse |`
Where-Object { $_.name -match 'o' } |`
Rename-Item -NewName { $_name -replace 'o', '0' }
It is working but now I want to log into a file every files/folder that have changed.
So basicly I want to add a function to write the name of my file before and after being renamed.
For example, for the "BEFORE name", I tried to add this command after the Where-Object pipe :
Add-content $MylogFile
It succed to log every files having a 'o' inside but WITHOUT their path. And having a log of 1000+ files without their path is useless...
DO you have any idea to simply log the before/after name of each file that have been renamed by the script WITH their path ?
Thanks in advance !
Regards,
You just need to store the original search into a variable then iterate over it. The following should do what you want:
If you want to rename only files:
$files = Get-ChildItem -recurse | Where-Object { $_.PSIscontainer -eq $false -and $_.name -match 'o' }
$files | % {
$newname = $_.name -replace 'o', '0'
write-host "Before: $($_.fullname)"
write-host "After: $newname"
$_ | Rename-Item -NewName $newname
}
To rename files AND folders:
$files = Get-ChildItem -recurse | Where-Object { $_.PSIscontainer -eq $false -and $_.name -match 'o' }
$files | % {
$newname = $_.name -replace 'o', '0'
write-host "Before: $($_.fullname)"
write-host "After: $newname"
$_ | Rename-Item -NewName $newname
}
$dirs = Get-ChildItem -recurse | Where-Object { $_.PSIscontainer -eq $true -and $_.name -match 'o' }
$dirs | % {
$newname = $_.name -replace 'o', '0'
write-host "Dir Before: $($_.fullname)"
write-host "Dir After: $newname"
$_ | Rename-Item -NewName $newname
}
Related
Windows 10 64 BIT
Scenario: copy files in a directory and subdirectory to the destination directory.
File Type: Only pdf
Issue: When the file name has special characters not able to copy
Tried below code not working
#Get all files and not the directories
$files = Get-ChildItem -Path "c:/source" -Recurse -filter "*.pdf" | Where {$_.PSIsContainer -eq $false}
#Copy items from sources to new destination
foreach ($file in $files)
{
if ($file.Name -match '[^a-zA-Z0-9]')
{
$file.FullName
*$file.FullName | Rename-Item -NewName {$_ -replace '_*(\[.*?\]|\(.*?\))_*' -replace '_+', ' '} $NewName
*Rename-Item -NewName {$_ -replace '_*(\[.*?\]|\(.*?\))_*' -replace '_+', ' '}
*$NewName = rename-item $file.FullName.Replace('_*(\[*?\]|\(*?\))_*', '')
Rename-Item -Path $file.fullName -NewName {$_ -replace '_*(\[.*?\]|\(.*?\))_*' -replace '_+', ' '}
}
Copy-Item -Path $file.FullName -Destination "c:/desination\"
}
I have created a script that will rename pst files to acl owner. It works. The only problem i have is when there are two pst files in the same folder.It gives them the same name. How can i add an increment in my script. It ried it with Si = 1 and Si++ but with no results.
Here is my script:
Get-ChildItem C:\Users\tester\* -Filter *.pst -recurse |
ForEach-Object{
$owner = ( $_ | Get-Acl ).Owner.Split("\")[1]
$newname = "$owner.pst"
$_ | Rename-Item -NewName $newname -Verbose -WhatIf
}
This is a quick and fast work around by adding names already used to an array and checking each time you loop.
$increment = 1
$alreadyProcessed = #()
Get-ChildItem C:\Users\tester\* -Filter *.pst -recurse |
ForEach-Object{
$owner = ( $_ | Get-Acl ).Owner.Split("\")[1]
$newname = "$owner.pst"
if($alreadyProcessed.Contains($newName))
{
$newName = "$owner`$increment.pst"
$increment++
}
$alreadyProcessed += $newname
$_ | Rename-Item -NewName $newname -Verbose -WhatIf
}
This will ensure a unique name each time.
If you plan to run your script multiple times in the same place then you should check to see what names are available otherwise your counter will reset to 1 but those files would already exist.
function Get-NextName ($file) {
$existing = (Get-Item "$file.*").Name
$i = 1
while ($existing -contains "$file.$i") {
$i++
}
"$file.$i"
}
And then adjust your function:
Get-ChildItem C:\Users\tester\* -Filter *.pst -recurse |
ForEach-Object{
$owner = ( $_ | Get-Acl ).Owner.Split("\")[1]
$newname = Get-NextName "$owner.pst"
$_ | Rename-Item -NewName $newname -Verbose -WhatIf
}
I'm trying to log data surrounding the renaming of files using the following script. The only problem is that the log file contains files that were not renamed due to 'access denied' errors when attempting to rename. I need to figure out how to only create log entries for files that were SUCCESSFULLY renamed or pipe the failed renames to a different log file. I'd also like the total number of files renamed listed at the top of the log file if at all possible(ie 'xxx files were renamed') I appreciate any suggestions for getting this to work using powershell v2.
$drivesArray = Get-PSDrive -PSProvider 'FileSystem' | select -Expand Root
foreach ($drive in $drivesArray) {
Get-ChildItem $drive | Where-Object {
$_.FullName -notlike "${Env:WinDir}*" -and
$_.FullName -notlike "${Env:ProgramFiles}*"
} | ForEach-Object {
Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue
} | Where-Object {
-not $_.PSIsContainer -and
$_.Extension -notmatch '^\.(xxx|exe|html)$'
} | ForEach-Object {
$newName = $_.FullName + '.xxx';
Rename-Item -Path $_.FullName -NewName ($_.FullName + '.xxx') -ErrorAction SilentlyContinue
Add-Content c:\temp\renameLog.txt -Value $('{0} {1} {2} {3}' -f $(Get-Date),$_.fullname,$_.name,$newName )
}
}
Here is an example, untested of course.
$success = 0
$failed = 0
$drivesArray = Get-PSDrive -PSProvider 'FileSystem' | select -Expand Root
foreach ($drive in $drivesArray) {
Get-ChildItem $drive | Where-Object {
$_.FullName -notlike "${Env:WinDir}*" -and
$_.FullName -notlike "${Env:ProgramFiles}*"
} | ForEach-Object {
Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue
} | Where-Object {
-not $_.PSIsContainer -and $_.Extension -notmatch '^\.(xxx|exe|html)$' -and $_.Name -notmatch '^renameLog.txt|^renameLog_failed.txt'
} | ForEach-Object {
try {
$newName = $_.FullName + '.xxx';
Rename-Item -Path $_.FullName -NewName ($_.FullName + '.xxx') -ErrorAction Stop
Add-Content c:\temp\renameLog.txt -Value $('{0} {1} {2} {3}' -f $(Get-Date),$_.fullname,$_.name,$newName )
$success ++
} catch [exception] {
Add-Content c:\temp\renameLog_failed.txt -Value $('{0} {1} {2} {3}' -f $(Get-Date),$_.fullname,$_.name,$newName )
$failed ++
$error.Clear()
}
}
}
Add-Content "c:\temp\renameLog.txt" -Value $("Total: " + $success)
Add-Content "c:\temp\renameLog_failed.txt" -Value $("Total: " + $failed)
My Current Code Is
Param(
[string]$filePath = "C:\",
[string]$logFileFind = "error.log",
[string]$logFileReplace ="ThisHasBeenReplaced.log"
)
($configFile = Get-ChildItem -Recurse -Force $filePath -ErrorAction SilentlyContinue | Where-Object { ($_.PSIsContainer -eq $false) -and ( $_.Name -like "*.config") }
It Works fine and gives me list of files i was wondering how i could go through these files and find and replace certain words for when I'm moving though environments and the path wont be the same. I'm very limited in my powershell knowledge and i tried adding this to the end of the script.
ForEach-Object{(Get-Content $configFile) -replace $logFileFind , $logFileReplace | Set-Content $configFile})
This didn't work and i was wondering if there was anyone out there who knew what i could do to make it work.
Thanks in Advance!
You always access $configFile in your foreach loop (which is probably an System.Array), not the actual element. Try this:
$configFile | foreach { (get-content $_.FullName -Raw) -replace $logFileFind , $logFileReplace | Set-Content $_.FullName }
Here is a full example:
Get-ChildItem -Recurse -force $filePath -ea 0 |
where { ($_.PSIsContainer -eq $false) -and ( $_.Name -like "*.config") } |
foreach {
(gc $_.FullName -raw) -replace $logFileFind , $logFileReplace | sc $_.FullName
}
I am using following coe to replace the string
$folders=Get-ChildItem -Path "C:\temp\Database Scripts"
foreach($folder in $folders)
{
Write-Host $folder
$spath=[string]::Concat("C:\temp\Database Scripts\", $folder)
$subfolders=Get-ChildItem $spath
foreach($subfolder in $subfolders )
{
if($subfolder -match "Running Scripts")
{
$subfolerpath=[string]::Concat($spath,"\",$subfolder,"\*")
$files =get-childitem -Path $subfolerpath -include "AVEVAScripts*"
if($files -ne $null)
{
foreach( $file in $files)
{
Write-Host $file;
(Get-Content $file) | ForEach-Object {$_ -replace "DATABASE_USER","fhghjgj" `
-replace "DATABASE_PASSWORD", "DFGHFHJGJH" } |Set-Content $file
}
}
}
}
}
But ending up with following error.
Set-Content : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
Please help :)
Remove the $x in the end of Set-Content. $x is never declared.
Also, you could simplify it a lot. Ex:
Get-ChildItem -Filter "Running Scripts" -Path "C:\temp\Database Scripts" -Recurse | ForEach-Object {
Get-ChildItem -Path $_.FullName -Filter "AVEVAScripts*" -Recurse | ForEach-Object {
(Get-Content $_.FullName) | ForEach-Object {
$_ -replace "DATABASE_USER","fhghjgj" -replace "DATABASE_PASSWORD", "DFGHFHJGJH"
} | Set-Content $_.FullName
}
}
Or find all files that includes "AVEVAScripts" in it's name, then check if their full path includes "Running Scripts"
Get-ChildItem -Filter "AVEVAScripts*" -Path "C:\temp\Database Scripts" -Recurse |
Where-Object { $_.FullName -like "*Running Scripts*" } |
ForEach-Object {
(Get-Content $_.FullName) | ForEach-Object {
$_ -replace "DATABASE_USER","fhghjgj" -replace "DATABASE_PASSWORD", "DFGHFHJGJH"
} | Set-Content $_.FullName
}