Monday, March 31, 2008

この記事は2008/03/20にわんくまブログで書いたものです。

Windows Server 2008 の評価版がダウンロード可能になったことを受けて、Standardエディションをインストールしてみました。

デフォルトではPowerShellはインストールされていません。

今回はWindows Server 2008 ServerにPowerShellをインストールする手順を紹介します。

まずはWindows Server 2008のインストールが完了したらWindows Updateを実行し、必ず最新の状態にしてから進めてください。

ここから先はWindows Updateが完了したWindows Server 2008でのPowerShellのインストール手順です。

 

1)「初期構成タスク」を起動し、「このサーバーのカスタマイズ」から「機能の追加」をクリックします。

 

 

2)「機能の追加ウィザード」が表示されるので、一覧から「Windows PowerShell」にチェックを付け[次へ(N)]をクリックします。

3)あとはインストールが完了するのを待ちます

4)インストールが完了すると、[スタート]-[すべてのプログラム]-[Windows PowerShell 1.0] から Windows PowerShell を起動することができるようになります。

Monday, March 31, 2008 5:24:13 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/03/11にわんくまブログで書いたものです。

PowerShell を使用して一からXmlDocumentを作成する手順を紹介します。

Step1
はじめにXmlDocumentを作成します

PS C:\Work> $XmlDoc = New-Object System.Xml.XmlDocument
PS C:\Work> $XmlDoc.GetType()

Step2
XML宣言ノード を作成するにはXmlDeclaretionクラスを使用します。

PS C:\Work> [System.Xml.XmlDeclaration]$XmlDecl = $XmlDoc.CreateXmlDeclaration("1.0","UTF-8",$Null) 

Step3
ルート要素を追加する

PS C:\Work> $rootElement = $XmlDoc.CreateElement("personal_data")

Step4
子要素を追加する
まず、子要素を作成する

PS C:\Work> $zipElement = $XmlDoc.CreateElement("zip")

Step5
子要素の値を設定する

PS C:\Work> $zipValue = $xmlDoc.CreateTextNode("012-3456")
PS C:\Work> $zipElement.AppendChild($zipValue)

Step6
子要素をルート要素に追加する

PS C:\Work> $rootElement.AppendChild($zipElement)
#text
-----
012-3456 

Step7
必要な子要素分だけStep4~Step6を繰り返します。

Step8
ルート要素をDOMドキュメントに追加する

PS C:\Work> $xmlDoc.AppendChild($rootElement) 
zip
---
012-3456 

Step9
作成したドキュメントをファイルに保存する

PS C:\Work> $XmlDoc.Save("C:\Work\Test.xml")

PowerShellでXmlDocumentを作成したくなったら参考にしてください。

Monday, March 31, 2008 5:20:23 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/03/06にわんくまブログで書いたものです。

Encodingを指定してXMLファイルを作成する(PowerShell Tips) で紹介した方法で、文字列からXMLファイルを作成すると、インデントと改行がされないことをお伝えしました。

ということで、今回は前回の手順に+αすることで、改行とインデントがされるようにしてみたいと思います。

まずは前回の手順どおりにXmlTextWriterまで作成します。

PS C:\Work> $SaveFile = "C:\Work\UTF8.xml"
PS C:\Work> $Encoding = [System.Text.Encoding]::UTF8
PS C:\Work> $strXml = @"
>> <?xml version='1.0' encoding='utf-8' ?>
>> <personal_data>
>> <zip_code>012-3456</zip_code>
>> <address>1-1,Tokyo,Japan</address>
>> <name>HIRO</name>
>> </personal_data>
>> "@
>> PS C:\Work> $xmlDoc = [xml]$strXml PS C:\Work> $XmlWriter = New-Object System.Xml.XmlTextWriter($SaveFile, $Encoding)

で、今回のポイントはここからです

PS C:\Work> $XmlWriter.Formatting = [System.Xml.Formatting]::Indented
PS C:\Work> $XmlWriter.Indentation = 4

XmlTextWriter のFormattingプロパティに Indentedを指定することで、作成するXmlドキュメントでインデントがされるようになります。

また、XmlTextWriter の Indentation プロパティを使用することでインデント幅を指定することができます。

上記の場合はインデント幅は空白4つ分です。

あとは、ドキュメントを保存して、XmlTextWriterを閉じておしまいです。

PS C:\Work> $xmlDoc.Save($xmlWriter)
PS C:\Work> $XmlWriter.Close()

作成されたドキュメントは下記のように改行とインデントがされています。

<xml version='1.0' encoding='utf-8'?>
<personal_data>
    <zip_code>012-3456</zip_code>
    <address>1-1,Tokyo,Japan</address>
    <name>HIRO</name>
</personal_data>

Monday, March 31, 2008 5:05:53 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/03/05にわんくまブログで書いたものです。

インストールされているアプリの一覧を取得するにはWMIオブジェクトの win32_product を使用します。

Get-WmiObject win32_product

リモートコンピュータのインストール済みアプリ一覧の取得は -computerName パラメータを使用して

Get-WmiObject -computerName リモートコンピュータ名 win32_product 

とします。

ただし、 win32_productは Windows VistaとWindows 2003 Server にはありません。

正確にはWindows 2003 ServerはWMIプロバイダを追加することで使用できるようになるらしいです。

OSごとに、使用可能なWMIオブジェクトが異なるのは、進化していく上で必要なことなんでしょうが.....

んー、Vistaや2003 Serverでwin32_productに代わるものってなんでしょう?

Monday, March 31, 2008 5:02:51 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/03/04にわんくまブログで書いたものです

文字列からXmlDocumentを作成する(PowerShell Tips)

での Xmlファイルの作成はEncodingの指定をせずに保存しました。

今回はEncodingを指定して、保存する方法を紹介します。

 

まずは保存先ファイル名とEncodingを変数に代入します。

PS C:\Work> $SaveFile = "C:\Work\UTF8.xml"
PS C:\Work> $Encoding = [System.Text.Encoding]::UTF8

次に、前回同様ヒア文字列を使用してXML文字列を作成

PS C:\Work> $strXml = @"
>> <?xml version='1.0' encoding='utf-8' ?>
>> <personal_data>
>> <zip_code>012-3456</zip_code>
>> <address>1-1,Tokyo,Japan</address>
>> <name>HIRO</name>
>> </personal_data>
>> "@
>>

で、これをXmlDocument型にキャストしておきます。

PS C:\Work> $xmlDoc = [xml]$strXml

で、前回はここで$XmlDoc.Save()メソッドを実行したのですが、ここでXmlTextWriterを作成します。

こうすることでEncodingを指定できます。

PS C:\Work> $XmlWriter = New-Object System.Xml.XmlTextWriter($SaveFile, $Encoding)

で、保存して、XmlTextWriterを閉じます。

PS C:\Work> $xmlDoc.Save($xmlWriter)
PS C:\Work> $xmlWriter.Close()

実際にファイルを開いてみると、utf-8で有ることが確認できます。(下図はサクラエディタで開いたものです)

 

 

最後に、上記を応用して、Shift_Jisで保存してみたいと思います。

