Powershell Scripting Game - March 2016

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Powershell Scripting Game - March 2016相关的知识,希望对你有一定的参考价值。

又到了每月一次的PowerShell脚本比赛。这次的题目很有趣,测试了好几个知识点,豆子花了半天的功夫才全部实现。

http://powershell.org/wp/2016/03/05/2016-march-scripting-games-puzzle/

题目如下:

某欧洲文件服务器里面有大量的文件名是使用拉丁字母命名的,把他们都找出来。

具体的要求有以下几点:

  1. 所有的这些拉丁字母(法语,德语等等)都是属于Latin-1 字母范畴,只需要找到包含这些字母的文件,其他的拉丁符号不用考虑。

  2. 写一个函数来获取这些文件的名称,位置,尺寸;尺寸需要好的可读性,比如小文件显示多少K,大文件显示多少M或者多少G

  3. 如果找到了对应的文件信息,按下列格式yyyyMMdd_FileNamesWithDiacritics.csv 保存为csv文件。yyyyMMdd表示年份,月份和日期。

  4. 写一个计划任务,每2周六晚上11点执行上面的函数

  5. 把上面生成的附件发邮件给管理员

  6. http://powershell.org/wp/wp-content/uploads/2016/03/FileShare.zip 这个是用来测试的文件 


下面是豆子完成的步骤:

1.首先需要解决的问题是怎么找到这些拉丁字母?根据提示,我发现Latin-1的Unicode代码如下所示。如果只是显示字母而不包括其他的符号,那么他的代码范围是00C0到00FF

技术分享

那这样的话 我可以通过正则表达式来进行判断是否文件名包括了这些符号。比如

Get-ChildItem -Recurse c:\test | Where-Object {$_.name -match "[\u00C0-\u00FF]"}


2. 输出文件大小,还必须有很好的可读性。他默认的输出结果是按字节排列的,我需要根据大小进行重新定义,如果精度太长也很难看,我需要保留小数点后一位就行了。

我可以在自定义的字段里面进行判断,如果小于1000字节的 用Byte显示,小于1M 的用KB显示,大于1G的用MB显示。


例如

  Get-ChildItem -Recurse -Path $path| 
        Where-Object {$_.name -match "[\u00C0-\u00FF]"} | 
        select Name, directory, creationtime, lastwritetime,
        @{
        n="Size";
        e={
        if($_.length -lt 1000){"{0:n1}" -f $_.length.tostring()+" Byte"}
        elseif($_.length -lt 1000000){("{0:n1}" -f ($_.length/1kb)).ToString()+" KB" }
        else{("{0:n1}" -f ($_.length/1mb)).ToString() + " MB"} 
        }
        } | tee -Variable file



3.  按照时间格式保存,可以使用 get-date -Format YYYY.M.d 来实现。注意我export-csv的时候指定了编码格式是Unicode,不然默认的是ASII格式只会显示问号。


        if($file -eq $null){Write-Warning "No file name dectected with Latin Character"}
        else{
        $name=(get-date -Format yyyy.M.d)+"FileNamesWithDiacritics.csv"
        
        $file | export-csv c:\temp\$name -Encoding Unicode}


4.计划任务。这里应该有个bug。我用的是Windows10和Powershell 5,但是当我创建触发器的时候会报错找不到对应的命令。经过研究,需要手动注册对应的mof文件的内容到WMI库里面。

mofcomp那条命令就是手动注册的命令。

mofcomp C:\Windows\System32\wbem\SchedProv.mof
$action = New-ScheduledTaskAction -Execute ‘Powershell.exe‘ -Argument ‘Get-Diacritic.ps1 ‘
$trigger = New-ScheduledTaskTrigger -Weekly -WeeksInterval 2 -DaysOfWeek Saturday -At 3am
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "LatinName" -Description "Weekly FileName Scanning"


5.发送文件给管理员


