我编写了一个Powershell v3脚本,列出了文件服务器上用户拥有的所有文件。在我停下来之前它跑了3个小时。它必须通过619,238个文件和57,452个文件夹(517 GB)。这需要多少个数量级?有没有办法提高速度?
我尝试使用管道进行此操作,但无法正常工作。
它运行在运行Windows 2009 R2 SP1且内存为4GB的Vmware虚拟机上。它在我运行时占用了大约60%的CPU。
这里是我写的代码。我是Powershell的新手,但我对Perl有很多经验。我的同事说要写一个蝙蝠档。
<#
.SYNOPSIS
C:\ams\psscripts\list-files.ps1
.DESCRIPTION
List all the files that a given user owns
.PARAMETER none
username: user
logfile: path to log file. This is optional. If omitted the the log file is created "u:\scratch\<$username>-files.txt
.EXAMPLE
C:\ams\psscripts\list-files.ps1 plo
Example: C:\ams\psscripts\list-files.ps1 plo u:\scratch\log.txt
#>
param (
[string]$username,
[string]$logfile
)
# Load modules
Set-ExecutionPolicy Unrestricted
Import-Module ActiveDirectory
Add-PSSnapin Quest.ActiveRoles.ADManagement
function printHelp {
Write-Host "This script will find all the files owned by a user. It scans \\dfs\groups"
Write-Host "C:\ams\psscripts\list-files.ps1 user logfile (optional)"
Write-Host "Example: C:\ams\psscripts\list-files.ps1 plo"
Write-Host "Example: C:\ams\psscripts\list-files.ps1 plo u:\scratch\log.txt"
}
if ($logfile -eq "") {
$logfile = "u:\scratch\" + $username + "-files.txt"
Write-Host "Setting log file to $logfile"
}
# you must use a UNC path
[String]$path = "\\dfs\u$\groups"
[String]$AD_username = "AMS\" + $username
# check that we have a valid AD user
if (!(Get-QADUser $AD_username)){
Write-Host "ERROR: Not a valid AD User: $AD_username"
Exit 0
}
Write-Output "Listing all files owned by $username from $path" | Out-File -FilePath $logfile
Write-Host "Listing all files owned by $username from $path"
$d = Get-Date
Write-Output $d | Out-File -FilePath $logfile -Append
$files = Get-ChildItem $path -Recurse
Foreach ($file in $files)
{
$f = Get-Acl $file.FullName
$d = [string]::Compare($file.FullName, $username, $True)
if (($f.Owner -eq $username) -or ($f.Owner -eq $AD_username))
{
Write-Host "$file.FullName"
Write-Output $file.FullName | Out-File -FilePath $logfile -Append
}
}
Write-Host "Completed"
exit 0
我要做的下一步是修改上面的脚本,找到给定用户拥有的文件,并将其更改为经理。
这是我发现更改所有者的脚本。它将处于循环文件系统的循环中。这是一个很好的方法。
$username=”dnp”
$domain=”ams”
$ID = new-object System.Security.Principal.NTAccount($domain, $username)
# file to change owner. must be UNC path
$path = "\\dfs\c$\ams\psscripts\test.txt"
write-host $path
$acl = get-acl $path
$acl.SetOwner($ID)
set-acl -path $path -aclObject $acl
谢谢, 丹
答案 0 :(得分:0)
尝试使用它来记录用户拥有的文件,因为在整个过程完成之前没有写入磁盘:
[string]$fileowned += $file.fullname|?{$f.owner -eq $username -or $f.owner -eq $AD_username}
一旦退出循环,则将结果$ logfile写入磁盘:
$fileowned|out-file $logfile
顺便说一句,你两次使用$ d;一次用于比较字符串的get-date和next。
答案 1 :(得分:0)
我不知道应该采取什么样的数量级,但要通过删除foreach
循环中的冗余比较来提高开始的速度:
$d = [string]::Compare($file.FullName, $username, $True)
字符串比较成本很高,而且您没有使用$d
。您还要与$ username或“AMS \”+ $ username进行比较,这又是昂贵的。我不明白为什么你需要与两者进行比较。我已修改您的脚本以添加时间。我建议在文件的子集上进行尝试,以获得一些经验数据来计算出整个集合需要多长时间。请记住,在这种情况下,文件的总大小是无关紧要的,因为您不处理它们,只是它们的属性。
<#
.SYNOPSIS
C:\ams\psscripts\list-files.ps1
.DESCRIPTION
List all the files that a given user owns
.PARAMETER none
username: user
logfile: path to log file. This is optional. If omitted the the log file is created "u:\scratch\<$username>-files.txt
.EXAMPLE
C:\ams\psscripts\list-files.ps1 plo
Example: C:\ams\psscripts\list-files.ps1 plo u:\scratch\log.txt
#>
param (
[string]$username,
[string]$logfile
)
# Load modules
Set-ExecutionPolicy Unrestricted
#Import-Module ActiveDirectory
#Add-PSSnapin Quest.ActiveRoles.ADManagement
function printHelp {
Write-Host "This script will find all the files owned by a user. It scans \\dfs\groups"
Write-Host "C:\ams\psscripts\list-files.ps1 user logfile (optional)"
Write-Host "Example: C:\ams\psscripts\list-files.ps1 plo"
Write-Host "Example: C:\ams\psscripts\list-files.ps1 plo u:\scratch\log.txt"
}
#StopWatch
$stopWatch = New-Object System.Diagnostics.Stopwatch
$stopWatch.Start()
if ($logfile -eq "") {
$logfile = "e:\scratch\" + $username + "-files.txt"
Write-Host "Setting log file to $logfile"
}
# you must use a UNC path
[String]$path = "\\test-server\testfolder\subfolder"
[String]$AD_username = "AMS\" + $username
# check that we have a valid AD user
if (!(Get-QADUser $AD_username)){
Write-Host "ERROR: Not a valid AD User: $AD_username"
Exit 0
}
Write-Output "Listing all files owned by $username from $path" | Out-File -FilePath $logfile
Write-Host "Listing all files owned by $username from $path"
$d = Get-Date
Write-Output $d | Out-File -FilePath $logfile -Append
$stopWatch.Stop()
Write-Output ("Setup time: {0}." -f $stopWatch.Elapsed) | Out-File -FilePath $logfile -Append
$stopWatch.Reset()
$stopWatch.Start()
$files = Get-ChildItem $path -Recurse
$stopWatch.Stop()
Write-Output ("Got {0} files to process, took {1}" -f $files.Count, $stopWatch.Elapsed) | Out-File -FilePath $logfile -Append
$stopWatch.Reset()
$stopWatch.Start()
Foreach ($file in $files)
{
$f = Get-Acl $file.FullName
#$d = [string]::Compare($file.FullName, $username, $True)
#if (($f.Owner -eq $username) -or ($f.Owner -eq $AD_username))
if ($f.Owner -eq $AD_username)
{
Write-Host ("{0}" -f $file.FullName)
Write-Output $file.FullName | Out-File -FilePath $logfile -Append
}
}
$stopWatch.Stop()
Write-Output ("Processed {0} files, took {1}" -f $files.Count, $stopWatch.Elapsed) | Out-File -FilePath $logfile -Append
Write-Host "Completed"
exit 0
运行此操作会在我们的基础架构中产生以下结果:
得到37803个文件要处理,取00:00:57.5834897
处理了37803个文件,耗时00:10:42.2988004
原始代码用了15分钟来处理相同数量的文件:
处理了37803个文件,耗时00:15:04.1024350
在内存字符串构造中添加了@ GeorgeR.Jenkins,但它没有显着减少处理时间:
处理了37803个文件,取得了00:10:26.7815446
有趣的是,尝试将get-childitem传递给where子句并没有改善性能。使用
$files = Get-ChildItem $path -Recurse | where {(Get-Acl $_.FullName).Owner -eq $AD_username} <br/>
只会返回具有正确所有者的文件,因此以后不需要处理: 有46个文件要处理,花了00:13:51.4940596
所有人都说,如果你在类似的基础设施上运行,我预计,以我见过的最快速度,即每秒59个文件,你的619,238个文件需要大约175分钟。我用原始代码获得的速率是每秒42个文件,这需要246分钟。我再次建议使用一小部分文件在系统上运行,以计算在运行整个集合之前需要多长时间。