PS C:\Work> $SaveFile = " ps c:\Work\Shift_Jis.xml? c:\Work>$encoding = [System.Text.Encoding]::GetEncoding("Shift_Jis")
PS C:\Work> $xmlDoc = [xml]$strXml
PS C:\Work> $XmlWriter = New-Object System.Xml.XmlTextWriter($SaveFile, $Encoding)
PS C:\Work> $xmlDoc.Save($xmlWriter)
PS C:\Work> $xmlWriter.Close()

作成したXmlファイルはShift_Jisであることが確認できます。

 

注意事項が2点あります。

1つ目はEncodingです。

UTF8のときと違って、Shift_Jistは

$encoding = [System.Text.Encoding]::Shift_Jis

とすることができません。

GetEncodingメソッドを使用して

[System.Text.Encoding]::GetEncoding("Shift_Jis")

とする必要があります。

2つ目は、Xmlファイルが改行されずに1行になってしまっていることです。

前回の方法で保存したものは改行および自動インデントがされました)

これについては、次回以降で説明したいと思います。

Monday, March 31, 2008 4:46:49 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/03/03にわんくまブログで書いたものです。

指定した年月のカレンダーを表示する の色つき版を作ってみました。

実行結果は下記の下段のほうです。

下図の上段のほうは、前回の実行結果です。

 

以下ソース

Get-Calendar2.ps1

#===============================================================================
# Get-Calendar2: 指定した年月のカレンダーを表示する(色つき版)
#
# パラメータ:
#       $Year: 年(省略した場合は現在の年)
#      $Month: 月(省略した場合は現在の月)
#
# 使用例1(年月指定)
#   PS > Get-Calendar2 2008 2
#
# 使用例2(年月省略)
#   PS > Get-Calendar
#
# copyright HIRO's.NET(http://hiros-dot.net//)
#===============================================================================
function global:Get-Calendar2
{
  Param ([int]$Year = $(Get-Date).Year, [int]$Month =  $(Get-Date).Month)
  
  #表示用年月作成
  $DispMonth = New-Object DateTime($Year, $Month, 1)
  $strDispMonth = ($DispMonth.ToString("MMMM",[System.Globalization.CultureInfo]'en-US') + " " + $Year)
  #横幅35文字の中間に表示されるようにする
  Write-Host ""
  Write-Host $strDispMonth.PadLeft([int](35 - (35 - $strDispMonth.Length) / 2))
  
  $firstSunday = Get-FirstSunday $Year $Month
  $lastDay = Get-LastDay $Year $Month
  Write-Host "Sun." -foregroundcolor Red -noNewline
  Write-Host " Mon. Tue. Wed. Thu. Fri. " -noNewline
  Write-Host "Sat." -foregroundcolor Cyan
  
  # 第1日曜日が"1日"以外の第1週を表示
  if ( $firstSunday -ne 1 )
  {
    for ( $i = 1; $i -lt $firstSunday - 1; $i++ )
    {
      $week += $i.ToString("  #  ")
    }
    $spc = "     "
    $spc *= [int](7 - ( $firstSunday - 1 ))
    Write-Host ($spc + $week) -noNewline
    #土曜日をCyanにする
    Write-Host ($firstSunday - 1).ToString("  #  ") -foregroundcolor Cyan
  }
  
  #中間週を表示
  $loopWeek = [Math]::floor(($LastDay - $firstSunday) / 7)
  $Day = $firstSunday
  for ( $weekCnt = 0; $weekCnt -lt $loopWeek; $weekCnt++ )
  {
    for ( $iDay = 0; $iDay -lt 7; $iDay++ )
    {
      if ( $Day -lt 10 ) { $strDay = $Day.ToString("  #  ") }
      else               { $strDay = $Day.ToString(" ##  ") }
      
      #日曜日はRed, 土曜日はCyanにする
      if ($iDay -eq 0 )     { Write-Host $strDay -foregroundcolor Red -noNewline }
      elseif ($iDay -eq 6 ) { Write-Host $strDay -foregroundcolor Cyan}
      else                  { Write-Host $strDay -noNewline }
      $Day += 1
    }
    #Write-Host ($week)
  }
  
  #最終週を表示
  if ( $Day -le $LastDay )
  {
    $week = ""
    $LastSunday = $Day
    $Day += 1
    for ( $iDay = $Day; $iDay -le $LastDay - 1; $iDay++ )
    {
      $week += $Day.ToString(" ##  ")
      $Day += 1
    }
    
    #最終週の日曜日の色をRedにする
    Write-Host $LastSunday.ToString(" ##  ") -foregroundcolor Red -noNewline
    Write-Host $week -noNewline
    
    #最終日が土曜日の場合は色をCyanにする
    if ($LastDay - $LastSunday -eq 6) { Write-Host $LastDay.ToString(" ##  ") -foregroundcolor Cyan }
    else                              { Write-Host $LastDay.ToString(" ##  ") }
  }
}

 

ポイントは

Write-Hostコマンドレットで色を付けているということです。

前景色(文字色)はパラメータ -foregroundcolor で指定することができます。

指定可能な色は

  • Black
  • DarkBlue
  • DarkGreen
  • DarkCyan
  • DarkRed
  • DarkMagenta
  • DarkYellow
  • Gray
  • DarkGray
  • Blue
  • Green
  • Cyan
  • Red
  • Magenta
  • Yellow
  • White

です。

あとは むたぐちさんに Write-Hostコマンドレットは、-noNewlineパラメータを使用すれば改行しないで文字を出力できることを教えていただきましたので、それを使用しました。

Monday, March 31, 2008 4:35:58 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/03/03にわんくまブログで書いたものです。

今回は文字列からXmlDocumentを作成して、ファイルに保存する方法を紹介します。

まずは、以下のようにしてXML文字列を作成します。

PowerShellでは複数行にわたる文字列は ヒア文字列を使用することであらわすことができます。

ヒア文字列は@" ~ "@ で表します。

PS C:\Work> $strXml = @"
>> <?xml version='1.0' ?>
>> <personal_data>
>> <zipcode>012-3456</zipcode>
>> <address>1-1, Tokyo, Japan</address>
>> <name>HIRO</name>
>> </personal_data>
>> "@
>>

 

どのような文字列が代入されたのかを確認してみると

PS C:\Work> $strXML

<?xml version='1.0' ?>
<personal_data>
<zipcode>012-3456</zipcode>
<address>1-1, Tokyo, Japan</address>
<name>HIRO</name>
</personal_data>

きちんと改行されて代入されていることがわかります

次にこの文字列をXmlDocument型にキャストします。

PS C:\Work> $xmlDoc = [xml]$strXml

最後に、ファイルへ出力する方法ですが、Saveメソッドを使用して下記のように記述します。

PS C:\Work> $xmlDoc.Save("C:\Work\Test.xml")

で、ファイルに出力できたら、メモ帳などで内容を確認してみてください。

下記のようになっているかと思います。

Test.xml

<?xml version="1.0"?>
<personal_data>
  <zipcode>012-3456</zipcode>
  <address>1-1, Tokyo, Japan</address>
  <name>HIRO</name>
</personal_data>

インデントまで自動でしてくれます。

すばらしいですね。

Monday, March 31, 2008 4:11:51 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/03/03にわんくまブログで書いたものです。

今週は、PowerShellでのXMLの取り扱いについてまとめていこうかと思います。

まずはXMLファイルの読み込みから。

VB.NETだとXmlDocumentは

