2011年9月13日火曜日

◆ActiveDirectory、無効のアカウントをフィルターする

Search-ADAccountコマンドレットのAccountDisabledパラメータを使えば無効でないアカウントを取得することは可能だが、既に取得済みのユーザーに対してフィルターしたいこともある。

有効、無効を判定する属性はuserAccountControl属性として以下のように保持しているようだ。
image

最下位2ビット目がそれっぽいのでフィルターすると以下のようになる。

001
002
003

Get-ADGroupMember "Domain Users"| 
Get-ADUser -prop name,userAccountControl | 
?{!(($_.userAccountControl -band 0x00002) -eq 0x00002)}

ちなみに、PowerShell: ◆ActiveDirectoryグループごとのメンバー一覧を表示する2で使ったPowerQuestの拡張コマンドを使うと以下のように簡単にフィルターできる。

001
Get-QADGroupMember "Domain Users"| ?{!$_.AccountIsDisabled}

ただし、拡張コマンドは全般的に機能が豊富な分若干重い感じがするのでケースバイケースで使い分けが必要かもしれない。

--

あれ、単純にEnabledプロパティを使えばよいだけ?(汗)

2011年9月9日金曜日

◆PowershellでSharePointサイトのクロール処理を実行する

SharePointのプロキシー設定がメタメタで、色々と調査するのに何度も手動クロールする必要があったため、Powershellスクリプトを作ってみた。
特に、IEのプロキシー設定を変える必要があり、SharePointの管理サイトにつながらない環境でテストするには必須になる。

001
002
003
004
005
006
007
008
009
010
011
012

