【问题标题】:Is this powershell script a good way to find the owner then change the owner这个powershell脚本是找到所有者然后更改所有者的好方法吗
【发布时间】:2013-08-11 12:34:21
【问题描述】:

我编写了一个 Powershell v3 脚本来列出我们文件服务器上用户拥有的所有文件。在我停止之前它运行了 3 个小时。它必须经过 619,238 个文件和 57,452 个文件夹 (517 GB)。这应该采取什么数量级?有没有办法提高速度?

我尝试使用管道来执行此操作,但没有得到任何工作。

它在运行 Windows 2009 R2 SP1 且内存为 4GB 的 Vmware 虚拟机上运行。当我运行它时,它使用了大约 60% 的 CPU。

这里是我写的代码。我对 Powershell 很陌生,但我对 Perl 有很多经验。我的同事说要写一个bat文件。

<#
.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

谢谢, 丹

【问题讨论】:

    标签: file loops powershell ownership


    【解决方案1】:

    我不知道应该采取什么数量级,但为了提高速度,您可以从删除 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 分钟。我再次建议在您的系统上运行一小部分文件,以计算运行整个文件集需要多长时间。

    【讨论】:

    • 感谢帮助它现在运行得更快了。在 Write-Output $file.FullName | 行中Out-File -FilePath $logfile -Append 有没有办法在不截断路径的情况下也写出 $file.LastWriteTime?我尝试了几种方法都没有成功。
    • 我使用了两个简单的文本文件 log.txt 和 file.txt:$log = Get-Item log.txt $file = Get-Item fileFound.txt $textOutput = ("{0}, Last write time: {1}" -f $file.FullName, $file.LastWriteTime) Write-Host $textOutput Write-Output $textOutput | Out-File -FilePath $log -Append -Encoding ASCII 只需先创建要写入的字符串,然后将其写入文件。
    • 非常感谢。我不完全明白你做了什么。所以,我这样做了:$textOutput = ("{0}, Last write time: {1}" -f $file.FullName, $file.LastWriteTime); Write-Host $textOutput; Write-Output $textOutput | Out-File -FilePath $logfile -Append -Encoding ASCII;
    • 没问题,这和我做的基本一样。
    【解决方案2】:

    尝试使用它来记录用户拥有的文件,因为在整个过程完成之前不会写入磁盘:

    [string]$fileowned +=  $file.fullname|?{$f.owner -eq $username -or $f.owner -eq $AD_username}
    

    一旦退出循环,然后将生成的 $logfile 写入磁盘:

    $fileowned|out-file $logfile
    

    顺便说一句,您使用了两次 $d;一次用于获取日期,下一次用于比较字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多