何も考えずにGet-NetTCPConnectionする
#外部の80番ポートに対する通信を表示する Get-NetTCPConnection | where {$_.RemotePort -eq 80 }
何も考えずにGet-NetTCPConnectionする
#外部の80番ポートに対する通信を表示する Get-NetTCPConnection | where {$_.RemotePort -eq 80 }
今年も残業が多かった 仕事をして技術的に得られたことはあまりなく、会議や調整ばかりしていたなあ。
来年はもう少し頑張りたい。
昨日の「Hey, Scripting Guy」!*1を読んでいて知ったのだが、最新のPowershell*2ではローカルユーザーを管理できる。
Microsoft Windows 10 Pro (10.0.14393) Major Minor Build Revision ----- ----- ----- -------- 5 1 14393 576
まずはどんなコマンドがあるか、手元の環境で確認してみる。
PS D:\SandBox> # とりあえずコマンドを引く PS D:\SandBox> Get-Command Get-LocalUser CommandType Name Version Source ----------- ---- ------- ------ Cmdlet Get-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts PS D:\SandBox> # 同じSourceに似たようなコマンドがないか調べる PS D:\SandBox> get-command -Module Microsoft.PowerShell.LocalAccounts CommandType Name Version Source ----------- ---- ------- ------ Cmdlet Add-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Disable-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Enable-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Get-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Get-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Get-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet New-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet New-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Remove-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Remove-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Remove-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Rename-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Rename-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Set-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts Cmdlet Set-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
続けていくつか使ってみる。
PS D:\SandBox> #ローカルユーザーの一覧から最初3つを取得 PS D:\SandBox> (Get-LocalUser)[1..3] Name Enabled Description ---- ------- ----------- DefaultAccount False システムで管理されるユーザー アカウントです。 Guest False コンピューター/ドメインへのゲスト アクセス用 (ビルトイン アカウント) HomeGroupUser$ True コンピューターへのホームグループ アクセス用のビルトイン アカウント PS D:\SandBox> #ローカルグループの一覧から最初3つを取得 PS D:\SandBox> (Get-LocalGroup)[1..3] Name Description ---- ----------- WinRMRemoteWMIUsers__ Members of this group can access WMI resources over management protocols (such a... __vmware__ VMware User Group Access Control Assistance Operators このグループのメンバーは、このコンピューター上のリソースの認証属性およびアクセス... PS D:\SandBox> #Administratorsグループのメンバーを取得 PS D:\SandBox> Get-LocalGroupMember Administrators ObjectClass Name PrincipalSource ----------- ---- --------------- ユーザー examplePC\Administrator Local
もっと詳しい使い方は公式のリファレンスを読めばよい。 Microsoft.PowerShell.LocalAccounts
PowerTip: Get a list of local Users in Windows 10 / Windows Server 2016 – Hey, Scripting Guy! Blog ⇒元ネタ
Tech TIPS:Windowsのnet userコマンドでユーザーアカウントを管理する - @IT ⇒該当コマンドレットが利用できない場合、昔ながらのnet user コマンドを使う。
bashならどうするの?というメモ
ユーザーの情報を取得したいだけならgetentコマンドを利用する。/etc/groupだけではわからないようなLDAP連携の値も持ってこれる。
変更を加えたいなら
範囲演算子(..)とパイプ(|)でループ処理のようなことができる
普通にループで書くなら以下のようになる。
#forループの場合 for ($i=0; $i -lt 10; $i++){ echo "hoge" } #foreachループの場合 foreach($cnt in 1..10){ echo "hoge" }
でも下のほうがすっきりしていると思う
PS D:\SandBox> 1..10 | %{ echo "hoge"}
変数も使える(一応実行例も載せた)
PS D:\SandBox> $limit=10 PS D:\SandBox> 1..$limit | %{ echo "hoge"} hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge
05.範囲演算子 < 演算子 Tips メニュー < PowerShell Tips < HIRO's.NET ⇒範囲演算子の簡単な説明
Powershellでプリンタの状態(ステータス)を取得するにはPrintManagementモジュールのGet-Printerを利用すればよい。
Powershll 3.0 以降
Get-Printerコマンドレットで特定のプリンタ名を指定してでCIMインスタンス*1を取得し、PrinterStatusを取得する*2。Normalなら利用できる状態のようだ。
PS D:\SandBox> (Get-Printer –Name "Microsoft XPS Document Writer").PrinterStatus Normal
※実行環境は以下
PS D:\SandBox> "$((get-wmiobject win32_operatingsystem).caption) ($((get-wmiobject win32_operatingsystem).version))" Microsoft Windows 10 Pro (10.0.14393) PS D:\SandBox> $PSVersionTable.PSVersion Major Minor Build Revision ----- ----- ----- -------- 5 1 14393 206
いつもの通り、英語版も含めてPowershellのレファレンスはクソなので何とかしてほしい。 PrinterStatusが取りうる値の範囲ぐらい明記してほしい。
技術面接で出された問題 - esm アジャイル事業部 開発者ブログ
上記のエントリを読んでPowershellだとどうやって実装するかなーと思ったので、テキトーに試す。
ソートだとこんな感じ?*1
[String]$a="ABCB" [String]$b="BCAB" if($a -eq $b){return $false} # 完全に一致する場合はアナグラムではないのでNG #$aと$bをソートした上で比較する。一致すればアナグラム。 $aa="" $bb="" if(($a.ToCharArray() | Sort-Object | %{$aa=$aa + $_}) -eq ($b.ToCharArray() | Sort-Object | %{$bb=$bb + $_})){return $true}else{return $false}
AとBに含まれる文字ごとの個数が一致すればOKのはずなので、もうちょっと真面目に書くとこんな感じ?
[String]$a="ABCB" [String]$b="BCAB" if($a -eq $b){return $false} #完全に一致する場合はアナグラムではないのでNG $hash1=@{} $a.ToCharArray() | %{if($hash1.ContainsKey($_)){$hash1[$_]=$hash1[$_]+1}else{$hash1[$_]=1}}; $b.ToCharArray() | %{if($hash1.ContainsKey($_)){$hash1[$_]=$hash1[$_]-1}else{$hash1[$_]=-1}}; $flg=$true $hash1.Values | %{if($_ -ne 0){$flg=$false}} return $flg
関数として使えるものにするなら、以下のようなこともしなくてはならないけど、まあこんな感じで実装できそうだということの確認にはなった。
Copy-itemを使ったディレクトリコピーはコピー先に指定するディレクトリの有無に依存して挙動が変わってしまう。
面倒でもディレクトリコピーはしないほうが無難であり、コピー先フォルダを作成した上で、コピー元フォルダ以下をワイルドカードコピーすべきでは、という話
というか、ディレクトリコピーをするならPowershellにこだわらずrobocopyを使ったほうが良いのだろうと思う*1
PS D:\SandBox> "$((get-wmiobject win32_operatingsystem).caption) ($((get-wmiobject win32_operatingsystem).version))" Microsoft Windows 10 Pro (10.0.10586) PS D:\SandBox> $PSVersionTable.PSVersion Major Minor Build Revision ----- ----- ----- -------- 5 0 10586 494
PS D:\SandBox> #フォルダ構成 PS D:\SandBox> tree /f D:\SandBox フォルダー パスの一覧 ボリューム シリアル番号は 4641-823A です D:\SANDBOX └─from test1.txt test2.txt PS D:\SandBox> #コピー先ディレクトリが存在しない場合にディレクトリコピーする PS D:\SandBox> Copy-Item .\from .\to -Recurse -Force -PassThru ディレクトリ: D:\SandBox Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2016/09/19 15:35 to ディレクトリ: D:\SandBox\to Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2016/09/19 15:31 14 test1.txt -a---- 2016/09/19 15:31 14 test2.txt PS D:\SandBox> #コピー先フォルダが作成され、ディレクトリがコピーされる PS D:\SandBox> tree /f D:\SandBox フォルダー パスの一覧 ボリューム シリアル番号は 4641-823A です D:\SANDBOX ├─from │ test1.txt │ test2.txt │ └─to test1.txt test2.txt PS D:\SandBox> PS D:\SandBox> #上記のようにコピー先フォルダが存在する状態で、先ほどと同じコマンドでディレクトリコピーする PS D:\SandBox> Copy-Item .\from .\to -Recurse -Force -PassThru ディレクトリ: D:\SandBox\to Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2016/09/19 15:37 from ディレクトリ: D:\SandBox\to\from Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2016/09/19 15:31 14 test1.txt -a---- 2016/09/19 15:31 14 test2.txt PS D:\SandBox> tree /f D:\SandBox フォルダー パスの一覧 ボリューム シリアル番号は 4641-823A です D:\SANDBOX ├─from │ test1.txt │ test2.txt │ └─to │ test1.txt │ test2.txt │ └─from test1.txt test2.txt PS D:\SandBox> #コピー先ディレクトリの配下に、コピー元フォルダが複製される
コピー先の有無によって挙動が変わるのは再現性がないため避けたい。 以下のように、ディレクトリコピーではなく、ディレクトリ配下をワイルドカードでコピーするようにすると、フォルダが存在しない場合はエラーとなる。
PS D:\SandBox> Copy-Item .\from\* .\to\ -Recurse -Force -PassThru Copy-Item : ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。 発生場所 行:1 文字:1 + Copy-Item .\from\* .\to\ -Recurse -Force -PassThru + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Copy-Item], IOException + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.CopyItemCommand PS D:\SandBox> md .\to\ ディレクトリ: D:\SandBox Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2016/09/19 15:46 to PS D:\SandBox> ls ディレクトリ: D:\SandBox Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2016/09/19 15:31 from d----- 2016/09/19 15:46 to PS D:\SandBox> Copy-Item .\from\* .\to\ -Recurse -Force -PassThru ディレクトリ: D:\SandBox\to Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2016/09/19 15:31 14 test1.txt -a---- 2016/09/19 15:31 14 test2.txt PS D:\SandBox> tree /f D:\SandBox フォルダー パスの一覧 ボリューム シリアル番号は 4641-823A です D:\SANDBOX ├─from │ test1.txt │ test2.txt │ └─to test1.txt test2.txt
ディレクトリコピーするときはPowershellを使わないほうが良いと思う(2016/09/19時点)。 なお、このあたりの詳細な挙動については、Copy-Item -Recurse の振舞が詳しい