Dim xmlDoc As New System.Xml.XmlDocument
xmlDoc.Load("C:\Work\Test.xml")

みたいに記述します。

 

PowerShellでは

[xml]$doc = Get-Content "C:\Work\Test.xml"

と書くと、変数$docにXMLファイルが読み込まれます。

これで読み込むことができるのですが、エンコーディングはきちんと指定することをお勧めします。

エンコーディングを指定する場合は、-encodingパラメータを使用します。

-encodingパラメータには、

  • Unicode
  • UTF7
  • UTF8
  • UTF32
  • ASCII
  • BigEndianUnicode
  • Default
  • OEM

を指定することができます。

UTF8で読み込む場合は

[xml]$doc = Get-Content "C:\Work\Test.xml" -encoding UTF8

のように記述します。

で、[xml]でキャストした$docのデータ型はどうなっているかというと(GetType()メソッドで確認)

PS C:\Work> $doc.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    XmlDocument                              System.Xml.XmlNode

XmlDocumentとなっていることが確認できます。

で、使用可能なメンバーは(Get-Memberコマンドレットで確認)

PS C:\Work> $doc | Get-Member


   TypeName: System.Xml.XmlDocument

Name                        MemberType            Definition
----                        ----------            ----------
ToString                    CodeMethod            static System.String XmlNode(PSObject instance)
add_NodeChanged             Method                System.Void add_NodeChanged(XmlNodeChangedEventHandler value)
add_NodeChanging            Method                System.Void add_NodeChanging(XmlNodeChangedEventHandler value)
add_NodeInserted            Method                System.Void add_NodeInserted(XmlNodeChangedEventHandler value)
add_NodeInserting           Method                System.Void add_NodeInserting(XmlNodeChangedEventHandler value)
add_NodeRemoved             Method                System.Void add_NodeRemoved(XmlNodeChangedEventHandler value)
add_NodeRemoving            Method                System.Void add_NodeRemoving(XmlNodeChangedEventHandler value)
AppendChild                 Method                System.Xml.XmlNode AppendChild(XmlNode newChild)
Clone                       Method                System.Xml.XmlNode Clone()
CloneNode                   Method                System.Xml.XmlNode CloneNode(Boolean deep)
:
たくさんあるので省略
:

このようにPowerShellでは簡単にXMLを取り扱うことが可能です。

Monday, March 31, 2008 4:09:19 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/02/22にわんくまブログで書いたものです。

前回はキャラクタベースのカレンダー表示を紹介しました。

今回は、GUI版を作成したので紹介します。

 

実行イメージは下記の通りです。

 

 

View-Calendar.ps1

