Array output to multiple lines - powershell

Get-ChildItem "$Folder" *.xlsx -Recurse | ?{-not ($_.PSIsContainer -or (Test-Path "I:\TEMP_Dir_SSN\$_"))} | copy-Item -Destination "I:TEMP_Dir_SSN" | out-null
Get-ChildItem "$Folder" *.xlsx -Recurse | %{
$test = Resolve-Path $_.FullName
$holdArray += $test.path
}
$holdArray | out-file "I:\TEMP_Dir_SSN\fullPath.txt" -append
The output:
I:\1992.xlsxI:\projects\confluence\projects\documents\XXXX_ComplianceRegulations.xlsxI:\projects\confluence\projects\documents\XXXX_vendorCloudStandardsPoliciesRegs.xlsx
I want it:
I:\1992.xlsx
I:\projects\confluence\projects\documents\XXXX_ComplianceRegulations.xlsx
I:\projects\confluence\projects\documents\XXXX_vendorCloudStandardsPoliciesRegs.xlsx
I'm not sure what is going wrong here. It should be adding it to the next line down, not appending it to the end of the string.

Change $holdArray += $test.path to [array]$holdArray += $test.path
You have not told PowerShell this is an array so it is treating it as a string.

You are flattening the "array" to a space delimited string since you have not declared $holdArray initially. Skip the array "build" logic and use the pipeline to get the results you want.
Get-ChildItem $Folder *.xlsx -Recurse |
Resolve-Path | Convert-Path |
Add-Content "I:\TEMP_Dir_SSN\fullPath.txt"
Add-Content appends by default.

Related

powershell script not interpreting file path correctly

I have an issue where a path to a file is generated by an application. So the path looks like this….
Unfortunately, this output is generated from an application…so I cannot manipulate the output.
Now…when I run my powershell script to copy the file …I get the following errors
It seems that the problem is that my powershell script is not getting the path correctly….
$folders = Get-Content -Path '\\TFA-APP-01\CUI\WS\FOUNDFILES\results.txt'
$dest = '\\TFA-APP-01\CUI\WS\FOUNDFILES\found\'
$excludes = "WS","FOUNDFILES"
foreach ($folder in $folders) {
# Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Desktop'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Documents'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Downloads'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Outlook'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'INetCache'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Attachments'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
}
How can I either parse the results.txt file and extract just the file paths to another text file?
Or how can I modify my CopyResults.ps1 script to interpret the file path correctly?
Your issue is that Get-Content converts every line of a file into an element of an array, and you don't want to look at every line. You want to look at a specific part of a specific line that repeats in a specific pattern.
Because of all of these constants, we can make a pretty simple script to get the information you want.
$paths = Get-Content C:\temp\paths.txt
for ($i = 1; $i -lt $paths.Length; $i += 3) {
$path = "$($paths[$i].Split('.txt')[0]).txt"
$path # \\SERVER\PATH\FILE.TXT
}
Your file has a pattern of [empty line, path line, company line]. If we think about the .txt file as an array with many subarrays of that pattern, we can see that we want to get the 1st index ($i = 1) for every set of 3 ($i += 3) in the file.
Since I split by .txt, I have to string interpolate the .txt extension back on.
Edit:
Here's the script modified for your issues
$paths = Get-Content C:\temp\paths.txt
for ($i = 1; $i -lt $paths.Length; $i += 3) {
$pathSplit = $paths[$i].Split('.')
$extension = $pathSplit[1].split(' ')[0]
$path = "${$pathSplit[0]).$extension"
$path # \\SERVER\PATH\FILE.TXT
}
$pathSplit is split at the extension into 2 parts. One is the majority of the path and the other is the rest of the line.
$extension looks at the 1st index and splits by the space in order to isolate the file extension.
Finally, $path combines $pathSplit[0] and $extension to give you the full file path.

recursively count files in folder and output to file

