ラベル 文法 の投稿を表示しています。 すべての投稿を表示
ラベル 文法 の投稿を表示しています。 すべての投稿を表示

2022年8月19日金曜日

◆引数の数が可変の場合

変数で受け取った値を引数に使ってコマンドを呼び出す場合などに、省略された場合を考慮しないといけない。

  Send-MailMessage    -To $to                                       `

  -Cc $cc                                       `

  -From $from                  `

  -Subject $subject                                        `

  -SmtpServer $mailServer                                 `

  -Body $body                                 `

  -Attachments $attachment                    `

  -Encoding  ([System.Text.Encoding]::Default)     

こんなケースで$attachmentに値が入ってこないとエラーになる。

だからと言って引数の組み合わせの分だけコマンドを用意するのも・・・。

なんか簡単に解決できる方法がありそうにも思うが、見つからなかったのでとりあえず以下の様にしてみた。

  $param = @{

"To" = $to

"Cc" = $cc

"From" = $from

"Subject" = $subject

"SmtpServer" = $mailServer

"Body" = $body

"Attachments" = $attachment

"Encoding" = [System.Text.Encoding]::Default

  }

if($attachment -eq ""){$param.Remove("Attachments")}

Send-MailMessage @param

2022年2月14日月曜日

◆2022/02/14 連想配列と一緒にフォーマット演算子のプレースフォルダを使う

ADのサブネットをコマンド設定するときに「New-ADObject」を使うようなのだが、その中で以下の様なプロパティがある

-OtherAttributes @{location="Building A";siteObject="CN=HQ,CN=Sites,CN=Configuration,DC=FABRIKAM,DC=COM"}


サブネットがたくさんあるとループしながらフォーマット演算子で可変部分を入れ替えてとなるのだが、フォーマット演算子と連想配列を一緒に使うとエラーとなる。

{}の扱いがよろしくない。


連想配列側の括弧を2重にすると良いようだ。{{hoge}}のように。

2020年12月15日火曜日

◆noexitパラメータ

確か昔も嵌ったことがあってもしかするとどこかにメモしたのかもしれませんが再度。

start-process powershell.exe -Credential $cred -ArgumentList ("-command dir -noexit " )

このexitパラメータが効かなかったりするのだが、なぜかパラメータの先頭にするとOK。

2020年11月20日金曜日

◆配列宣言時に各要素の区切り文字を変えると動作が異なるのは何故か

https://ja.stackoverflow.com/questions/72053/%e9%85%8d%e5%88%97%e5%ae%a3%e8%a8%80%e6%99%82%e3%81%ab%e5%90%84%e8%a6%81%e7%b4%a0%e3%81%ae%e5%8c%ba%e5%88%87%e3%82%8a%e6%96%87%e5%ad%97%e3%82%92%e5%a4%89%e3%81%88%e3%82%8b%e3%81%a8%e5%8b%95%e4%bd%9c%e3%81%8c%e7%95%b0%e3%81%aa%e3%82%8b%e3%81%ae%e3%81%af%e4%bd%95%e6%95%85%e3%81%8b


Powershellっぽくて、こういう話は好きです。

簡単に言えば、

$a = 1
$b = 2


は、

$a = 1 ; $b = 2

って1行にも書けるよ。

てのと、

「,」と「+」は「,」が優先ねってだけの話だと思うのですが一見すると摩訶不思議にも思えるってところでしょうか。

まぁ、配列の区切りは「,」だけを使う人がほとんどでしょうから嵌る人はまずいないでしょうけど。

2020年10月28日水曜日

◆配列の連結

PS C:\> $a = 1,2,3
PS C:\> $b = 4,5,6
PS C:\> $a + $b
1
2
3
4
5
6
PS C:\> $a,$b
1
2
3
4
5
6

この2つは一見同じ結果に見えるが、$a = 1 とすると前者は

[System.Object[]] に 'op_Addition' という名前のメソッドが含まれないため、メソッドの呼び出しに失敗しました。
発生場所 行:1 文字:1
+ $a + $b
+ ~~~~~~~
     + CategoryInfo          : InvalidOperation: (op_Addition:String) []、RuntimeException
     + FullyQualifiedErrorId : MethodNotFound

となる。

後者も一見良さそうに見えるが実際には多段階配列になってしまう。

$c = $a , $b
$c.count   #2になる
$c[0][0]     #1

どうすれば汎用的ですかね。

$c = @()
$c += $a |  %{$_}
$c += $b |  %{$_}

とか?

.NETクラスを使う?

連結も加算も「+」にしたので混乱を招く?

2020年10月22日木曜日

◆Get-ADUser フィルター(filter)の指定方法

外側をダブルコーテーション、文字列をシングルコーテーションで囲むのが基本でしょうか。

外側囲み記号

属性

値の指定方法

値の囲み記号

結果

シングルコーテーション

数値

コンスタント

無し

Get-ADUser -Filter 'employeeid -eq 479'

シングルコーテーション

数値

変数

無し

$id = 479

Get-ADUser -Filter 'employeeid -eq $id'

シングルコーテーション

数値

変数(プロパティ)

無し

$p = 1 | select id , account

$p.id = 479 ; $p.account = "hoge_hoge"

Get-ADUser -Filter 'employeeid -eq $($p.id)'

X

シングルコーテーション

文字列

コンスタント

ダブルコーテーション

Get-ADUser -Filter 'samaccountname -eq "hoge_hoge"'

シングルコーテーション

文字列

変数

無し

$account = "hoge_hoge"

Get-ADUser -Filter 'samaccountname -eq $account'

シングルコーテーション

文字列

変数

ダブルコーテーション

$account = "hoge_hoge"

Get-ADUser -Filter 'samaccountname -eq "$account" '

X

シングルコーテーション

文字列

変数(プロパティ)

無し

$p = 1 | select id , account

$p.id = 479 ; $p.account = "hoge_hoge"

Get-ADUser -Filter 'samaccountname -eq $($p.account)'

X

ダブルコーテーション

数値

コンスタント

無し

Get-ADUser -Filter "employeeid -eq 479"

ダブルコーテーション

数値

変数

無し

$id = 479

Get-ADUser -Filter "employeeid -eq $id"

ダブルコーテーション

数値

変数(プロパティ)

無し

$p = 1 | select id , account

$p.id = 479 ; $p.account = "hoge_hoge"

Get-ADUser -Filter "employeeid -eq $($p.id)"

ダブルコーテーション

文字列

コンスタント

シングルコーテーション

Get-ADUser -Filter "samaccountname -eq 'hoge_hoge' "

ダブルコーテーション

文字列

変数

無し

$account = "hoge_hoge"

Get-ADUser -Filter "samaccountname -eq $account"

X

ダブルコーテーション

文字列

変数

シングルコーテーション

$account = "hoge_hoge"

Get-ADUser -Filter "samaccountname -eq '$account' "

ダブルコーテーション

文字列

変数(プロパティ)

無し

$p = 1 | select id , account

$p.id = 479 ; $p.account = "hoge_hoge"

Get-ADUser -Filter "samaccountname -eq $($p.account)"

X

ダブルコーテーション

文字列

変数(プロパティ)

シングルコーテーション

$p = 1 | select id , account

$p.id = 479 ; $p.account = "hoge_hoge"

Get-ADUser -Filter "samaccountname -eq '$($p.account)' "

波括弧

数値

コンスタント

無し

Get-ADUser -Filter {employeeid -eq 479}

波括弧

数値

変数

無し

$id = 479

Get-ADUser -Filter {employeeid -eq $id}

波括弧

数値

変数(プロパティ)

無し

$p = 1 | select id , account

$p.id = 479 ; $p.account = "hoge_hoge"

Get-ADUser -Filter {employeeid -eq $($p.id)}

X

2020年9月11日金曜日

◆ActiveDirectoryの配列、非配列のプロパティを同列に扱う

ActiveDirectoryに限った話ではないのだが、ActiveDirectoryのプロパティを扱っていて気付いた現象。

ActiveDirectoryには単一値を持つプロパティと配列を取るプロパティがある。
どちらになるかはMSの決めなので使う側からすると複数入れたいのに単一値プロパティだったり、一つしかないのに配列のプロパティだったりする。

そこで配列の場合も先頭の要素しか使わずに、複数必要な場合はカンマで区切って入れる運用とした。

実はこのプロパティが配列と単一値と混在すると意識していなかったのだが、たまたま以下の様なロジックでうまくいっていた。

$aに様々なプロパティが入ってきて、

$b  =  if( $true ){ $a }

$aがstringでも要素数1のstring配列でも$bにはstringが入ってくれた。

これを故有って以下の様に変えたら$bを使う場所でエラーが発生。

if( $true) { $b = $a }

$b の型がstringではないというエラーだった。
よくよく考えてみればこのエラーは理解できるのだが、そもそもじゃあなぜ変更前はうまくいっていたんだ?と逆に疑問に思った。

結局これはどういうことかというと、最初のロジックの動作は以下の様なイメージ。

$b =  $a | %{ $_ }

要は値が詰めなおされている。
その際、$a の要素は1つなので$bの型は配列ではなく単なるstringになるのだ。


ここで、もう一つ今まで気づいていなかったことが発生。

$b にもともと値が入っていなければ最初のロジックで良いのだが、$bにもともと値が入っていて、ある条件の時だけ$aを設定したいといった時にこのロジックはうまくいかない。
どうも以下の様な動作をして$bの値をつぶしてしまうようだ。

$b = if( $true ){ $a } else { $null }

いままで結構Powershellを使ってきたがまだまだ気づいていないことがありますね。

結局今回のニーズでどのようなロジックがベストかは難しいところ。
以下の様なロジックを書いていたら、後から見た人にどちらかののIF文を削除される可能性もありそうですよね。

if( $hoge –eq $true ){
    $b = if( $hoge –eq $true) { $a }
}

2020年3月25日水曜日

◆実行ポリシー

Restrictedな環境でもps1ファイルを右クリックして「PowerShellで実行」が動くのは最初からでしたっけ?

2018年10月24日水曜日

◆再入門

3年ほど前に転勤になりPowerShellとは無縁になっていたため、すっかり文法を忘れてしまった。

使う局面が無いのでこのままでは全く使えなくなってしまうのでボケ防止に初歩の初歩から再入門してみようと思う(本当に少しずつ)

最近ではPowerShellもバージョンが進んで様々なコマンドレットが追加されたものと思うが、年齢的にも環境的にもついて行けないので文字列操作などの基本部分だけにとどめる。

PowerShell第一人者の牟田口さんの昔のブログなどを見てちょぼちょぼとやってくつもり。(続かないかもしれませんが)

 

今日は配列の抽出

1,2,3,4,5  -eq 3

なんてやるとどうなるんだっけ?てな所ですが、TrueとかFalseとか帰ってくるわけではなくて配列の中の3と等しいものが抽出されるんですね。

image

こんな感じにやりたくなりますけどね。

image

一応以下で昔やってたみたいですね。

◆配列をフィルターする

2015年4月21日火曜日

◆Splatting(分配演算子)

以前ちょっとだけ以下で書いたことのある機能。
PowerShell: ◆分配演算子

もう少しわかり易い例が載っていたのでメモしておく。
Using Splatting - Power Tips - PowerShell.com – PowerShell Scripts, Tips, Forums, and Resources

この記事に対する質問で「どんな時に使うんだい?」ってのあったが、そこが大事。

使いでがあるのは、関数などで受け取ったパラメータをそのままフォワードしたりする時。

image

(私は、引数が長くなって見づらくなる時によく使っている)

ちなみに「Splat」は「ぶつけて平らに延ばす」的な意味。
PowerShellの何かのエラーメッセージで「分配演算子」と訳していたので私はその名前を使っている。

Help的には3.0から「about_splatting」として載っているようだ。
相変わらず日本語訳はされていないので正式になんという日本語名かは不明。

PowerShellに限らず、日本語訳は機械翻訳程度しかやらないのがMSの主流になってきているようなので、これからは一段と英語力が要求されそうだ。

2015年4月16日木曜日

◆Gourp-Object からのHashTable

ちょっと躓いたのでメモ。

001
002
003
004
005
006
007

$HashService = Get-WmiObject Win32_Service | 
 
Group-Object State -AsHashTable
$HashService.Stopped 
"◆◆◆◆"
$HashService2 = Get-Service |
 
 
Group-Object Status -AsHashTable 
$HashService2.Stopped

$HashService.Stoppedは参照できるが、$HashService2.Stoppedの方は参照できない。
AsStringをつければうまくいくことは判っているが、なぜ違いが出るのだろう・・・。

あとで調査。

2015年4月10日金曜日

◆カスタムオブジェクトに表示用の型を指定する

Faking Object Type - Power Tips - PowerShell.com – PowerShell Scripts, Tips, Forums, and Resources

「PSCustomObject」を作るときに既存の型を表示用に指定することができるそうな。

image

「PSTypeName」として型を指定しておくと表示するときに、その型のフォーマットで表示してくれる。
メンバーを表示してみると「CodeProperty」というちょっと変わったプロパティで保持されているのが判る。

image

既存の一覧に独自のオブジェクトを追加して一緒に表示するなんて使い方ができたりするのかな。

image

image

ただし、この機能はVer.3.0以降が要求される。

2014年10月8日水曜日

◆パラメータ名の一部省略の不思議

コマンドレットのパラメータは他のパラメータと区別可能ならば途中までの文字で指定が可能だ。

image

dir –p と入力してタブを押すと「Path」しか出てこないので「p」だけでも良さそうだが、なぜか以下のようなエラーとなる。

PS>dir -p c:\
Get-ChildItem : パラメーター名 'p' があいまいなため、パラメーターを処理できません。一致する名前の候補は次のとおりです:
-Path -LiteralPath。
発生場所 行:1 文字:4
+ dir <<<<  -p c:\
    + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem]、ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameter,Microsoft.PowerShell.Commands.GetChildItemCommand

なぜ「LiteralPath」も対象になるのだろう。

2014年10月6日月曜日

◆IF文での判定条件の書き方

今更ながら基本の基本を確認しておく。

IF文での判定条件は普通に考えると、

if($a –eq 1){hogehoge}

てな感じに書くのが一般的な気がする。
ただし、これは一般的な他の言語と同様な書き方で一見何の問題も無いように見えるが、PowerShellの場合はちょっと事情が異なる。

例えば以前PowerShell: ◆配列をフィルターするで書いたように、配列などではイコール演算子が感覚とはちょっと違った動作をする。

この間、PowerShell: ◆閾値以下の空き容量のHDドライブがあったら警告するで使った抽出判定も、

if(Get-PSDrive | ?{$_.USED –ne “”}){hogehoge}

ってな感じでは旨くいかない。(余計なものが幾つか残ってしまう)
image

では、どうすればよいのか。
昔からなんとなく使っている以下の書き方が実は正しい書き方なのではと最近思っている。

if($a){hogehoge}

こう書いた場合、どう判定されるかというと(経験的に)、その変数のデータ型の初期値であればFalse、初期値以外がTrueになる。

数値であれば、0がFalse、文字列であれば””がFalse、オブジェクトであればNullがFalseといった具合。
配列がちょっと厄介だが、要素が複数の場合はTrue、ひとつの場合はその変数の属性に応じて上記と同様に判定される。

この機能はおそらく、PowerShellが$aをbool型に自動変換しているのだろう。
即ち、

if([bool]$a){hogehoge}

と書くのと同じではないかと思う。

image

 

先に書いた、

if(Get-PSDrive | ?{$_.USED –ne “”}){hogehoge}

のパターンでは、USEDプロパティがスクリプトプロパティなので、ドライブによってUSEDのデータ型が違ってきている。

なので、演算子を直接使って判定しようとすると

image

てな感じになってしまう。

これはやはり普段から

if($a){hogehoge}

の書き方を使うのが良いのだろうと思う。

ちなみに、「-ne」の場合は「!」を使って(!$a)とする。

 

あくまでも、経験則で考えたものですが・・・・。

2014年9月26日金曜日

◆Foreach-Objectのパラメータへの疑問

今更の感じはするが、Foreach-Objectの動作。

PS>1..3 | ForEach-Object{"開始"}{"ループ"}{"終了"}
開始
ループ
ループ
ループ
終了

本来、ヘルプを見ると位置オペランドは(-Process)だけなので、なぜこれで動くのだろうとちょっと疑問に思う。

ちなみに、以下は良いが、

PS>1..3 | ForEach-Object{"開始"}{"ループ"}

当然、以下は上と同じ書式なので「ループ」が初期処理とみなされる。

PS>1..3 | ForEach-Object{"ループ"}{"終了"}

なので、

PS>1..3 | ForEach-Object{"ループ"}  -end{"終了"}

とする必要が有りそう。

2014年8月20日水曜日

◆変数の値解決?

ネットで見かけた質問で以下のようなものがあった。

$drive = ""
$cmd = "dir $drive"
$drives = "c:","d:"

foreach($drive in $drives)
{
    Invoke-Expression $cmd
}

なんとなく眺めるとうまくいくような気もする。

Invoke-Expressionをやめて単純に$cmdを表示させると、

PS>$drive = ""
$cmd = "dir $drive"
$drives = "c:","d:"

foreach($drive in $drives)
{
    $cmd
}

-- 以下、結果--

dir
dir

 

これまた意外と嵌れば嵌るのかもね・・・っと思ったり。

要は2行目の、
$cmd = "dir $drive"

のときに、$driveは値解決されちゃうので$cmdの中身は”dir”になっちゃう。

どうすれば良いんですかね・・・。

こんな感じ?

$drive = ""
$cmd = "dir {0}"
$drives = "c:","d:"

foreach($drive in $drives)
{
    Invoke-Expression ($cmd -f $drive)
}


もしかして、こんなのがスマートか?

$drive = ""
$cmd = {dir $drive}
$drives = "c:","d:"

foreach($drive in $drives)
{
   
   & $cmd
}

2014年7月1日火曜日

◆演算子を連結して実行する

PowerShellの演算子は連結して実行できたりする。

PS>"a,b,c,d,e" -split ','
a
b
c
d
e
PS>"a,b,c,d,e" -split ',' -notlike 'c'
a
b
d
e
PS>"a,b,c,d,e" -split ',' -notlike 'c'-replace 'b','{0}'
a
{0}
d
e
PS>"a,b,c,d,e" -split ',' -notlike 'c'-replace 'b','{0}'-join '-'
a-{0}-d-e
PS>("a,b,c,d,e" -split ',' -notlike 'c'-replace 'b','{0}'-join '-') -f 'bbb'
a-bbb-d-e

最後のフォーマット演算子(-f)はなぜか括弧が必要だった。
(優先順位が違うのだろうか)

2014年4月30日水曜日

◆UNCパスをTest-Pathで確認する

Testing UNC Paths - Power Tips - PowerShell.com – PowerShell Scripts, Tips, Forums, and Resources

Set-Location HKCU:\

とかやった後に、Test-Path \\Server\myfolder

とかでUNCパスを確認しようとするとうまくいかないってお話。

\\Server というレジストリーを探しに行っちゃうって事でしょうか。

コンテキストの影響を受けずに確認するには、

Test-Path  FileSystem::\\Server\myfolder

とやると良いとの事。

2014年1月20日月曜日

◆Ordered Hash Tableについてもメモ

ハッシュテーブルの順番は通常保証されていない。
image

保証するためには以下のように「Ordered」型に変換してあげる。
image

Insertなんかも出来るようになる。
image

この「Ordered」は3.0から追加された機能なので、2.0で使う場合は「Orderd」の実体である「OrderedDictionary」クラスを使う。
image