[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
#===============================================================================
# View-Calendar: 指定した年月のカレンダーを表示する(GUI版)
#
# パラメータ:
#       $Year: 年(省略した場合は現在の年)
#      $Month: 月(省略した場合は現在の月)
#
# 使用例1(年月指定)
#   PS > View-Calendar 2008 2
#
# 使用例2(年月省略)
#   PS > View-Calendar
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:View-Calendar
{
  Param ([int]$Year = $(Get-Date).Year, [int]$Month =  $(Get-Date).Month)
  
  #===== Formの作成 =====
  $form = New-Object System.Windows.Forms.Form
  $form.Text = "Calendar"
  $form.Width = 147
  $form.Height = 210
  $form.FormBorderStyle = [Windows.Forms.FormBorderStyle]::FixedToolWindow

  #===== MonthCalendarの作成 =====
  $cal = New-Object System.Windows.Forms.MonthCalendar
  $cal.Dock = [System.Windows.Forms.DockStyle]::Fill
  $cal.SelectionStart = New-Object DateTime($Year, $Month, 1)
  $cal.SelectionEnd = New-Object DateTime($Year, $Month, 1)
  $form.Controls.Add($cal)
  
  #===== Panelの作成 =====
  $panel1 = New-Object System.Windows.Forms.Panel
  $form.Controls.Add($panel1)
  $panel1.Dock = [System.Windows.Forms.DockStyle]::Bottom
  $panel1.Height = 30

  #===== [閉じる]ボタンの作成 =====
  $btnClose = New-Object System.Windows.Forms.Button
  $btnClose.Location = New-Object System.Drawing.Point(61, 4)
  $btnClose.Text = "閉じる"
  $btnClose.anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Right
  $btnClose.Add_Click({$form.Close()})
  $panel1.Controls.Add($btnClose)
  
  [void]$form.ShowDialog()
}

ポイント

見てのとおり、今回はMonthCalendarコントロールを使用しました。

MonthCalendarコントロールは、日にちをマウスで選択可能なので、フォームが閉じられる時に選択されている日を返すようにしてもよいかもしれませんね。

その場合は

[閉じる]ボタンが押される時の処理を

$btnClose.Add_Click({$form.Close()})

から

$btnClose.Add_Click({$form.DialogResult = "OK"; $form.Close()})

として、フォームのShowDialog()を

if ( $form.ShowDialog() -eq "OK" )
{
  retrurn $cal.SelectionStart.ToString()
}

とすればよいと思います。

Monday, March 31, 2008 4:00:06 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/02/21にわんくまブログで書いたものです。

PowerShellでは、カレンダーを表示するコマンドレットがないので自作してみました。

紹介する関数(Get-Calendar)は

指定した年月の最終日を取得する(PowerShell Tips)

指定した年月の第1日曜日を取得する(PowerShell Tips)

が必要です。

実行イメージは下記のとおり

Get-Calendar.ps1

#===============================================================================
# Get-Calendar: 指定した年月のカレンダーを表示する
#
# パラメータ:
#       $Year: 年(省略した場合は現在の年)
#      $Month: 月(省略した場合は現在の月)
#
# 使用例1(年月指定)
#   PS > Get-Calendar 2008 2
#
# 使用例2(年月省略)
#   PS > Get-Calendar
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:Get-Calendar
{
  Param ([int]$Year = $(Get-Date).Year, [int]$Month =  $(Get-Date).Month)
  
  #表示用年月作成
  $DispMonth = New-Object DateTime($Year, $Month, 1)
  $strDispMonth = ($DispMonth.ToString("MMMM",[System.Globalization.CultureInfo]'en-US') + " " + $Year)
  #横幅35文字の中間に表示されるようにする
  Write-Host ""
  Write-Host $strDispMonth.PadLeft([int](35 - (35 - $strDispMonth.Length) / 2))
  
  $firstSunday = Get-FirstSunday $Year $Month
  $lastDay = Get-LastDay $Year $Month
  Write-Host "Sun. Mon. Tue. Wed. Thu. Fri. Sat."
  
  # 第1日曜日が"1日"以外の第1週を表示
  if ( $firstSunday -ne 1 )
  {
    for ( $i = 1; $i -lt $firstSunday; $i++ )
    {
      $week += $i.ToString("  #  ");
    }
    $spc = "     "
    $spc *= [int](7 - ( $firstSunday - 1 ))
    Write-Host ($spc + $week)
  }
  
  #中間週を表示
  $loopWeek = [Math]::floor(($LastDay - $firstSunday) / 7)
  $Day = $firstSunday
  for ( $weekCnt = 0; $weekCnt -lt $loopWeek; $weekCnt++ )
  {
    $week = "";
    for ( $iDay = 0; $iDay -lt 7; $iDay++ )
    {
      if ( $Day -lt 10 ) { $week += $Day.ToString("  #  "); }
      else               { $week += $Day.ToString(" ##  "); }
      $Day += 1
    }
    Write-Host ($week)
  }
  
  #最終週を表示
  if ( $Day -le $LastDay )
  {
    $week = ""
    for ( $iDay = $Day; $iDay -le $LastDay; $iDay++ )
    {
      $week += $Day.ToString(" ##  ");
      $Day += 1
    }
    Write-Host ($week)
  }
}

 

ポイント

1.タイトル(年月)の表示

 「月」を英語で表示したかったので、ToString("MMMM")としましたが、”2月”と返ってくるので

  ToString("MMMM",[System.Globalization.CultureInfo]'en-US') として英語で取得しています。

 

 カレンダーを表示するのに必要な幅は35文字としています。

 これは1日を5文字使用して表示しているので、× 7日 = 35文字となっています。

 でタイトルは中心に表示したいので、計算して左側にスペースを入れています。(PadLeftメソッド)

 

2.カレンダーの表示

  表示は第1週、中間週、最終週の3つに分けて行っています。

  これは、第1週が必ずしも日曜日から始まるとは限らないこと、最終週が必ずしも土曜日で終わるとは限らないことを考慮したためです。

 

もうちょっとスマートに書けると良いんですが、これくらいの技量しかないので...

アドバイス等ありましたら、よろしくお願いします。

Monday, March 31, 2008 3:47:30 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/02/21にわんくまブログで書いたものです。

指定した年月の最終日を取得する関数を作成してみました。

Get-LastDay.ps1

#===============================================================================
# Get-LastDay: 指定した年月の最終日を取得する
#
# パラメータ:
#       $Year: 年(省略した場合は現在の年)
#      $Month: 月(省略した場合は現在の月)
#
# 使用例1(年月指定)
#   PS > Get-LastDay 2008 2
#
# 使用例2(年月省略)
#   PS > Get-LastDay
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:Get-LastDay
{
  Param ([int]$Year = $(Get-Date).Year, [int]$Month =  $(Get-Date).Month)
  return [System.DateTime]::DaysInMonth($Year, $Month)
}

 

関数本体よりコメントのほうが長い....

 

ポイント

DateTime構造体のDaysInMonthは、指定した年月が持つ日数を返します。

それをreturnしているだけです...

 

補足

パラメータを省略した場合は、当月の最終日を返します。

Monday, March 31, 2008 3:44:18 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/02/21にわんくまブログで書いたものです。

指定した年月の第1日曜日を取得する関数を作ってみました。

 

Get-FirstSunday.ps1

#===============================================================================
# Get-FirstSunday: 指定した年月の第1日曜日を取得する
#
# パラメータ:
#       $Year: 年(省略した場合は現在の年)
#      $Month: 月(省略した場合は現在の月)
#
# 使用例1(年月指定)
#   PS > Get-FirstSunday 2008 2
#
# 使用例2(年月省略)
#   PS > Get-FirstSunday
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:Get-FirstSunday
{
  Param ([int]$Year = $(Get-Date).Year, [int]$Month =  $(Get-Date).Month)
  for ( $i = 0; $i -lt 7; $i++ )
  {
    $checkDay = New-Object DateTime($Year, $Month, [int]($i + 1))
    if ( $checkDay.DayOfWeek -eq 0 )
    {
      break
    }
  }
  return $i + 1
}

 

ポイント

なんのことはありません。

DateTime構造体のDayOfWeekメソッドを使用し、指定した年月の1~7までのどれが日曜日かを判定して返します。

 

補足

この関数は、パラメータ年、月を省略した場合は当月の第1日曜日を返すようにしてあります。

Monday, March 31, 2008 3:40:28 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/02/19にわんくまブログで書いたものです。

今日は、PowerShellでホスト名とIPアドレスを相互変換する関数を作ってみました。

まずはIPアドレスからホスト名を取得する関数です

Get-HostByName.ps1

#===============================================================================
# Get-HostByName: IPアドレスからホスト名を取得する
#
# 使用例
#   PS > Get-HostByName 10.84.5.10
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
[void][reflection.assembly]::LoadWithPartialName("System.Net")
function global:Get-HostByName
{
  Param ([string]$IPAddress)
  
  $hostEntry = New-Object System.Net.IPHostEntry
  $hostEntry = [System.Net.Dns]::GetHostEntry($IPAddress)
  
  return $hostEntry.HostName
}

 

ポイント

IPアドレスからホスト名を取得するのに、System.Net.DnsのGetHostEntryメソッドを使用しています。

HostEntry情報を取得したら、その中のHostNameプロパティを参照し、ホスト名を取得します。

 

次にホスト名からIPアドレスを取得する関数です。

Get-HostByAddress.ps1

#===============================================================================
# Get-HostByAddress: ホスト名からIPアドレスを取得する
#
# 使用例
#   PS > Get-HostByAddress "www.yahoo.co.jp"
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
[void][reflection.assembly]::LoadWithPartialName("System.Net")
function global:Get-HostByAddress
{
  Param ([string]$HostName)
  
  $hostEntry = New-Object System.Net.IPHostEntry
  $hostEntry = [System.Net.Dns]::GetHostEntry($HostName)
  
  return $hostEntry.AddressList[0].IPAddressToString
}

 

ポイント

こちらもSystem.Net.DnsのGetHostEntryメソッドを使用しています。

HostEntry情報を取得したら、その中のAddressList(配列で返されます)を取得し、IPAddressToString でIPアドレスのみを取得しています。

Monday, March 31, 2008 3:37:08 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/02/17にわんくまブログで書いたものです。

ちょっと前に、PowerShellで作ったタイピング練習用ソフトを紹介します。

 

このタイピングソフトは、CNNの記事をダウンロードしてきて、その記事から1単語ずつ画面に表示し、ユーザーにその通り入力してもらうというものです。

タイピング速度の速い人は、CNNの最新記事(英語)をちょろっと読めてしまう、一石二鳥のソフトとなっています。

制限時間は60秒1本勝負で(実際には正確に60秒にすることはできませんでした。後述します)、記事カテゴリを選択できるようにしてあります。

 

#===============================================================================
# Typing: CNNの記事(RSS)を利用してタイピング練習する
#
# パラメータ
#        なし
# 使用例
#   PS > Typing
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:Typing
{
  #===============================================
  # 初期化処理
  #===============================================
  #背景色を保存
  $bgclr = $host.UI.RawUI.BackgroundColor
  
  #前景色を保存
  $fgclr = $host.UI.RawUI.ForegroundColor
  
  #問題の色を定義
  $questioncolor = [System.ConsoleColor]::Red

  $rss_list = @(
    @("Top Stories","http://rss.cnn.com/rss/cnn_topstories.rss"),
    @("World", "http://rss.cnn.com/rss/edition_world.rss"),
    @("Africa","http://rss.cnn.com/rss/edition_africa.rss"),
    @("Americas","http://rss.cnn.com/rss/edition_americas.rss"),
    @("Asia","http://rss.cnn.com/rss/edition_asia.rss"),
    @("Europe","http://rss.cnn.com/rss/edition_europe.rss"),
    @("Middle East","http://rss.cnn.com/rss/edition_meast.rss"),
    @("U.S.","http://rss.cnn.com/rss/edition_us.rss"),
    @("World Business","http://rss.cnn.com/rss/edition_business.rss"),
    @("Technology","http://rss.cnn.com/rss/edition_technology.rss"),
    @("Science & Space","http://rss.cnn.com/rss/edition_space.rss"),
    @("Entertainment","http://rss.cnn.com/rss/edition_entertainment.rss"),
    @("World Sport","http://rss.cnn.com/rss/edition_sport.rss"),
    @("Football","http://rss.cnn.com/rss/edition_football.rss"),
    @("Travel","http://rss.cnn.com/rss/edition_travel.rss"),
    @("Video","http://rss.cnn.com/rss/cnn_freevideo.rss"),
    @("Most Recent","http://rss.cnn.com/rss/cnn_latest.rss"),
    @("Art of Life Blog","http://rss.cnn.com/rss/edition_artoflife.rss"),
    @("Business Traveller Blog","http://rss.cnn.com/rss/edition_richardquest.rss"),
    @("In the Field Blog","http://rss.cnn.com/rss/edition_inthefield.rss"),
    @("World's Untold Stories Blog","http://rss.cnn.com/rss/edition_untoldstories.rss"),
    @("The Screening Room Blog","http://rss.cnn.com/rss/edition_screeningroom.rss"),
    @("Marketplace Middle East Blog","http://rss.cnn.com/rss/edition_mme.rss"),
    @("Inside the Middle East Blog","http://rss.cnn.com/rss/edition_ime.rss")
  )
  
  Write-Host "タイピング練習の問題カテゴリーを選択してください"
  for ( $icnt = 0; $icnt -lt $rss_list.Length; $icnt++)
  {
    Write-Host $($($icnt + 1).ToString("0#") + ": " + $rss_list[$icnt][0])
  }
  
  #ユーザーが選択したカテゴリ番号を保存
  $no = Read-Host
  
  if ( $([int]$no) -le 0 -and $([int]$no) -gt  $rss_list.Length )
  {
    Write-Host "Noを正しく入力してね"
    return
  }
  Write-Host "データダウンロード中..."
  $feed = [xml](new-object system.net.webclient).downloadstring($rss_list[$no - 1][1])
  $contents =$($feed.rss.channel.item | Select-Object -property DESCRIPTION)
  Write-Host "データダウンロード完了"

  foreach ( $content in $contents )
  {
    $a += $content.Description.split(" ")
  }

  Write-Host "[Enter]キーを押すと始まります"
  Read-Host
   
  $start = Get-Date
  $i = 0
  $score = 0
  $miss = 0
    
  #背景色を黒にする
  $host.UI.RawUI.BackgroundColor = [System.ConsoleColor]::Black
  cls
    
  while ( $(Get-Date).subtract($start).TotalSeconds -lt 60)
  {
    #問題を出す
    if ( $a[$i] -ne " ")
    {
      Write-Host $a[$i] -foregroundcolor $questioncolor
      
      #ユーザーからの回答入力を取得する
      $Host.UI.RawUI.ForegroundColor = $fgclr
      $input = Read-Host
      
      cls
      
      #正解したらスコアをカウントアップ
      if ( $input -ceq $a[$i] )
      {
        $score += 10
      }
      else
      {
        $miss++;
        Write-Host "`a"
        cls
      }
    }
    $i++
    
    #問題がなくなったら終了
    if ($a.Length -eq $i )
    {
      break;
    }
  }

  Write-Host $("start: " + $start)
  Write-Host $("end: " + $(Get-Date))
  Write-Host $("Score: " + $Score)
  Write-Host $("Miss:" + $miss)
}
ポイント

1.背景色と前景色

  PowerShellのコンソールウィンドウの背景色や前景色は $host.UI.RawUI のBackgroundColor と ForegroundColor を指定することで変更できます。

  色はSystem.ConsoleColor列挙体を指定します。

2.問題の色

  出題する問題(単語)の色は Write-Hostコマンドレットの-foregroundcolor パラメータで指定しています。

3.カテゴリを選択させる

 カテゴリはあらかじめ変数として持っておくこととしました。($rss_list) このとき変数は2次元配列変数にし、カテゴリ名とRSSのURLをペアで持たせています。

  $rss_list[0][1]とするとURL http://rss.cnn.com/rss/cnn_topstories.rss が取り出せるという寸法です。

  で、ユーザーにカテゴリを入力させるわけですが、Read-Hostコマンドレットを使用することで入力を取得することができます。

4.rssのダウンロード

  rssのダウンロードはsystem.net.webclientのdownloadstringメソッドを使用しています。

  [xml](new-object system.net.webclient).downloadstring($rss_list[$no - 1][1])  の部分です。

  先頭に[xml]と付けることでxmlにキャストしています。

5.descriptionタグ内容の取り出し

  $contents =$($feed.rss.channel.item | Select-Object -property DESCRIPTION)

 で行っています。 Select-Object でDescriptionを取り出します。

6.制限時間

  whileでループして60秒経過したら終わるようにしています。

  while ( $(Get-Date).subtract($start).TotalSeconds -lt 60)

  {

  }

  ただし、このタイピングソフトは正確には60秒を計測することはできません。

 なぜなら、Whileの中でRead-Hostコマンドレットを使用しているからです。

  Read-Hostコマンドレットはユーザーが[Enter]を押すまで処理を止めてしまいます。よって60秒経過してもユーザーが何も入力しなければ、このループは1時間経過しようが止まらないのです。 だれか良い方法知っていたら教えてください。 Read-Keyみたいなコマンドレット作れば良いのかしら?

7.入力ミスをしたらBeepを鳴らす

  Beep音はWrite-Host "`a" と書けば鳴らすことができます。

 

ほんとは、もう少しコードをきれいにしてから載せるつもりでしたが...

Monday, March 31, 2008 3:32:23 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/02/08にわんくまブログで書いたものです。

New-TimeSpanコマンドレットを使用すると、時間計算をすることができます。

まずは、単純に10:00:00~12:00:00までの差分を計算してみます。

PS> New-TimeSpan -start 10:00:00 -end 12:00:00

とすると、実行結果は

Days              : 0
Hours             : 2
Minutes           : 0
Seconds           : 0
Milliseconds      : 0
Ticks             : 72000000000
TotalDays         : 0.0833333333333333
TotalHours        : 2
TotalMinutes      : 120
TotalSeconds      : 7200
TotalMilliseconds : 7200000
のようになります。

-endパラメータで指定した12:00:00から-startパラメータで指定した10:00:00までの差分を表示していることがわかります。

つぎに日付まで含めた場合の、時間計算ですが下記のようにします。

(これが意外にも方法はあります。)

PS> New-TimeSpan -start (Get-Date "2007/02/03 10:00:00") -end (Get-Date "2007/02/07 12:00:00")

実行結果は下記のとおりです。

Days              : 4
Hours             : 2
Minutes           : 0
Seconds           : 0
Milliseconds      : 0
Ticks             : 3528000000000
TotalDays         : 4.08333333333333
TotalHours        : 98
TotalMinutes      : 5880
TotalSeconds      : 352800
TotalMilliseconds : 352800000

 

このように、New-TimeSpanを使用することで、簡単に時間計算を行うことができます。

Monday, March 31, 2008 3:28:58 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/02/04にわんくまブログで書いたものです。

ネタ元:http://forums.microsoft.com/TechNet-JA/ShowPost.aspx?PostID=2784931&SiteID=36

PowerShellのInvoke-Itemコマンドレットは外部アプリを起動できるコマンドレットですが、引数を渡す方法がありません。(というか見つけられれていない?)

Google先生に聞いたりしても、なかなか良い返事が聞けません。

 

PS>Invoke-Item "c:\Program Files\Mozilla Firefox\firefox.exe"  http://blog.hiros-dot.net/

と書いてもエラーになります。

 

Set-Aliasコマンドレットで

PS> Set-Alias fox "c:\Program Files\Mozilla Firefox\firefox.exe"
PS> fox http://blogs.wankuma.com/hiro/

だと、引数渡せるんですけどね....

 

Invoke-Itemでやる方法はあるのかな......?

Monday, March 31, 2008 3:20:18 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/01/29にわんくまブログで書いたものです。

昨年、デジタル一眼レフを購入したのですが、それをきっかけに息子のスポ少(ミニバス)の写真を撮る機会が増えました。

チームメンバーの方から写真がほしいと言われるので、専用サイトへアップするのですが元画像のままだとサイズが大きすぎるし、枚数は多いしで大変なのです。

ということでリサイズする関数を作ってみました。(jpeg専用です)

[void][reflection.assembly]::LoadWithPartialName("System.Drawing")
[void][reflection.assembly]::LoadWithPartialName("System.Drawing.Imaging")

#===============================================================================
# Resize-Image: 画像ファイルをリサイズする(jpegのみ)
#
# パラメータ
# -srcFile : リサイズ元画像ファイルパス
# -dstFile : リサイズ後画像ファイルパス
# -width   : リサイズ後の幅
# -height  : リサイズ後の高さ
# -quality : 品質
#             Default 既定の補間モード 
#             Low 低品質補間 
#             High 高品質補間 
#             NearestNeighbor 最近傍補間 
#             Bilinear 双一次補間 
#             Bicubic 双三次補間 
#             HighQualityBilinear 高品質双一次補間 
#             HighQualityBicubic 高品質双三次補間 
# 使用例
#   PS > Resize-Image "C:\Work\AAA.jpg" "C:\Work\BBB.jpg" 600 480 "HighQualityBicubic"
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:Resize-Image
{
  Param([string]$srcFile, [string]$dstFile, [int]$width=0, [int]$height=0, [string]$quality="Default")

  #元画像ファイルの存在確認
  if ( (Test-Path $srcFile) -eq $False )
  {
    Write-Host "リサイズ元画像が存在しません。パスを確認してください!!"
    return
  }

  #元画像の読み込み
  $srcImg = New-Object System.Drawing.Bitmap($srcFile)
  
  $newWidth = 0
  $newHeight = 0
  #受け取った引数から、新しいサイズを決定する
  if ( $width -gt 0 -and $height -eq 0 )
  {
    $newWidth = $width
    $newHeight = $srcImg.Height / ($srcImg.Width / $newWidth)
  }
  elseif ( $height -gt 0 -and $width -eq 0 )
  {
    $newHeight = $height
    $newWidth = $srcImg.Width / ($srcImg.Height / $newHeight)
  }
  elseif ( $width -gt 0 -and $height -gt 0 )
  {
    $newWidth = $width
    $newHeight = $height
  }
  else
  {
    Write-Host "画像サイズを指定してください"
    return
  }
  
  $dstImg = New-Object System.Drawing.Bitmap($srcImg, $newWidth, $newHeight)
  $g = [System.Drawing.Graphics]::FromImage($dstImg)
  
  #画像品質の設定
  switch ($quality)
  {
    "Default" #既定の補間モード
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Default}
    "Low" #低品質補間 
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Low}
    "High" #高品質補間
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::High}
    "NearestNeighbor" #最近傍補間
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::NearestNeighbor}
    "Bilinear" #双一次補間 
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Bilinear}
    "Bicubic" #双三次補間
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Bicubic}
    "HighQualityBilinear" #高品質双一次補間 
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBilinear}
    "HighQualityBicubic" #高品質双三次補間
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic}
    default
      {$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Default}
  }
  
  #リサイズ画像を作成し保存する
  $g.DrawImage($srcImg, 0, 0, $newWidth, $newHeight)
  $dstImg.Save($dstFile, [System.Drawing.Imaging.ImageFormat]::Jpeg)
  
  #オブジェクトの破棄
  $srcImg.Dispose()
  $dstImg.Dispose()
}

