0

我的目标是编写一个 powershell 脚本,它将递归地检查文件服务器中是否存在任何“x”(插入天数)旧或更旧的目录。

我最初遇到了一些问题,我想我已经解决了大部分问题。我遇到的问题之一是 248 个字符的路径限制。我发现我在我的代码中实现了一个自定义函数来绕过这个限制。

最终结果是我想输出文件夹的路径和 LastAccessTime 并将信息导出到易于阅读的 csv 文件中。

目前一切正常,但由于某种原因,我多次输出一些路径(重复,三倍,甚至 4 次)。我只希望它为每个目录和子目录输出一次。

我会很感激我能得到的任何指导。提前致谢。这是我的代码

#Add the import and snapin in order to perform AD functions
Add-PSSnapin Quest.ActiveRoles.ADManagement -ea SilentlyContinue
Import-Module ActiveDirectory

#Clear Screen
CLS

Function Get-FolderItem 
{
    [cmdletbinding(DefaultParameterSetName='Filter')]
    Param (
        [parameter(Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [Alias('FullName')]
        [string[]]$Path = $PWD,
        [parameter(ParameterSetName='Filter')]
        [string[]]$Filter = '*.*',    
        [parameter(ParameterSetName='Exclude')]
        [string[]]$ExcludeFile,              
        [parameter()]
        [int]$MaxAge,
        [parameter()]
        [int]$MinAge
    )
    Begin 
    {
        $params = New-Object System.Collections.Arraylist
        $params.AddRange(@("/L","/S","/NJH","/BYTES","/FP","/NC","/NFL","/TS","/XJ","/R:0","/W:0"))

        If ($PSBoundParameters['MaxAge']) 
        {
            $params.Add("/MaxAge:$MaxAge") | Out-Null
        }
        If ($PSBoundParameters['MinAge']) 
        {
            $params.Add("/MinAge:$MinAge") | Out-Null
        }
    }
    Process 
    {
        ForEach ($item in $Path) 
        {
            Try 
            {
                $item = (Resolve-Path -LiteralPath $item -ErrorAction Stop).ProviderPath

                If (-Not (Test-Path -LiteralPath $item -Type Container -ErrorAction Stop)) 
                {
                    Write-Warning ("{0} is not a directory and will be skipped" -f $item)
                    Return
                }

                If ($PSBoundParameters['ExcludeFile']) 
                {
                    $Script = "robocopy `"$item`" NULL $Filter $params /XF $($ExcludeFile  -join ',')"
                } 

                Else 
                {
                    $Script = "robocopy `"$item`" NULL $Filter $params"
                }

                Write-Verbose ("Scanning {0}" -f $item)

                Invoke-Expression $Script | ForEach {
                    Try 
                    {
                       If ($_.Trim() -match "^(?<Children>\d+)\s+(?<FullName>.*)") 
                       {
                            $object = New-Object PSObject -Property @{
                                ParentFolder = $matches.fullname -replace '(.*\\).*','$1'
                                FullName = $matches.FullName
                                Name = $matches.fullname -replace '.*\\(.*)','$1'
                            }
                            $object.pstypenames.insert(0,'System.IO.RobocopyDirectoryInfo')

                            Write-Output $object
                        }
                        Else 
                        {
                            Write-Verbose ("Not matched: {0}" -f $_)
                        }
                    } 
                    Catch 
                    {
                        Write-Warning ("{0}" -f $_.Exception.Message)
                        Return
                    }
                }
            } 
            Catch 
            {
                Write-Warning ("{0}" -f $_.Exception.Message)
                Return
            }
        }
    }
}

Function ExportFolders 
{
   #================ Global Variables ================

   #Path to folders
    $Dir = "\\myFileServer\somedir\blah"

   #Get all folders
    $ParentDir = Get-ChildItem $Dir | Where-Object {$_.PSIsContainer -eq $True}

   #Export file to our destination
    $ExportedFile = "c:\temp\dirFolders.csv"

   #Duration in Days+ the file hasn't triggered "LastAccessTime"
    $duration = 800
    $cutOffDate = (Get-Date).AddDays(-$duration)

   #Used to hold our information
    $results = @()

   #=============== Done with Variables ===============

    ForEach ($SubDir in $ParentDir)
    {
        $FolderPath = $SubDir.FullName

        $folders = Get-ChildItem -Recurse $FolderPath -force -directory| Where-Object { ($_.LastAccessTimeUtc -le $cutOffDate)} | Select-Object FullName, LastAccessTime

        ForEach ($folder in $folders)
        {
            $folderPath = $folder.fullname
            $fixedFolderPaths = ($folderPath | Get-FolderItem).fullname

            ForEach ($fixedFolderPath in $fixedFolderPaths)
            {
                #$fixedFolderPath
                $getLastAccessTime = $(Get-Item $fixedFolderPath -force).lastaccesstime
                #$getLastAccessTime

                $details = @{ "Folder Path" = $fixedFolderPath; "LastAccessTime" = $getLastAccessTime}

                $results += New-Object PSObject -Property $details
                $results
            }               
        }
    }
}

ExportFolders

我稍微更新了我的代码并简化了它。这是新代码。

#Add the import and snapin in order to perform AD functions
Add-PSSnapin Quest.ActiveRoles.ADManagement -ea SilentlyContinue
Import-Module ActiveDirectory

#Clear Screen
CLS

Function ExportFolders 
{
   #================ Global Variables ================

   #Path to user profiles in Barrington
    $Dir = "\\myFileServer\somedir\blah"

   #Get all user folders
    $ParentDir = Get-ChildItem $Dir | Where-Object {$_.PSIsContainer -eq $True} | where {$_.GetFileSystemInfos().Count -eq 0 -or $_.GetFileSystemInfos().Count -gt 0}

   #Export file to our destination
    $ExportedFile = "c:\temp\dirFolders.csv"

   #Duration in Days+ the file hasn't triggered "LastAccessTime"
    $duration = 1
    $cutOffDate = (Get-Date).AddDays(-$duration)

   #Used to hold our information
    $results = @()
    $details = $null

   #=============== Done with Variables ===============

    ForEach ($SubDir in $ParentDir)
    {
        $FolderName = $SubDir.FullName
        $FolderInfo = $(Get-Item $FolderName -force) | Select-Object FullName, LastAccessTime #| ft -HideTableHeaders
        $FolderLeafs = gci -Recurse $FolderName -force -directory | Where-Object {$_.PSIsContainer -eq $True} | where {$_.GetFileSystemInfos().Count -eq 0 -or $_.GetFileSystemInfos().Count -gt 0} | Select-Object FullName, LastAccessTime #| ft -HideTableHeaders

        $details = @{ "LastAccessTime" = $FolderInfo.LastAccessTime; "Folder Path" = $FolderInfo.FullName}
        $results += New-Object PSObject -Property $details

        ForEach ($FolderLeaf in $FolderLeafs.fullname)
        {
            $details = @{ "LastAccessTime" = $(Get-Item $FolderLeaf -force).LastAccessTime; "Folder Path" = $FolderLeaf}
            $results += New-Object PSObject -Property $details
        }

        $results
    }
}

ExportFolders

FolderInfo 变量有时会打印出多次,但 FolderLeaf 变量会打印出一次。问题是,如果我从打印出 folderInfo 的详细信息中移动或删除结果变量,则不会打印出父目录。仅显示所有子目录。还有一些目录是空的,不会打印出来,我希望打印出所有目录,包括空目录。

更新后的代码似乎可以很好地打印所有目录,但正如我提到的,我仍然得到一些重复的 $FolderInfo 变量。

我想我必须输入一个条件或其他东西来检查它是否已经被处理,但我不确定我会使用哪个条件来做到这一点,这样它就不会被打印多次。

4

1 回答 1

0

在你的ExportFoldersGet-ChildItem -Recurse中,然后遍历所有调用Get-FolderItem. 然后在Get-FolderItem您为 Robocopy 提供/S标志中的标志,$params.AddRange(@("/L", "/S", "/NJH", "/BYTES", "/FP", "/NC", "/NFL", "/TS", "/XJ", "/R:0", "/W:0"))/S标志表示复制子目录,但不是空的。所以你又在递归了。可能您只需要删除/S标志,以便您在ExportFolders.

回应编辑:

$results在循环里面。因此,您将有第一个重复项,$subdir然后第二个重复 n-1 个,依此类推。

ForEach ($SubDir in $ParentDir) {
    #skipped code
    ForEach ($FolderLeaf in $FolderLeafs.fullname) {
         #skipped code
    }
    $results
}

应该

ForEach ($SubDir in $ParentDir) {
    #skipped code
    ForEach ($FolderLeaf in $FolderLeafs.fullname) {
         #skipped code
    }
}
$results
于 2018-04-24T16:44:23.357 回答