注意这里我用的是Office365测试的,所以端口是587。我为了省事,密码用的是明文,比较好的做法应该是把加密之后的指纹(一堆乱码),拷贝到脚本里面使用。

$from = "[email protected]"
$to = "[email protected]" 
$smtp = "smtp.office365.com" 
$sub = "file list" 
$body = "Attached is the file list"
$attach="C:\scripts\file.csv"
$secpasswd = ConvertTo-SecureString "Password" -AsPlainText -Force 
$mycreds = New-Object System.Management.Automation.PSCredential ($from, $secpasswd)
Send-MailMessage -To $to -From $from -Subject $sub -Body $body -Credential $mycreds -SmtpServer $smtp -DeliveryNotificationOption Never -BodyAshtml -UseSsl -port 587 -Attachments $attach


最后给个完整的版本


Get-Diacritic.ps1

function Get-Diacritic
{
    [CmdletBinding()]
    
    Param
    (
        # Param1 help description
        [Parameter(
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $Path=".\"
    )
    Begin
    {
    }
    Process
    {
    
        Get-ChildItem -Recurse -Path $path| 
        Where-Object {$_.name -match "[\u00C0-\u00FF]"} | 
        select Name, directory, creationtime, lastwritetime,
        @{
        n="Size";
        e={
        if($_.length -lt 1000){"{0:n1}" -f $_.length.tostring()+" Byte"}
        elseif($_.length -lt 1000000){("{0:n1}" -f ($_.length/1kb)).ToString()+" KB" }
        else{("{0:n1}" -f ($_.length/1mb)).ToString() + " MB"} 
        }
        } | tee -Variable file 
        if($file -eq $null){Write-Warning "No file name dectected with Latin Character"}
        else{
        $name=(get-date -Format yyyy.M.d)+"FileNamesWithDiacritics.csv"
        
        $file | export-csv c:\temp\$name -Encoding Unicode}
        $from = "[email protected]"
        $to = "[email protected]" 
        $smtp = "smtp.office365.com" 
        $sub = "file list" 
        
        $Body = $file | ConvertTo-Html -Head "Scanning Result" -As Table | Out-String
        $attach="c:\temp\"+$name
        $secpasswd = ConvertTo-SecureString "Password" -AsPlainText -Force 
        $mycreds = New-Object System.Management.Automation.PSCredential ($from, $secpasswd)
        Send-MailMessage -To $to -From $from -Subject $sub -Body $body -Credential $mycreds -SmtpServer $smtp -DeliveryNotificationOption Never -BodyAsHtml -UseSsl -port 587 -Attachments $attach
    }
    End
    {
    }
}

Get-Diacritic c:\users\yli\Downloads


计划任务脚本

mofcomp C:\Windows\System32\wbem\SchedProv.mof
$action = New-ScheduledTaskAction -Execute ‘Powershell.exe‘ -Argument ‘Get-Diacritic -path C:\users\yli\Downloads‘
$trigger = New-ScheduledTaskTrigger -Weekly -WeeksInterval 2 -DaysOfWeek Saturday -At 3am
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "LatinName" -Description "Weekly FileName Scanning"


运行结果

下面的值保存为CSV文件

技术分享


保存的文件名

技术分享


创建的计划任务


技术分享


执行一下计划任务

Start-ScheduledTask -TaskName "LatinName"


收到的邮件

技术分享


本文出自 “麻婆豆腐” 博客,请务必保留此出处http://beanxyz.blog.51cto.com/5570417/1749412

以上是关于Powershell Scripting Game - March 2016的主要内容,如果未能解决你的问题,请参考以下文章

PowerShell启用多跳远程控制

PowerShell启用多跳远程控制

[powershell]Use powershell to get file hash / 使用powershell获取文件哈希值

VBS使用Scripting.Dictionary字典对象

Excel:Scripting.Dictionary

访问 VBA:Scripting.Dictionary - 转储到表?