使用方法

Resize-Image "リサイズ元画像ファイルのパス" "リサイズ後の画像保存先パス" 幅 高さ 品質

です。

品質には文字列を指定するのですが、指定できる値は下記のとおりです。

説明
"Default" 既定の補間モード
"Low" 低品質補間
"High" 高品質補間
"NearestNeighbor" 最近傍補間
"Bilinear" 双一次補間
"Bicubic" 双三次補間
"HighQualityBilinear" 高品質双一次補間
"HighQualityBicubic" 高品質双三次補間


ポイント

1.画像ファイルを扱うので、System.Drawingは必須です。 先頭でアセンブリをロードします。

2.縦横比率を維持する

 幅と高さを適切に指定すれば、見た目にもキチンとリサイズされますが、いちいち縦横比を計算してから指定するのは面倒です。 ということで幅または高さのどちらか一方を指定すると、縦横比率を計算したサイズを決定するようにしてあります。

関数内の"#受け取った引数から、新しいサイズを決定する "のコメント以下のif文がその計算を行っている箇所です。

 

ということでもう1つの使用方法ですが

Resize-Image "リサイズ元画像ファイルのパス" "リサイズ後の画像保存先パス" -width 幅 -quality 品質

または

Resize-Image "リサイズ元画像ファイルのパス" "リサイズ後の画像保存先パス" -height 高さ -quality 品質

