読者です 読者をやめる 読者になる 読者になる

Powreshellでnetstatする

何も考えずにGet-NetTCPConnectionする

#外部の80番ポートに対する通信を表示する
Get-NetTCPConnection | where {$_.RemotePort -eq 80 }                                               

2016年を振り返る

今年も残業が多かった 仕事をして技術的に得られたことはあまりなく、会議や調整ばかりしていたなあ。

来年はもう少し頑張りたい。

Powershellでローカルユーザーを管理する(Microsoft.PowerShell.LocalAccounts)

昨日の「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連携の値も持ってこれる。

変更を加えたいなら

  • user(add|del|mod)
  • group(add|del|mod)

Powershellでループを書かずに指定回数処理を繰り返す

範囲演算子(..)とパイプ(|)でループ処理のようなことができる

普通にループで書くなら以下のようになる。

#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

何が起こっているのか

  • 範囲演算子で指定個数の整数が生成される
  • パイプで渡してforeach-object(=%)する際は、普通は渡したオブジェクト($_)に対して処理をする
  • が、あえてそれをしないことで渡したオブジェクトの数だけ処理を実行させる

参考

05.範囲演算子 < 演算子 Tips メニュー < PowerShell Tips < HIRO's.NET ⇒範囲演算子の簡単な説明

Powershellでプリンターの状態を取得する

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     

参考

PrintManagementモジュールについて
CIMについて
  • Windows用語集 - WMI:ITpro CIM(Common Information Model)はWIM(Windows Management Instrumentation)の一部で監視情報のデータ構造を標準化するための形式、と理解した。
Powershellをバージョン指定で実行する方法について

余談

いつもの通り、英語版も含めてPowershellのレファレンスはクソなので何とかしてほしい。 PrinterStatusが取りうる値の範囲ぐらい明記してほしい。

*1:正確には「Microsoft.Management.Infrastructure.CimInstance#ROOT/StandardCimv2/MSFT_Printer」

*2:取得したインスタンスのメンバーを確認すると「ScriptProperty System.Object PrinterStatus」とあるので、PrintManagementのみの独自拡張なのだと思う

Active Directory証明書サービス(ADCS)でDeltaCRLを無効化する際にちょっとだけ嵌った話

大したことはないのだけれど、備忘のためにメモ。

  • ADCSが停止かつDeltaCRLの有効期限が切れた状態で、DeltaCRLを無効化した。
  • その後ADCSを起動すると証明書が発行できなくなった。
  • 対策として、ADCSの停止⇒DeltaCRLを有効化して⇒ADCSを起動⇒DeltaCRLを無効化することで証明書が再度発行できるようになった。

環境

事象

  • DeltaCRLは有効期限切れ状態。
  • ADCSが停止した状態でmmcの証明機関スナップインを開く
  • 左のツリーから[失効した証明書]を右クリックしプロパティを開く
  • CRL公開のパラメーターで[DeltaCRLを公開する]のチェックをはずす
  • ADCS起動
  • certutil -CRL でCRLを更新
  • CSRファイルを利用して、[すべてのタスク]-[新しい要求の送信]を実行する

⇒証明書発行に失敗する。

 メッセージは「失効サーバーがオフラインのため、失効の関数は失効を確認できませんでした」

原因

事象としては以下と近い

証明書発行に失敗 | Always on the clock

DeltaCRLを利用しないよう設定変更しているので、実際にcertutil -CRLを実施してもCRLのみが更新され、DeltaCRLは更新されない。 しかし、実際には、内部でDeltaCRLが有効期限切れになっているといった情報を保持しているのだと思う*1。 そのため一度DeltaCRLの有効期限切れを解消してから再度DeltaCRLを無効化した。 そうすることで証明書は通常通り発行することができた。

*1:あくまで推測

Powershellでアナグラムの判定をする

技術面接で出された問題 - 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

関数として使えるものにするなら、以下のようなこともしなくてはならないけど、まあこんな感じで実装できそうだということの確認にはなった。

  • 引数で文字列を受けとれるようにする
  • 引数チェックする($nullチェックとか?)
  • 性能評価*2

*1:ソートはもう少しましなやり方があるような気もするのだけれど、”配列の比較”の実装に悩んでしまったので、ソートした後に文字列として連結して比較している。単純に-eqなどで比較すると同一オブジェクトかどうかを比較してしまうので

*2:ちょっと真面目に書いた方はおそらくO(n)にはなっていると思うけど。