又到了每月一次的PowerShell腳本比賽。這次的題目很有趣,測試了好幾個知識點,豆子花了半天的功夫才全部實現。
http://powershell.org/wp/2016/03/05/2016-march-scripting-games-puzzle/
題目如下:
某歐洲文件服務器里面有大量的文件名是使用拉丁字母命名的,把他們都找出來。
具體的要求有以下幾點:
所有的這些拉丁字母(法語,德語等等)都是屬于Latin-1 字母范疇,只需要找到包含這些字母的文件,其他的拉丁符號不用考慮。
寫一個函數來獲取這些文件的名稱,位置,尺寸;尺寸需要好的可讀性,比如小文件顯示多少K,大文件顯示多少M或者多少G
如果找到了對應的文件信息,按下列格式yyyyMMdd_FileNamesWithDiacritics.csv 保存為csv文件。yyyyMMdd表示年份,月份和日期。
寫一個計劃任務,每2周六晚上11點執行上面的函數
把上面生成的附件發郵件給管理員
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 = "abc@test.com" $to = "abc@test.com" $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 = "abc@test.com" $to = "def@test.com" $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"
收到的郵件
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。