のようにします。

これで縦横比が維持された画像が作成されます。

3.画像品質

 画像品質を指定するにはInterpolationModeを使用します。

 

Monday, March 31, 2008 3:15:04 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/01/23にわんくまブログで書いたものです。

データを取得してXMLファイルへ保存する(Oracle) (Windows PowerShell Tips)

データを取得してXMLファイルへ保存する その2(Oracle) (Windows PowerShell Tips)

で、Oracleから取得したデータをXML出力する例を紹介しました。

XMLを出力しただけでは見るのが不便なので、簡易XMLビューアを作ってみました。
実行例は下記のとおりです。

 

View-Xml.ps1

#===============================================================================
# View-Xml: XMLファイルを読み込んで表示する(簡易XMLViewer)
#
# 使用例
#   PS > View-Xml XMLファイルパス
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:View-Xml
{
  Param($XmlFile)

  #パスが指定されているか?
  if ( $XmlFile.Length -eq $null )
  {
    Write-Host "XMLファイルを指定してください"
    return
  }
  
  #存在するパスか?
  if ( -not $(Test-Path $XmlFile) )
  {
    Write-Host $XmlFile + "は存在しません"
    return
  }
  
  #データセットを作成し、XMLファイルを読み込む
  $dtSet = New-Object System.Data.DataSet
  $dtSet.ReadXml($XmlFile)
  
  #===== Formの作成 =====
  [reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
  $form = New-Object System.Windows.Forms.Form
  $form.Text = $XmlFile
  $form.Width = 500
  $form.Height = 400
  
  #===== DataGridViewの作成 =====
  $dgvXML = New-Object System.Windows.Forms.DataGridView
  $dgvXML.Dock = [System.Windows.Forms.DockStyle]::Fill
  $dgvXML.DataSource = $dtSet.Tables[0]
  $form.Controls.Add($dgvXML)
  
  #===== Panelの作成 =====
  $panel1 = New-Object System.Windows.Forms.Panel
  $form.Controls.Add($panel1)
  $panel1.Dock = [System.Windows.Forms.DockStyle]::Bottom
  $panel1.Height = 30
  
  #===== [閉じる]ボタンの作成 =====
  $btnClose = New-Object System.Windows.Forms.Button
  $btnClose.Location = New-Object System.Drawing.Point(405, 4)
  $btnClose.Text = "閉じる"
  $btnClose.anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Right
  $btnClose.Add_Click({$form.Close()})
  $panel1.Controls.AddRange($btnClose)
  
  #===== Formを表示 =====
  $form.ShowDialog()
}

使用方法は
View-Xml "XMLファイルのパス"
です。

ポイントは
・データセットを作成して、XMLファイルを読み込む
  $dtSet = New-Object System.Data.DataSet
  $dtSet.ReadXml($XmlFile)


・データセットをDataGridViewに連結する
  $dgvXML.DataSource = $dtSet.Tables[0]

・anchorプロパティ
 anchorプロパティは -bor 演算子を使うとうまくいきます。(-or演算子は試してみたところダメでした)
  -bor はビットごとのOR演算を行います。


です。

あとは、前回までのポイントを御参考下さい。

Monday, March 31, 2008 3:02:28 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/01/22にわんくまブログで書いたものです。

ネタ元: データを取得してXMLファイルへ保存する(Oracle) (Windows PowerShell Tips)

でOracleデータベースからデータを取得し、XMLファイルへ保存する関数を紹介しました。
今回は、これを改善し、

  • 取得したデータをWinodwsフォームのDataGridViewへの表示
  • [XMLへ保存]ボタンが押されたら、ファイル保存ダイアログを表示し、任意の名前を付けて保存
    ができるようにしてみました。

Export-OracleDataXml2.ps1

#===============================================================================
# Export-OracleDataXml2: データを取得してXMLファイルへ保存する(Oracle)
#
# 使用例
#   PS > Export-OracleDataXml
#   PS > DataSource: データソース名
#   PS > User ID: ユーザーID
#   PS > Password: パスワード
#   PS > Query String: クエリ文字列
#
# copyright HIRO's.NET(http://hiros-dot.net.com/)
#===============================================================================
function global:Export-OracleDataXml2
{
  #===== 必要情報をユーザーから取得する =====
  $DataSource = Read-Host "Data Source"
  $UserID = Read-Host "User ID"
  $Password = Read-Host "Password" -assecurestring
  $QueryString = Read-Host "Query String"
  
  #===== newpopsさんのblog参照 http://d.hatena.ne.jp/newpops/20050923/p1 =====
  #SecureStringからパスワード文字列を取得する
  $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
  $pass = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr)
  
  #===== Oracleからのデータ取得 =====
  [reflection.assembly]::LoadWithPartialName("System.Data.OracleClient")
  $ConnectionString = "Data Source=" + $DataSource + ";User ID=" + $UserID + ";Password=" + $Pass + ";Integrated Security=no;"
  $OraConn = New-Object System.Data.OracleClient.OracleConnection($ConnectionString)
  $dtSet = New-Object System.Data.DataSet
  $OraDa = New-Object System.Data.OracleClient.OracleDataAdapter($QueryString, $OraConn)
  $OraDa.Fill($dtSet)
  
  #===== Formの作成 =====
  [reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
  $form = New-Object System.Windows.Forms.Form
  $form.Text = $DataSource + "@" + $UserID
  $form.Width = 500
  $form.Height = 400

  #===== DataGridViewの作成 =====
  $dgvOracle = New-Object System.Windows.Forms.DataGridView
  $dgvOracle.Dock = [System.Windows.Forms.DockStyle]::Fill
  $dgvOracle.DataSource = $dtSet.Tables[0]
  $form.Controls.Add($dgvOracle)
  
  #===== Panelの作成 =====
  $panel1 = New-Object System.Windows.Forms.Panel
  $form.Controls.Add($panel1)
  $panel1.Dock = [System.Windows.Forms.DockStyle]::Bottom
  $panel1.Height = 30

  #===== [XMLへ保存]ボタンの作成 =====
  $btnExport = New-Object System.Windows.Forms.Button
  $btnExport.Location = New-Object System.Drawing.Point(324, 4)
  $btnExport.Text = "XMLへ保存"
  $btnExport.anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Right
  $btnExport.Add_Click(
  {
    #===== ファイル保存ダイアログを作成 =====
    $dlgSave = New-Object System.Windows.Forms.SaveFileDialog
    $dlgSave.DefaultExt = "XML"
    $dlgSave.Filter = "XMLファイル(*.xml)|*.xml"
    if ( $dlgSave.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK )
    {
      #===== データを保存する =====
      $dtSet.WriteXml($dlgSave.Filename)
    }
  })
  $panel1.Controls.Add($btnExport)
  
  #===== [閉じる]ボタンの作成 =====
  $btnClose = New-Object System.Windows.Forms.Button
  $btnClose.Location = New-Object System.Drawing.Point(405, 4)
  $btnClose.Text = "閉じる"
  $btnClose.anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Right
  $btnClose.Add_Click({$form.Close()})
  $panel1.Controls.AddRange($btnClose)
  
  #===== Formを表示 =====
  $form.ShowDialog()
}

 

実行結果は、下記のとおりです。

 

今回のポイント
・Windows フォームを作成する
VB.NETやC#で開発をされている方は、ソースを見ると何となくわかると思います。


**VB.NET**

Dim form As New Form()


**C#**

Form form = new Form();


**PowerShell**

$form = New-Object System.Windows.Forms.Form


でフォームのインスタンスを作成します。

・各コントロールの作成とフォームへの配置
コントロールを作成してフォームへ配置するには

$control = New-Object System.Windows.Forms.コントロール


のように記述してコントロールを作成して

$form.ControlAdd($control)


としてフォームへ配置します。
今回、ボタンはパネル上に配置したので

$panel1.Controls.Add($btnExport)


のようになっています。

・ボタンのクリックイベント


ボタンのクリックイベントは

$button.Add_Click({ここに処理したいスクリプトを記述})


のように記述します。

Monday, March 31, 2008 2:48:36 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/01/15にわんくまブログで書いたものです。

ネタ元:データを取得してXMLファイルへ保存する(Oracle) (PowerShell Tips)

で、SecurityStringの話をちらっとしたのですが、関数化しておくとSecurityStringからの文字列取得が少し楽になると思います。

ということで

Convert-ToStringBSTR.ps1

#===============================================================================
# Convert-ToStringBSTR: SecurityString文字列を解読した値を返す
#
# 使用例
#   PS > Convert-ToStringBSTR $SecurityString
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:Convert-ToStringBSTR
{
  Param([System.Security.SecureString]$SecureString)
  
  $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
  $pass = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr)
  
  return $pass
}