I want to count files for every folder on an E-drive, and output the folder path and file count to a text file using PowerShell (version 2).
I have found this script, but it outputs to console. How do I change it to output to a text file?
Set-Location -Path E:\
Get-ChildItem -recurse | Where-Object{ $_.PSIsContainer } | ForEach-Object{ Write-Host $_.FullName (Get-ChildItem $_.FullName | Measure-Object).Count }
I think it would be best to get an array of resulting objects where you can store both the directory path and the number of files it contains. That way, you can afterwards show it in the console and also save it to a structured CSV file you can open in Excel.
This is for PowerShell 2:
# to keep the property order in PS version < 3.0, create an
# Ordered Dictionary to store the properties first
$dict = New-Object System.Collections.Specialized.OrderedDictionary
# now loop over the folders
$result = Get-ChildItem -Path 'E:\' -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.PSIsContainer } |
ForEach-Object {
# add the results in the temporary ordered dictionary
$dict.Add('Directory', $_.FullName)
$dict.Add('Files', #(Get-ChildItem -Path $_.FullName -Force -ErrorAction SilentlyContinue |
Where-Object { !$_.PSIsContainer }).Count)
# and output a PSObject to be collected in array '$result'
New-Object PSObject -Property $dict
$dict.Clear()
}
# output on screen
$result | Format-Table -AutoSize
#output to CSV file
$result | Export-Csv -Path 'D:\Test\FileCount.csv' -NoTypeInformation
The -Force switch makes sure you also count items that otherwise can't be accessed by the user, such as hidden or system files.
Get-ChildItem c:\tmp -recurse |
Where-Object{ $_.PSIsContainer } |
ForEach-Object {
"$($_.Fullname) $((Get-ChildItem $_.FullName | Where-Object{!$_.PSIsContainer}).count)"
} |
Out-File c:\tmp\out.txt
You can use the > operator for this:
Set-Location -Path E:\
(Get-ChildItem -recurse | Where-Object{ $_.PSIsContainer } | ForEach-Object{ Write-Host $_.FullName (Get-ChildItem $_.FullName | Measure-Object).Count }) >"OUTPUTFILEPATH.txt"

Could not redirect the file names that are being deleted to an output csv file using Powershell

Am trying to delete files older than x days and would like to know which file is being deleted.
Am using below powershell script, it doesnt work
$limit = (Get-Date).AddDays(-365)
$path = $args[0]
# Delete files older than the $limit.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force | select Name,LastWriteTime | Export-CSV -NoTypeInformation -Path $args[1]
Am passing first argument as path where files are there.
Second argument is the output file which should contain the file and date modified values of those which gets deleted.
The above code works fine for deletion, but doesnt redirects the file names and the last modified values which got deleted.
If I use below code, it only redirects the file names and last modified values but files doesnt get deleted.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | select Name,LastWriteTime | Export-CSV -NoTypeInformation -Path $args[1] | Remove-Item -Force
Using below command to run it -
./OlderFiles_Cleansing.ps1 'C:\Dev\PS' 'C:\dev\CleanedFiles_01062016.csv'
What am I missing?
Neither the Export-Csv nor the Remove-Item Cmdlet return the collection you pipe in and so make it impossible to work with the items further in the pipeline.
You can do following though - split the command:
$filesToDelete = Get-ChildItem -Path $path -Recurse -Force -Attributes !Directory | Where-Object CreationTime -lt $limit
$filesToDelete | select Name,LastWriteTime | Export-CSV -NoTypeInformation -Path $args[1]
$filesToDelete | Remove-Item -Force
Note I have improved the way of detecting that an item is a file using the
Attributes param and so could simplify the Where pipe part

Doing a variable substitution and saving the files

