这个powershell脚本是找到所有者然后更改所有者的好方法

时间:2013-08-09 14:25:37

标签: file loops powershell ownership

我编写了一个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

谢谢, 丹

2 个答案:

答案 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分钟。我再次建议使用一小部分文件在系统上运行,以计算在运行整个集合之前需要多长时间。