使用方法ですが、まずSecurityStringを準備します

たとえば

PS C:\Work> $a = Read-Host "何か文字列を入力してね" -assecurestring

で、

PS C:\Work> Convert-ToStringBSTR $a

とすると解読した文字列が表示されます。

Monday, March 31, 2008 2:43:26 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/01/15にわんくまブログで書いたものです。

Windows PowerShellからOracleへアクセスし、取得したデータをXMLファイルへ落とし込む関数を作ってみました。

Export-OracleDataXml.ps1

#===============================================================================
# Export-OracleDataXml: データを取得してXMLファイルへ保存する(Oracle)
#
# 使用例
#   PS > Export-OracleDataXml
#   PS > DataSource: データソース名
#   PS > User ID: ユーザーID
#   PS > Password: パスワード
#   PS > Query String: クエリ文字列
#   PS > Save Path: 保存先を指定
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:Export-OracleDataXml
{
  #===== 必要情報をユーザーから取得する =====
  $DataSource = Read-Host "Data Source"
  $UserID = Read-Host "User ID"
  $Password = Read-Host "Password" -assecurestring
  $QueryString = Read-Host "Query String"
  $SavePath = Read-Host "Save Path"
  
  #保存先パスに"\"が含まれていない場合(つまりファイル名のみが指定されていた場合)は
  #絶対パスにする(ファイル名のみが指定された場合、カレントディレクトリに保存するため)
  if ( $SavePath.IndexOf("\") -eq -1 )
  {
    $SavePath = $(Join-Path $(Get-Location).Path $SavePath)
  }
  
  #===== newpopsさんのblog参照 http://d.hatena.ne.jp/newpops/20050923/p1 =====
  #SecureStringからパスワード文字列を取得する
  $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
  $pass = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr)
  
  #===== Oracleからのデータ取得とファイルへの保存 =====
  [reflection.assembly]::LoadWithPartialName("System.Data.OracleClient")
  $ConnectionString = "Data Source=" + $DataSource + ";User ID=" + $UserID + ";Password=" + $Pass + ";Integrated Security=no;"
  $OraConn = New-Object System.Data.OracleClient.OracleConnection($ConnectionString)
  $dtSet = New-Object System.Data.DataSet
  $OraDa = New-Object System.Data.OracleClient.OracleDataAdapter($QueryString, $OraConn)
  $OraDa.Fill($dtSet)
  $dtSet.WriteXml($SavePath)
}

最初に使用方法ですがコンソールウィンドウに

PS C:\Work> Export-OracleDataXml

と入力します。

つぎに、接続先、ユーザー名、パスワード、データを取得するためのselect文、取得データの保存先を聞かれるので順番に入力していきます。

下記はOracleのサンプルであるscott/tigerのemp表データをすべて取得し、結果をC:\Work\emp.xmlへ保存する例です

PS C:\Work> Data Source: YourServer
PS C:\Work> User ID: scott
PS C:\Work> Password: *****
PS C:\Work> Query String: select * from emp
PS C:\Work> SavePath: C:\Work\emp.xml

 

===== ポイント =====

今回の関数は対話式にしてみました。

1)Read-Hostコマンドレットを使用して、ユーザーからの入力を取得して、変数へ代入しています。

 Read-Hostコマンドレットは

 $a = Read-Host "メッセージ"

 のように使用します。

 この場合は、コンソールに "メッセージ:" と表示され

 ユーザーが[Enter]を押すまでの文字列を$aに代入します。