$sApp = Get-SPEnterpriseSearchServiceApplication "Search Service Application"
$cSource = Get-SPEnterpriseSearchCrawlContentSource
 `
 
-Identity "ローカルの SharePoint サイト" -SearchApplication 
$sApp
$cSource
.StartFullCrawl()
cls
Write-Host
 "■クロールスタート"
Do
{
 
Start-Sleep 3
  Write-Host "*" -NoNewline
}
until($cSource.CrawlStatus -eq "Idle")
$cSource | fl *
<!--E

まずは1行目でサーチサービスアプリケーションのインスタンスを取得。
そのインスタンスを使って2行目でコンテンツソースを取得。
あとは取得したコンテンツソースのStartFullCrawlメソッドを呼んでやるだけ。
終了イベントはなさげだったのでループして監視。
結果はコンテンツソースオブジェクトから取得できる。

この例では一つのソースだけを使っているが、複数のソースを纏めてクロールするには、2行目でIdentityパラメータを省略するとソース全部が返ってくるので、それをループしてやれば良さそうだ。

◆FileのTemporary属性をクリアする

エクスプローラーでファイルを検索していてなぜかヒットしないファイルが有ることに気がついた。

例えば、以下のような状態で検索ボックスに「Audi.jpg」と入れてもヒットしないのだ。
image

結果、
image

最初はWindowsの検索機能の不具合か、検索設定が何かしらあるのかと色々と調べたが、どうもファイル自体に問題があるような感じ。

プロパティを見ると、セキュリティブロックがかかっていた。
image

なんだ、これかと思ったのだが、こいつを解除しても状況は変わらず・・・。

しかし、ブロックされていたということはインターネットからダウンロードしたりメール添付されて着たファイルと思われる。
やはり何か特別な状態に成っている可能性大。
ファイル属性を他のファイルと比較してみると「Temporary」という属性が付けられている。
image

どうやらこいつが犯人っぽい。
このTemporary属性が付いているとファイルサーバーのレプリケートの対象などからも外れるらしい。
いったい誰がこんな属性を付けたのかと思えばなんとサードパーティではなくOUTLOOK君。
相変わらず「いけてない」

まぁ、文句を言っても仕方が無いのでこのTemporary属性を削除してみる。
Archive等の属性であればSet-ItemPropertyとかで設定できるっぽいのだが、
13.ファイルの属性を設定する < ファイル操作 Tips メニュー < PowerShell Tips < HIRO's.NET
Temporary属性はこいつでは設定できないようだ。
以下のようにフラグを直接操作してあげる必要がありそう。

001
002

$tFile = Get-Item w:\test\Audi.jpg 
$tFile.attributes = ($tFile.attributes -band 0xFEFF)

フラグの詳細は以下を参照。

ファイルを纏めて操作するときはこんな感じで。

001
002
003
004
005

Get-childitem w:\test -recurse | 
%{if (($_.attributes -band 0x100) -eq 0x100
) {
        
$_.attributes = ($_.attributes -band 0xFEFF)
      }
 }

2011年9月6日火曜日

◆C#からPowershellコマンドレットを使う

まずはPowershell用のdll(System.Management.Automation)を参照設定。
このdllは通常、
C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0
にある。

あとはスクリプトを文字列で定義してRunspaceInvokeクラスのInvokeメソッドに渡してやるだけだ。
結果はCollection<PSObject>で返ってくるのでPSObjectを実際の型にキャストしてあげればOK。
目的にもよるのだろうが、単一値の取得などであればPowershellの方で文字列まで変換して返したほうが簡単な気がする。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Collections.ObjectModel;
using System.Diagnostics;

namespace ConsoleApplication6
{
    class Program
    {
        static void Main(string[] args)
        {
//            string script = @"Write-Output 'Start ----'
//                              ps | %{$_.name}";
            string script = @"ipmo ActiveDirectory
                              Get-ADUser test | %{$_.name}";

            RunspaceInvoke ivk = new RunspaceInvoke();
            Collection<PSObject> psList = ivk.Invoke(script);
            foreach (var pso in psList)
            {
                //string st = pso.BaseObject.ToString();
                string st = pso.ToString();

                Console.WriteLine("TestUserName:{0}",st );
            }

            Console.Write("Enter eny key");
            Console.ReadLine();
        }
    }
}

image

2011年9月1日木曜日

◆Hyper-Vの仮想マシンをバックアップする

仮想マシンをシャットダウンして、バックアップして、再び起動するというスクリプトを作ってみた。

標準ではPowershellからVMを操作するコマンドはなぜか用意されていない。
そこで、PowershellからVMを操作するにはWMIを使用するか、CodePlexで提供されているツールを使うか、システムセンターを使うかなのだそうだ。
ここらへんの話は以下の記事で詳しく解説してある。
【ハウツー】【管理効率化への挑戦】PowerShellで仮想環境も管理!! Hyper-V、SCとの連携 (1) Hyper-Vマネージャの問題点 | エンタープライズ | マイコミジャーナル

今回はバリバリ仮想マシンを操作するわけではないので、追加モジュールの必要ないWMIを使うことにした。

function main
{
    $ErrorActionPreference = "STOP"

    $VMName = "GSG-SVV2"
    $VMQuery = "SELECT * FROM Msvm_ComputerSystem WHERE ElementName='$($VMName)'"
    $VMObj = gwmi -Query $VMQuery -Namespace "root\virtualization" -Computername "."
   
    Write-Output "■仮想マシン($($VMName))バックアップ開始:$(Get-Date)▼▼▼▼▼▼▼▼"
    if($VMObj.EnabledState -eq 2)
    {
        shutdown-vm
        Start-Sleep 300
    }
    bkupcopy
    startup-vm
    Write-Output "■仮想マシン($($VMName))バックアップ終了:$(Get-Date)▼▼▼▼▼▼▼▼"
   
    trap{
      Send-MailMessage    -To "<vmuser@hoge.co.jp>"                     `
                    -From "VMServer <admin@hoge.co.jp>"            `
                    -Subject "VM Bkup Error"                     `
                    -SmtpServer "smtp.hoge.co.jp"                             `
                    -Body "仮想マシン($($VMName))バックアップエラー" `
                    -Encoding  ([System.Text.Encoding]::Default)
    }   
}

