クロージャー

クロージャーってなんかカッコいい。コードレビューで、なんでクロージャー使ってんの?の質問に答えられないならオススメしません。
理にかなったクロージャーはカッコいい。

function Closure {
  $n = 1
  {
    $script:n = $n + 1
    $n
  }.GetNewClosure() 
}

$obj1 = Closure
$obj2 = Closure
& $obj1
# 2
& $obj1
# 3
& $obj2
# 2
& $obj2
# 3

filter

?Where-Objectコマンドと同じですね。

# 偶数のみ取り出す
1..10 | ? { $_ % 2 -eq 0 }

map

%Foreach-Objectコマンドと同じですね。

# 全てに2をかける
1..10 | % { $_ * 2 }

portを使ってるプロセス

Select-Stringは正規表現も使用できるので柔軟性が増しますね。

netstat -aon | Select-String ".0.0:4000"
netstat -aon | Select-String -Pattern ".0.0:4000$"

&{}と.{}の違い

&{}はスクリプト内部で処理を留める
.{}は元のスコープに影響する

$hoge = $null
& {$hoge = 4}
# [String]::IsNullOrEmpty($hoge)
# True

$hoge = $null
. {$hoge = 4}
# [String]::IsNullOrEmpty($hoge)
# False

$hoge
# 4

Firewall設定確認

Get-NetFirewallRule | where {$_.DisplayName -eq "Something"}

Test-ComputerSecureChannel コマンドレットの使い方

Test-ComputerSecureChannel コマンドレットは、信頼関係の状態をチェックして、ローカルコンピューターとドメインの間のセキュリティで保護されたチャネルが正しく機能しているかどうかを検証します。
会社でOutlookが更新されないなぁって時に確認するといいかもしれません。
コンパネでネットワークアダプターを無効にして、再度有効にすると調子がようくなる場合もありました。

# ローカルコンピューター上のAdministratorsグループのメンバーで実行する
# 確認
Test-ComputerSecureChannel

# 修復
Test-ComputerSecureChannel -credential administrator -repair

Gulp的なファイルの変更監視スクリプト

下記の場合、Register-TaskRunner.ps1と同じフォルダーに置いた拡張子がps1のファイルを監視する。 また、変更したファイルのユニットテストが同じフォルダにある場合は変更の度に実行される。
どこのファイルを監視するかやユニットテストを実行するかは調整できます。
また、変更を検知した際に実行されるコマンドも調整可能です。

function Register-TaskRunner {
<#
.SYNOPSIS
Watch changing file and run any tasks.

.DESCRIPTION
Powershell task runner

.EXAMPLE
$parent = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
Register-Watcher -Folder $parent

.NOTES
https://msdn.microsoft.com/ja-jp/library/system.io.filesystemwatcher(v=vs.110).aspx  
https://mcpmag.com/articles/2015/09/24/changes-to-a-folder-using-powershell.aspx?m=1

#>
    [CmdletBinding()]
    Param
    (
      [Parameter(Mandatory=$true)]
      [string]$Folder,
      
      [Parameter(Mandatory=$false)]
      [string]$Filter = "*.ps1"
    )    

    $VerbosePreference = "Continue"
    $events = Get-EventSubscriber
    foreach ($event in $events) {
        if ($event.EventName -eq "Changed" -and $Folder -eq $event.SourceObject.Path) { 
            Write-Verbose "already exist the event."
            return
        }
    }
    
    $Watcher = New-Object IO.FileSystemWatcher -Property @{ 
        Path = $Folder
        Filter = $Filter
        IncludeSubdirectories = $false
        EnableRaisingEvents = $true
    }

    $changeAction = [scriptblock]::Create('
        $path = $Event.SourceEventArgs.FullPath
        $changedFileName = $Event.SourceEventArgs.Name
        $changeType = $Event.SourceEventArgs.ChangeType
        $timeStamp = $Event.TimeGenerated  
        $testScript = $changedFileName -replace ".ps1", ".Tests.ps1"  
        $testFullPath = "$($Event.MessageData)\$testScript"
        Write-Host "The file $changedFileName was $changeType at $timeStamp"
        if (Test-Path $testFullPath) { 
            Write-Host "Running $testScript" -BackgroundColor DarkGray       
            . $testFullPath
        } else {
            Write-Host "not exist $testScript" -BackgroundColor DarkGray       
        }
    ')

    Register-ObjectEvent -InputObject $Watcher `
                         -EventName "Changed" `
                         -Action $changeAction `
                         -MessageData $Folder
}
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
Register-TaskRunner -Folder $here

変更監視をやめたい時にはUnregister-TaskRunnerで。

function Unregister-TaskRunner {
    Get-EventSubscriber | Unregister-Event
}

Githubのトレンドを取得する

このように使用する
Get-GitHubTrend
Get-GitHubTrend -target javascript
Get-GitHubTrend -target ruby -length 10

function Get-GitHubTrend {
    Param
    (
       [Parameter(Mandatory=$false)]
       [string]$target = "powershell",

       [Parameter(Mandatory=$false)]
       [string]$baseUrl = "https://github.com",

       [Parameter(Mandatory=$false)]
       [string]$regex = '\"(.*)\"',

       [Parameter(Mandatory=$false)]
       [int]$length = 5,

       [Parameter(Mandatory=$false)]
       [switch]$week,

       [Parameter(Mandatory=$false)]
       [switch]$month
    )
    if ($week) {
        $url = "$baseUrl/trending/$($target)?since=weekly"
    } elseif ($month) {
        $url = "$baseUrl/trending/$($target)?since=monthly"
    } else {
        $url = "$baseUrl/trending/$target"
    }
    
    $geturl = Invoke-WebRequest -Uri $url
    $comment = $geturl.ParsedHtml.body.getElementsByTagName('div') | 
        Where {$_.getAttributeNode('class').Value -eq 'py-1'}
    $hrefs = $geturl.ParsedHtml.body.getElementsByTagName('div') | 
        Where {$_.getAttributeNode('class').Value -eq 'd-inline-block col-9 mb-1'}


    foreach ($html in $hrefs.innerHTML) {
        $result = (([regex]::Matches($html, $regex)).Groups[1].Value)
        $href += @("$baseUrl$result")
    }

    for ($i = 0; $i -lt $length; $i++) {
        if ($href[$i] -eq $null) { return }
        Write-Host $hrefs[$i].innerText  -BackgroundColor DarkGreen
        Write-Host $comment[$i].innerText
        Write-Host $href[$i] `n
    }
}

Hashを配列のように扱う

Hashをループで回したい時に使えるかと。

$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3

foreach($key in $($myHash.keys)){
    $myHash[$key] = 5
}