I want it to go though some folders recursivly, find all files with certain endings, and then go through found files to do the subsitute and then save. I can make it work when I have a given filename, but I seem to be haveing some trouble when it comes to the unknown.
The thought is to read the variables for a given environment from a file and save it into PowerShell as variables (this part seems to work, so I've not mentioned it again), then simply substitute the mentioned variables in a set of unknown files.
I've been looking at this question, which seemed to have something of a similar problem, except that I'm trying to use a variable substitusion. Also looked at some previous answer for replace, but again, this is not replace, but variable substitution, so it seems to work a bit differently. So with that in mind, this is what I got so far:
After looking at the examples in the first link:
Get-ChildItem -Path .\ -Include *.ini,*.exe.config -Recurse | %{ gc $_ } | %{
$ExecutionContext.InvokeCommand.ExpandString($_) +
(Get-Content $_.FullName | Out-String ) | Set-Content -Path $_.FullName
}
After trying to do something with the second link:
$places = 'C:\Users\Roger\Documents\test\Program Files (x86)'
$places |
Get-ChildItem -Recurse -Include *.ini,*.config |
ForEach-Object {
(Get-Content $_) | % {
$ExecutionContext.InvokeCommand.ExpandString($_) |
Set-Content $_
'Processed: {0}' -f $_.FullName
}
}
And of course my own feeble attempts:
Get-ChildItem .\ -Include *.ini,*.exe.config -Recurse | %{ gc $_ } | %{
$ExecutionContext.InvokeCommand.ExpandString($_)
} | Set-Content $_.FullName
$places = 'C:\temp'
$places |
Get-ChildItem -Recurse -Include *.ini,*.config | ForEach-Object {
(Get-Content $_) | ForEach-Object {
$ExecutionContext.InvokeCommand.ExpandString($_)
} | Set-Content $_
'Processed: {0}' -f $_.FullName
}
Move the Set-Content out of the inside ForEach-Object. Set-Content would have been trying to fire for each line using the current line as its name as you have seen. Also, for yours and others sanity, you should try and be consistent with using aliases or not. I see both ForEach-Object and % which could be confusing to new users.

Count deleted empty folders

I have a script right now that looks for all files certain day old and certain file extension and it deletes all of the files. This works fine and it counts fine
Then I have to delete all folders that correspond to being empty and that includes all sub folders too.
I also have to output this into a file and display each file deleted. The output would show 30 folders deleted but actually 48 were really deleted.
Now my question is i am trying to do a count of all the folders deleted. I have this script but it just counts the deepest folders not all the ones deleted.
Here is the part of the script i can not get to count
$TargetFolder = "C:\Users\user\Desktop\temp"
$LogFile = "C:\Summary.txt"
$Count = 0
Date | Out-File -filepath $LogFile
get-childitem $TargetFolder -recurse -force | Where-Object {$_.psIsContainer}| sort fullName -des |
Where-Object {!(get-childitem $_.fullName -force)} | ForEach-Object{$Count++; $_.fullName} | remove-item -whatif | Out-File -filepath $LogFile -append
$Count = "Total Folders = " + $Count
$Count | Out-File -filepath $LogFile -append
Although the sort call will correctly send each directory through the pipeline in nesting order, since they are not really being removed (remove-item -whatif), the parents will still contain their empty child directories and so will not pass the second condition (!(get-childitem $_.fullName -force)). Also note that Remove-Item does not produce any output, so the deleted directories will not appear in the log.
Adapting Keith Hill's answer to a similar question, here is a modified version of the original script that uses a filter to retrieve all empty directories first, then removes and logs each one:
filter Where-Empty {
$children = #($_ |
Get-ChildItem -Recurse -Force |
Where-Object { -not $_.PSIsContainer })
if( $_.PSIsContainer -and $children.Length -eq 0 ) {
$_
}
}
$emptyDirectories = #(
Get-ChildItem $TargetFolder -Recurse -Force |
Where-Empty |
Sort-Object -Property FullName -Descending)
$emptyDirectories | ForEach-Object {
$_ | Remove-Item -WhatIf -Recurse
$_.FullName | Out-File -FilePath $LogFile -Append
}
$Count = $emptyDirectories.Count
"Total Folders = $Count" | Out-File -FilePath $LogFile -Append
Note that -Recurse was added to the call to Remove-Item, as empty child directories will remain when using -WhatIf. Neither flag should be needed when performing an actual remove on an empty directory.
Not tested:
get-childitem $TargetFolder -recurse -force |
where-object{$_.psiscontainer -and -not (get-childitem $_.fullname -recurse -force | where-object {!($_.psiscontainer)}}|
sort fullName -des |
Where-Object {!(get-childitem $.fullName -force)} |
ForEach-Object{$Count++; $_.fullName} |
remove-item -whatif |
Out-File -filepath $LogFile -append