function shutdown-vm
{

    $STDObjQuery = "SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='$($VMObj.name)'"

    $STDObj = gwmi -Query $STDObjQuery -Namespace "root\virtualization" -Computername "."
    $Result = $STDObj.InitiateShutdown($true,"バックアップ")
}


function bkupcopy
{
    $gen = [Math]::Floor(((Get-Date).DayOfYear/7))%3 + 1
    $bkupPath = "E:\仮想マシンバックアップ\gen$gen"
    if(Test-Path $bkupPath){cmd /C "rmdir /S /Q $bkupPath"}
    copy (Join-Path "D:\VM" $VMName) $bkupPath -force -Recurse
}

function startup-vm
{
    $VMObj.RequestStateChange(2)
}

. main >> c:\log\仮想マシンバックアップ.log 2>&1

毎週末に実行し、3世代管理することとした。(年初からの日数で週数を求めて世代としている)

コピーする前に前回のコピーをクリアしているのだが、PowershellのRemove-Itemを使うとなぜか上手く行かなかった。
どうも、非同期に動作して次行のCopyとぶつかるような動作をしてしまうのだ。
それで止む無くDOSコマンドを使ってクリアしている。

仮想マシンのステータスはこんな感じらしい。

Enabled (Turns the VM on) : 2
Disabled (Turns the VM off) : 3
Reboot (A hard reset of the VM) : 10
Reset (For future use) : 11
Paused (Pauses the VM) : 32768
Suspended (Saves the state of the VM) : 32769

起動時はこのステータスを2にしてあげれば良いのだが、シャットダウンは3にすれば良いというものでもないらしい。
(シャットダウンオブジェクトを取得してそのメソッドを呼び出している)

また、シャットダウンは非同期に動くようなのでとりあえずSleepを噛ませている。

◆SharePoint、サーバーファームをバックアップする

ファームのバックアップは、Backup-SPFarmコマンドレットを使う。

Backup-SPFarm -BackupMethod full `
  -Directory \\gsg-sv\ファームバックアップ -BackupThread 3 -ea Stop

BackupMethodでフルバックアップか差分バックアップかを指定。
Directoryがバックアップ先の場所。
BackupThreadはGUIで行うときのデフォルトが3だったので同じ値を指定。

バックアップのログを吐きつつエラーの時は管理者にメールするなんてのが普通のパターンだろうか。

& {
    trap{
    Send-MailMessage    -To "<spuser@hoge.co.jp>"                     `
                    -From "SharePoint <spadmin@hoge.co.jp>"            `
                    -Subject "SharePoint Farm Bkup Error"                     `
                    -SmtpServer "smtp.hoge.co.jp"                             `
                    -Body "SharePointファームバックアップエラー($(hostname))" `
                    -Encoding  ([System.Text.Encoding]::Default)

    }
    Add-PSSnapin Microsoft.SharePoint.PowerShell -ea 0
    Write-Output "■ファームバックアップ開始:$(Get-Date)▼▼▼▼▼▼▼▼"
    Backup-SPFarm -BackupMethod full `
      -Directory \\gsg-sv\ファームバックアップ -BackupThread 3 -ea Stop
    Write-Output "■ファームバックアップ終了:$(Get-Date)▲▲▲▲▲▲▲▲"
} >> c:\log\ファームバックアップ.log 2>&1

◆リダイレクト

リダイレクトはDOSコマンドと同様にリダイレクト演算子が使える。

dir  >  a.txt

エラー出力をリダイレクトする時はこんな感じ。

dir  hoge  2>  a.txt

標準出力とエラー出力を纏めてリダイレクトも出来る。

dir  c:\,hoge  >  a.txt  2>&1

複数のコマンドレットの結果を纏めてリダイレクトしたい時にそれぞれのコマンドレットにリダイレクト指定をするのはちょっと面倒。
関数などにまとめれば良いのだろうが、簡便的には以下のようにスクリプトブロックにしてしまえば纏めてリダイレクトできそうだ。

& {
    dir c:\
    dir hoge
} > a.txt 2>&1