I have been trying to run this script that captures all the files / folders within a share directory and passes it back to splunk. However the script is giving PathTooLongException 's even though the longest path i can find comes in at 197 characters.
I have tried mapping a share as a folder called z on the root of the C drive which doesnt help at all. Can someone shed some light on how to get around this or what is causing the errors?
param (
[string]$directory = "C:\Windows\Logs"
)
$errorCount = 0
$OutputList = #()
$directoryLink = 'c:\z'
#set up symbolic link
cmd /c mklink /d $directoryLink $directory
try
{
$colItems = (Get-ChildItem -Path $directoryLink -Recurse | Sort-Object)
}
catch
{
$errorCount += 1
}
foreach ($i in $colItems)
{
try
{
$subFolderItems = (Get-Item $i.FullName | Measure-Object -property
length -sum -ErrorAction SilentlyContinue)
$acl=$i.GetAccessControl()
$SizeValue= [Math]::Round(($subFolderItems.sum / 1MB),3)
$SplunkFileList = New-Object PSObject
$SplunkFileList | Add-Member -type NoteProperty -name Filename -Value $i.FullName
$SplunkFileList | Add-Member -type NoteProperty -name SizeMb -Value $SizeValue
$SplunkFileList | Add-Member -type NoteProperty -name LastAccess -Value $i.LastAccessTime
$SplunkFileList | Add-Member -type NoteProperty -name Owner -Value $acl.Owner
if ($i.PSIsContainer)
{
$SplunkFileList | Add-Member -type NoteProperty -name Type -Value "D"
}
else
{
$SplunkFileList | Add-Member -type NoteProperty -name Type -Value "F"
}
$OutputList += $SplunkFileList
}
catch [System.IO.IOExeception]
{
Write-Host 'An Exception was caught.'
Write-Host "Exception : $($_.Exception.GetType().FullName)"
$errorCount += 1
}
}
$OutputList | Select-Object Filename,SizeMb,LastAccess,Owner,Type | Format-
List
If you're using a modern version of Powershell (v5.1+ I think) you can get to the paths longer than 260 characters using the unicode version of Windows API.
To do this you prefix the path with \\?\ eg:
Get-ChildItem -LiteralPath '\\?\C:\Windows\Logs' -Recurse
Note: LiteralPath instead of Path
If you want to use a UNC path (\\server\C$\folder) the syntax is slightly different:
Get-ChildItem -LiteralPath '\\?\UNC\server\C$\folder' -Recurse
Related
I have a collection looping through a foreach statement, creating a table with the information gathered from the childitems, mapped to a table array to begin inserting data into an empty array.
when the file is moved from the source dir to the dest dir. I want to record the move and have it populate the result to the "File Status" col. The code executes but always skips the first row and leaves the "File Status" col empty for the first item.
What would be a more efficient approach to have it not skip the first item?
$childitems = Get-ChildItem "C:\folder1\" -Filter *.csv
$destpath = "C:\folder2\"
$emptytable = #()
$table1 = #(
[PSCustomObject]#{
Property = 'Location';Name = 'Store';ID = '1111'}
)
foreach ($childitem in $childitems) {
$file = $childitem | get-content
$fileid = $childitem.PSPath.Split("_")[4]
$PropertyName = $table1 | Where-Object {$_.id -eq $fileid}
$ImportDate = $childitem.BaseName.Split("_")[5]
foreach ($id in $fileid) {
$idobj = New-Object PSObject
$idobj | Add-Member -type NoteProperty -Name "Col1" -Value $PropertyName.Property
$idobj | Add-Member -type NoteProperty -Name "col2" -Value $PropertyName.Name
$idobj | Add-Member -type NoteProperty -Name "Col3" -Value $fileid
$idobj | Add-Member -type NoteProperty -Name "col4" -Value $file.Count
$idobj | Add-Member -type NoteProperty -Name "File Status" -Value $Movestatus
$idobj | Add-Member -type NoteProperty -Name "col5" -Value $ImportDate
foreach ($item in $childitem) { $Movestatus = ''
Try
{
Move-Item -Path $item.FullName -Destination $destpath -Force -ErrorAction SilentlyContinue
$Movestatus += 'Moved To Punches';
}
Catch
{
$Movestatus += 'Error Unable to Moved File';
}
Start-Sleep -Seconds 30
$emptytable += $idobj
}
}
}
$emptytabler code here
I am trying to print the path of a file if string is found. Problem is if 1 file does not contain the string in a folder then I do not get any output. Basically I am looking to see if a certificate epoch-time is within 30 days of expiration. Below is my code:
$c = Get-Date (Get-Date).ToUniversalTime() -UFormat %s
$epochtimes=[math]::Round($c)
$d = get-childitem C:\scripts\PALO\* -recurse | Select-String -pattern
"expiry-epoch"
$e=$d -split "epoch"
$certtime=[double] $e[1]
$certexp = $certtime - 2592000
ForEach ($i in $certexp){
If ($certexp -le $epochtime) {
Write-Host $i
}
}
I've made a couple of assumptions since it isn't totally clear from your question what is going on. Importantly, I've assumed you have a directory tree containing some text files each with a line in it like this:
expiry-epoch 1526854766.33933
If this is the case, then the following should display some useful information about the files:
Get-ChildItem -Path "C:\test" -File -Recurse |
ForEach-Object {$threshold = [Math]::Round((Get-Date (Get-Date).ToUniversalTime() -UFormat %s)) + 2592000} {
$certEpochTime = ([double]($_ | Select-String -Pattern "^expiry-epoch (\d+\.\d+)$").Matches.Groups[1].Value)
$certExpiryTime = (Get-Date "1/1/1970").AddSeconds($certEpochTime)
New-Object -TypeName PsCustomObject|
Add-Member -MemberType NoteProperty -Name ExpiresSoon -Value ($certEpochTime -le $threshold) -PassThru |
Add-Member -MemberType NoteProperty -Name DaysUntilExpiry -Value ([Math]::Round(($certExpiryTime - (Get-Date)).TotalDays)) -PassThru |
Add-Member -MemberType NoteProperty -Name CertExpiryTime -Value $certExpiryTime -PassThru |
Add-Member -MemberType NoteProperty -Name CertEpochTime -Value $certEpochTime -PassThru |
Add-Member -MemberType NoteProperty -Name FilePath -Value $_.FullName -PassThru
} | Format-Table -AutoSize
EDIT:
If all you need is the filename of any files with an expiry-epoch within 30 days, then this simplified version will do that:
Get-ChildItem -Path "C:\test" -File -Recurse |
ForEach-Object {$threshold = [Math]::Round((Get-Date (Get-Date).ToUniversalTime() -UFormat %s)) + 2592000} {
$certEpochTime = ([double]($_ | Select-String -Pattern "^expiry-epoch (\d+\.\d+)$").Matches.Groups[1].Value)
if($certEpochTime -le $threshold)
{
$_.FullName
}
}
I am writing a script that will iterate through folders, grabbing substrings of the folder names as variable values, and then iterate through the log files in each of the folders and get some data out of the log files for output to a .csv file. Where I am running into an issue is with the use of Get-ChildItem with variables I have already set. When I run this line by itself, it does not provide any value:
#running this to see the value of $files
$files = Get-ChildItem $_.FullName $folder
$files does not then contain any value.
Here is the entire portion of the script, for reference and context:
#get all folders from the Logs directory
$folders = Get-ChildItem "C:\Temp\MPOS\Logs"
#iterate through each folder
foreach ($folder in $folders) {
#set substrings of the folder name to variables
$storeNumber = $folder.Name.Substring(2,3)
$date = $folder.Name.Substring(9,7)
#get all files from the current folder being evaluated
$files = Get-ChildItem $_.FullName $folder
#iterate through each file in the current folder
foreach ($file in $files) {
#set substring of the file name to a variable
$registerNumber = $file.Name.Substring(12,4)
#get content of the file
$logfileContent = Get-Content $file
#look for all matches of the string "TransactionNumber"
$transactions = Select-String -InputObject $logfileContent -Pattern "TransactionNumber" -AllMatches
#count number of matches from above
$transactionCount = $transactions.Matches.Count
#below info is creating the object for the .csv
$transObject = New-Object PSObject
$transObject | Add-Member -MemberType NoteProperty -Name "StoreNumber" -Value $storeNumber
$transObject | Add-Member -MemberType NoteProperty -Name "Sales Date" -Value $date
$transObject | Add-Member -MemberType NoteProperty -Name "RegisterNumber" -Value $registerNumber
$transObject | Add-Member -MemberType NoteProperty -Name "Transactions" -Value $transactionCount
$resultsArray += $transObject
}
}
$resultsArray | Export-Csv C:\Temp\MPOS\MPOSTransactions.csv -NoTypeInformation
Edited code below - changed to read $folder.FullName - working now!
$resultsArray = #()
$folders = Get-ChildItem "C:\Temp\MPOS\Logs"
foreach ($folder in $folders) {
$storeNumber = $folder.Name.Substring(2,3)
$date = $folder.Name.Substring(9,7)
$files = Get-ChildItem $folder.FullName
foreach ($file in $files) {
$registerNumber = $file.Name.Substring(12,4)
$logfileContent = Get-Content $file.FullName
$transactions = Select-String -InputObject $logfileContent -Pattern "TransactionNumber" -AllMatches
$transactionCount = $transactions.Matches.Count
$transObject = New-Object PSObject
$transObject | Add-Member -MemberType NoteProperty -Name "StoreNumber" -Value $storeNumber
$transObject | Add-Member -MemberType NoteProperty -Name "Sales Date" -Value $date
$transObject | Add-Member -MemberType NoteProperty -Name "RegisterNumber" -Value $registerNumber
$transObject | Add-Member -MemberType NoteProperty -Name "Transactions" -Value $transactionCount
$resultsArray += $transObject
}
}
$resultsArray | Export-Csv C:\Temp\MPOS\MPOSTransactions.csv -NoTypeInformation
I had this exact issue, but I found out in my case I was trying to load a variable by piping in a value that also was using Format-Table command.
Example: (this worked)
$GetMostRecentFile = $GetLatestFile = Get-ChildItem -Force -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $.LastWriteTime.Date -lt (Get-Date).Date -and $.Name -ne 'Thumbs.db' -and $_.Name -ne '.DS_Store'} | Sort LastWriteTime -Descending | Select-Object -First 1 LastWriteTime,FullName,Length
(this didn't work)
$GetLatestFile = Get-ChildItem -Force -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $.LastWriteTime.Date -lt (Get-Date).Date -and $.Name -ne 'Thumbs.db' -and $_.Name -ne '.DS_Store'} | Sort LastWriteTime -Descending | Select-Object -First 1 LastWriteTime,FullName,Length | Format-Table -Wrap
Because I'd been using Format-Table as part of my commands to explore this data and build my queries, I forgot that if you pipe this (with FT) to a variable, the variable won't have the details.
In my case above, I needed to pull $GetMostRecentFile.FullName and $GetMostRecentFile.LastWriteTime pulled into another array. But when I was piping with FT, there was not $GetMostRecentFile.FullName. When I remove
I created the following code, but it is not actually reading any of the .zip or .prd files as expected, but the other parts are working. Might you help me figure out why it is not actually reading the zip files in the ForEach loop?
#Set variables for subversion paths
$ScriptPath = (Split-Path $myinvocation.MyCommand.path -Parent)
#$Package = $ScriptPath
#Create folder for temporary copy of SVN directory
New-Item C:\MyTemp-type directory -ErrorAction SilentlyContinue -Force
New-Item C:\Results -type directory -ErrorAction SilentlyContinue -Force
Test-Path $profile
New-item –type file –force $profile
#Set variables for subversion paths
$CurrentSVNPath = "http://MySVNPath"
$TempSVNPath = "C:\MyTemp"
$ResultsFilePath = "C:\Results"
#Download a local copy of the SVN Repository
# Wait for command to finish before moving forward
#$SVNDownloadJob = Start-Job {SVN Checkout $CurrentSVNPath $TempSVNPath}
$SVNDownloadJob = Start-Job {TortoiseProc.exe /command:update /path:"C:\SVN_Repo" /closeonend:1 | Out-Null}
Wait-Job $SVNDownloadJob
Receive-Job $SVNDownloadJob
#Find pattern to search for within all files from where this script is run
#If you do not want to look for the standard pattern uncomment/comment the $Pattern variables
#$Pattern = Read-Host 'What pattern are you looing for?'
$Pattern = "Simulate=`"true`""
$SearchPattern = “Simulate=`”true`””
$PackageList = Get-ChildItem –Path $ScriptPath –Recurse –filter “*.zip, *.prd”
#Start searching all folders where this script exists for 'Simulate=true'
$k =foreach ($file in Get-ChildItem -Path $ScriptPath -Recurse | Select-String -pattern $Pattern | Select-Object -Unique path) {$file.path}
$k > "$($ResultsFilePath)\SimulateEqualsTrueZipFiles.txt"
Foreach ( $Package in $PackageList) {
Read-Archive -$_.Path -Format Zip | `
Where-Object { $_.Name -like "*.zip" } | `
Expand-Archive -PassThru | select-string $SearchPattern | Select-Object -Unique path {$file.path}
$k > "$($ResultsFilePath)\SimulateEqualsTrueZipFiles.txt"
}
You can get the contents of Zip Folder by using below cmdlets
$ZipFile="Path"
$AllFile=Get-ChildItem $ZipFile -Recurse -Filter '*.zip'
$ObjArray = #()
foreach ($item in $AllFile){
$FullName=$item.FullName
$RawFiles = [IO.Compression.ZipFile]::OpenRead($FullName).Entries
$FullPathName=$FullName+"\"+"$RawFile"
foreach($RawFile in $RawFiles) {
$object = New-Object -TypeName PSObject
$Object | Add-Member -MemberType NoteProperty -Name FileName -Value $RawFile.Name
$Object | Add-Member -MemberType NoteProperty -Name FullPath -Value $FullPathName
$Object | Add-Member -MemberType NoteProperty -Name CompressedLengthInKB -Value ($RawFile.CompressedLength/1KB).Tostring("00")
$Object | Add-Member -MemberType NoteProperty -Name UnCompressedLengthInKB -Value ($RawFile.Length/1KB).Tostring("00")
$Object | Add-Member -MemberType NoteProperty -Name FileExtn -Value ([System.IO.Path]::GetExtension($RawFile.FullName))
$Object | Add-Member -MemberType NoteProperty -Name ZipFileName -Value $zipfile
$ObjArray += $Object
}
}
Make sure dot net 4.5 is installed before running the above cmdlets.
For now I have this piece of code:
$items = #()
$OutputFilePath = "c:\csv\text1.csv"
dir -Force -Recurse | foreach {
$FullName = $_.FullName
$Creation = $_.CreationTimeUtc
$Modified = $_.LastWriteTimeUtc
$Accessed = $_.LastAccessTimeUtc
$Size = $_.Length
$Atributes = $_.Attributes
$i = New-Object -TypeName psobject
$i | Add-Member -MemberType NoteProperty -Name FullName -Value $FullName
$i | Add-Member -MemberType NoteProperty -Name CreatedDateUtc -Value $Creation
$i | Add-Member -MemberType NoteProperty -Name CreatedTimeUtc -Value $Creation.TimeOfDay
$i | Add-Member -MemberType NoteProperty -Name CreatedTicksUtc -Value $Creation.Ticks
$i | Add-Member -MemberType NoteProperty -Name ModifiedDateUtc -Value $Modified
$i | Add-Member -MemberType NoteProperty -Name ModifiedTimeUtc -Value $Modified.TimeOfDay
$i | Add-Member -MemberType NoteProperty -Name ModifiedTicksUtc -Value $Modified.Ticks
$i | Add-Member -MemberType NoteProperty -Name AccessedDateUtc -Value $Accessed
$i | Add-Member -MemberType NoteProperty -Name AccessedTimeUtc -Value $Accessed.TimeOfDay
$i | Add-Member -MemberType NoteProperty -Name AccessedTicksUtc -Value $Accessed.Ticks
$i | Add-Member -MemberType NoteProperty -Name Size -Value $Size
$i | Add-Member -MemberType NoteProperty -Name Atributes -Value $Atributes
$items += $i
}
$FileExists = Test-Path $OutputFilePath
if ($FileExists -eq $False) {
$items | Export-Csv -Path $OutputFilePath -NoClobber -Encoding UTF8
} else {
[System.Windows.Forms.MessageBox]::Show("The output file already exists. Please delete or rename it to continue." ,"Error", 0, [System.Windows.Forms.MessageBoxIcon]::Error)
}
It gives me the list of UTC timestamps of all objects in a folder and subfolder. (I find UTC timestamps much more useful than non-UTC timestamps because I work on the concept of Virtual Reality weather timelapse service and I understand that errors at days when daylight saving time begins and ends wouldn't be acceptable so I say these errors are also unacceptable in other cases.) What I'm missing are the timestamps of parent folder itself.
How could I include timestamps of parent folder too?
Add a Get-Item on the current directory:
$(Get-Item .; Get-ChildItem . -Recurse -Force) | ForEach-Object {
...
}
In addition to Ansgar Wiechers's answer that solves the problem:
Create PSObject in one go instead of adding the members one by one which is slow
Pipe the output without recreating the array in each iteration which is slow
$OutputFilePath = "c:\csv\text1.csv"
if (Test-Path $OutputFilePath) {
[System.Windows.Forms.MessageBox]::Show(
"The output file already exists. Please delete or rename it to continue.",
"Error",
0,
[System.Windows.Forms.MessageBoxIcon]::Error
)
} else {
$(gi .; dir -Force -Recurse) | %{
New-Object PSObject -Property #{
FullName = $_.FullName
CreatedDateUtc = $_.CreationTimeUtc
CreatedTimeUtc = $_.CreationTimeUtc.TimeOfDay
CreatedTicksUtc = $_.CreationTimeUtc.Ticks
ModifiedDateUtc = $_.LastWriteTimeUtc
ModifiedTimeUtc = $_.LastWriteTimeUtc.TimeOfDay
ModifiedTicksUtc = $_.LastWriteTimeUtc.Ticks
AccessedDateUtc = $_.LastAccessTimeUtc
AccessedTimeUtc = $_.LastAccessTimeUtc.TimeOfDay
AccessedTicksUtc = $_.LastAccessTimeUtc.Ticks
Size = $_.Length
Atributes = $_.Atributes
}
} | Export-Csv -Path $OutputFilePath -NoClobber -Encoding UTF8
}
I've used aliases (gi for Get-Item and % for foreach) since you're fond of them.