2)SecureStringでパスワードを*で表示する

 Read-Hostコマンドレットのパラメータに -assecurestring というのがあるんですが、このパラメータを使用すると、ユーザーが入力する文字列が * で表示されます。

 -assecurestringを使用すると、変数の型がSystem.Security.SecureStringになります。

  System.Security.SecureString型のデータはこのままでは使用できません。

 このままでif文などで比較しても正しい結果は得られないので、解読してString型に変換する必要があります。

 newpopsさんのblogにその方法が書かれてありましたので参考にさせていただきました。(http://d.hatena.ne.jp/newpops/20050923/p1

3)System.Data.OracleClientの読み込み

 PowerShell起動時はSystem.Data.OracleClientは読み込まれていません。

 [reflection.assembly]::LoadWithPartialName で System.Data.OracleClientをロードし、OracleClientクラスを使用可能にしています。

4) DataSetを作成する

 取得したデータをXmlへ出力するのに、DataSetのWriteXmlメソッドを使用することにしました。

 New-Obejctコマンドレットを使用してDatSetを作成しています。

5)DataAdapterを作成する

 これもNew-Objetctコマンドレットを使用しています。

6)XMLへ出力する

 4)で述べたとおり、DataSetのWriteXmlメソッドを使用してXMLファイルへの出力を行います。

Monday, March 31, 2008 2:39:43 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/01/09にわんくまブログで書いたものです。

指定したファイルの行数を取得する(Windows PowerShell Tips) を関数にしたものが下記です。

===============================================================================
# Get-LineCount: 指定したファイルの行数を取得する
# Param: 
#   $filepath : 行数カウントを行うファイルのパス
#
# 使用例
#   Get-LineCount Test.txt
#
#   ヘルプを見る場合は
#   Get-LineCount /?
#
# copyright HIRO's.NET(http://hiros-dot.net/)
#===============================================================================
function global:Get-LineCount
{
  Param ([string]$filepath)
  
  #ヘルプの参照か?
  if ( $filepath -eq "/?" )
  {
    $helpmsg = @"
    書式`r`n
      Get-LineCount ファイル名
    `r`n
    使用例`r`n
      #Test.txtの行数を取得
      Get-LineCount `"Test.txt`"
      
      #ヘルプを参照する
      Get-LineCount /?
      
"@
    
    Write-Host $helpmsg
    return
  }
    
  $MeasureObject = Get-Content $filepath | Measure-Object
  return $MeasureObject.count
}

使用方法は

PS C:\Users\HIRO> Get-LineCount "Test.txt"
12

です

Monday, March 31, 2008 2:29:19 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback

この記事は2008/01/09にわんくまブログで書いたものです。

PowerShellにはファイル操作を行うコマンドレットがいくつか(Get-Content, Add-Contentなど)あるのですが、ファイルの行数を取得できるようなコマンドレットはありません。

たとえばGet-Contentコマンドレットはファイル内容を取得するコマンドレットですが、ファイル行数を取得すようなパラメータは存在しません。

既存のコマンドレットの組み合わせで何とかならないか模索していたところ Get-ContentとMeasure-Objectコマンドレットで行けそうなことがわかりました。

 

Get-Contentで読み取った内容を、パイプを使用してMeasure-Objectへ渡してやると Countプロパティで行数を取得することができます。

PS C:\Users\HIRO> Get-Content "Test.txt" | Measure-Object

Count    : 13
Average  :
Sum  :
Maximum  :
Minimum  :
Property :

といった感じです。

上記は、Test.txtは13行あることを示しています。

Monday, March 31, 2008 2:25:07 AM (Tokyo Standard Time, UTC+09:00)  #    Comments [0]  |  Trackback