2020-01-31

PowerShell 5.1の罠の続きです。

コマンドレットCompress-Archiveにはワイルドカードの扱いで問題がある様子。

1)正しい動き
Compress-Archiveでhoge.zipを生成する。
同じhoge.zipの生成を実行すると、既に存在するとしてエラー
-Forceを付加すると、既に存在しても上書き

PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\A\hoge.zip

PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\A\hoge.zip
Compress-Archive : アーカイブ ファイル C:\TEST\A\hoge.zip は既に存在します。既存のアーカイブ ファイルを更新するには、-Update パラメーターを使用してください。既存のアーカイブ ファイルを上書きするには、-Force パラメーターを使用してください。
発生場所 行:1 文字:1
+ Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\A\hoge. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (C:\TEST\A\hoge.zip:String) [Compress-Archive]、IOException
    + FullyQualifiedErrorId : ArchiveFileExists,Compress-Archive

PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\A\hoge.zip -Force

2)ワイルドカードの扱いに失敗する動き。パスにワイルドカード[が含まれている。
パスにワイルドカード[が含まれているとエラー
バッククオート`を1 個ではエラー
バッククオート``を2個にすると成功、hoge.zipが生成される
生成したファイルを上書きさせる事を狙って再度実行するとPowerShellの内部でエラー

見た感じでは、上書きの内部処理で元ファイルを削除する箇所に問題がある様子。
ファイル削除の箇所でエスケープが上手く処理されていない様だ。
そもそも-DesitinationPathの様な出力側でワイルドカードは使わない(複数のファイルに出力する事は無い)ので、標準でワイルドカードを受け付けないLiteralPath扱いするべきなのである。

3)おまけ
Copy-Itemの-Desitination
エスケープ不要で正常動作

Move-Itemの-Desitination
エスケープ必要で正常動作


どうしてこんな複雑な事に....。




PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\[A\hoge.zip -Force
Compress-Archive : パス 'C:\TEST\[A' が存在しないか、または有効なファイル システム パスではありません。
発生場所 行:1 文字:1
+ Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\[A\hoge ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (C:\TEST\[A:String) [Compress-Archive]、InvalidOperationException
    + FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Compress-Archive

PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\`[A\hoge.zip -Force
Compress-Archive : パス 'C:\TEST\[A' が存在しないか、または有効なファイル システム パスではありません。
発生場所 行:1 文字:1
+ Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\`[A\hog ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (C:\TEST\[A:String) [Compress-Archive]、InvalidOperationException
    + FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Compress-Archive


PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\``[A\hoge.zip -Force

PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath C:\TEST\``[A\hoge.zip -Force
Remove-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [A
発生場所 C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:182 文字:13
+             Remove-Item -Path $DestinationPath -Force -ErrorAction St ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Remove-Item]、ParameterBindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.RemoveItemCommand


PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath 'C:\TEST\``[A\hoge.zip' -Force
Remove-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [A
発生場所 C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:182 文字:13
+             Remove-Item -Path $DestinationPath -Force -ErrorAction St ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Remove-Item]、ParameterBindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.RemoveItemCommand


PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath "C:\TEST\``[A\hoge.zip" -Force
Remove-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [A
発生場所 C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:182 文字:13
+             Remove-Item -Path $DestinationPath -Force -ErrorAction St ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Remove-Item]、ParameterBindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.RemoveItemCommand


PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath "C:\TEST\[A\hoge.zip" -Force
Compress-Archive : パス 'C:\TEST\[A' が存在しないか、または有効なファイル システム パスではありません。
発生場所 行:1 文字:1
+ Compress-Archive -Path C:\TEST\*.txt -DestinationPath "C:\TEST\[A\hog ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (C:\TEST\[A:String) [Compress-Archive]、InvalidOperationException
    + FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Compress-Archive


PS C:\msys64\home\doctor_d\FileMaintenace> Compress-Archive -Path C:\TEST\*.txt -DestinationPath 'C:\TEST\[A\hoge.zip' -Force
Compress-Archive : パス 'C:\TEST\[A' が存在しないか、または有効なファイル システム パスではありません。
発生場所 行:1 文字:1
+ Compress-Archive -Path C:\TEST\*.txt -DestinationPath 'C:\TEST\[A\hog ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (C:\TEST\[A:String) [Compress-Archive]、InvalidOperationException
    + FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Compress-Archive



PS C:\msys64\home\doctor_d\FileMaintenace> Copy-Item -Path C:\TEST\*.txt -Destination C:\test\[A -Force

PS C:\msys64\home\doctor_d\FileMaintenace> Copy-Item -Path C:\TEST\*.txt -Destination C:\test\[A -Force


PS C:\msys64\home\doctor_d\FileMaintenace> Move-Item -Path C:\TEST\*.txt -Destination C:\test\[A -Force
Move-Item : 指定されたワイルドカード文字パターンは無効です: [A
発生場所 行:1 文字:1
+ Move-Item -Path C:\TEST\*.txt -Destination C:\test\[A -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Move-Item], WildcardPatternException
    + FullyQualifiedErrorId : RuntimeException,Microsoft.PowerShell.Commands.MoveItemCommand


PS C:\msys64\home\doctor_d\FileMaintenace> Move-Item -Path C:\TEST\*.txt -Destination C:\test\`[A -Force
Move-Item : 指定されたワイルドカード文字パターンは無効です: [A
発生場所 行:1 文字:1
+ Move-Item -Path C:\TEST\*.txt -Destination C:\test\`[A -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Move-Item], WildcardPatternException
    + FullyQualifiedErrorId : RuntimeException,Microsoft.PowerShell.Commands.MoveItemCommand


PS C:\msys64\home\doctor_d\FileMaintenace> Move-Item -Path C:\TEST\*.txt -Destination C:\test\``[A -Force

PS C:\msys64\home\doctor_d\FileMaintenace> Move-Item -Path C:\TEST\*.txt -Destination C:\test\``[A -Force

2020-01-29

Windowsのパス文字列扱いを観察してみたので、備忘録。

パス文字列長は260文字以下。259文字まで。

PS C:\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789> new-item -ItemType file -Path 12345678901234567890123456789012345678901234567890123
new-item : パス 'C:\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\1234567890123456789012345
6789012345678901234567890123' の一部が見つかりませんでした。
発生場所 行:1 文字:1
+ new-item -ItemType file -Path 123456789012345678901234567890123456789 ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (C:\012345678901...901234567890123:String) [New-Item], DirectoryNotFoundException
    + FullyQualifiedErrorId : NewItemIOError,Microsoft.PowerShell.Commands.NewItemCommand


PS C:\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789> new-item -ItemType file -Path 1234567890123456789012345678901234567890123456789012

ここで、フォルダのC:\0...89\までで3文字 + 51文字 x4 = 207文字
作成したファイルが52文字である。


PS C:\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789> Get-ChildItem | % {$_.FullName} | % {$_.Length}
259

さて、260文字制限は、フルパスの文字数なのでネットワークドライブとしてマウントすると、さらに深い階層に出来る。

 例えば、C:\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789\01234567890123456789012345678901234567890123456789をネットワークドライブZ:にマウントして、Z:に長いパス名のフォルダを格納する事が出来る。
 無論、260文字を超えるパスのフォルダやファイルはC:から始まるパス表記を指定して削除する事は出来ない。

2020-01-12

 これは詳しい方々が散々書かれているので、備忘録。

  例えば、C:\TEST配下に以下の様なフォルダを作成する。
 NTFSでは[]は禁則文字ではないので、A[、[AB]といったフォルダ、ファイルは作成可能である。滅多にこの様な命名は無いと思いますが。

A                                                                                                                     AA                                                                                                                          AB                                                                                                                           A[                                                                                                                            B[                                                                                                                            [A                                                                                                                            [AB]                                                                                                   

 ここで、フォルダ名をフィルタ後、削除する簡単なスクリプトを実行してみる。

 これは Where-Objectで正しく[Aフォルダをフィルタする。それをRemove-Itemに渡してくれる。しかしながらRemove-Itemは[Aの[をワイルドカードとして扱うため、閉じる]が存在しないとして、エラーとなってしまう。

 PS C:\TEST> Get-ChildItem -Name | Where-Object {$_ -eq '[A'} | ForEach-Object {Remove-Item $_}
Remove-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [A
発生場所 行:1 文字:68
+ ...  -Name | Where-Object {$_ -eq '[A'} | ForEach-Object {Remove-Item $_}
+                                                           ~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Remove-Item]、ParameterBindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.RemoveItemCommand



 これはWhere-Objectで正しく[AB]フォルダをフィルタする。それをRemove-Itemに渡してくれる。しかしながらRemove-Itemは[AB]を「[]がワイルドカードのため、A または B」として扱う。結果[AB]フォルダは削除せず、Aフォルダを削除してしまう。

PS C:\TEST> Get-ChildItem -Name | Where-Object {$_ -eq '[AB]'} | ForEach-Object {Remove-Item $_}

 解決するには{Remove-Item -LiteralPath $_}とする。

2020-01-11

 Powershellのヒアドキュメント改行コードではまったので、備忘録。  以下の様にSQL実行結果をログに出力するコードを作成。SQL実行結果の前に日時などをログに事前に出力させる。 日時などはまとめてヒアドキュメントで変数を作成しておく。

 出力結果のファイルをメモ帳で開くと、DATA,SHELL,SQLの文字列が改行されていない。サクラエディタでは改行されている。
 良く観察すると日時などの部分の改行はLFだが、SQL実行結果の部分の改行はWIndows標準のCR&LFになっている。
 そのためWindowsメモ帳ではLFだけの行が改行表示されないのであった。

 対応策は、ヒアドキュメントの各行の行末に
 `r  
と明示的にエスケープシーケンスのCRを追加した。


 謎なのはコードを一部修正する前はヒアドキュメントの部分もCR&LFのログが出力されていた事である。

2019-12-18

仕事上で他人のPowershellスクリプトを観察して感じたことを。

「Windowsバッチ臭い」のである。
例えば、バッチでパラメータを与える時、パラメータはスペース区切りで任意の複数個を記述できる。一見柔軟性が高い様だが、バッチ作成者以外から見ると厄介である。
不完全な設計書やプログラム本体を観察して、受け入れらるパラメータは何個なのか、パラメータの書式はどの様なものかを確認しないとバッチは利用できない。

対してPowershellであれば、利用者に負担を掛けずに使いやすいものを作成できる。

例えば以下のコードであれば、こんな感じで動いてくれる。
これであれば、指定が必須のパラメータは何なのか、パラメータはどの様な形式なのか、指定のものから選択する必要があれば、どの様な候補があるのか、等が対話的に表示できる。
一般的に他人のプログラムは「詳細設計書はあるが、このプログラムは何が出来るのか?」が判らないので、この様なものが必要と思うが、如何だろうか。


PS C:\Users\doctor_d\Desktop> C:\Users\doctor_d\Desktop\1.ps1
コマンド パイプライン位置 1 のコマンドレット 1.ps1
次のパラメーターに値を指定してください:
(ヘルプを表示するには、「!?」と入力してください。)
Number: !?
Number のヘルプはありません。
Number: 1
String: !?
YesまたはNoを選択
String: Yes
1
Yes


2019-11-09

旧CITI bankがSMBCに売却されて、CITI GoldはPRESTIA Goldに継承された。

 ATMカードであるCITI CardはGLOBAL PASSという名称のDebit機能を持つATMカードに順次置き換えられる。
 機能面では国内ATM兼海外ATMカード兼Visa Debitとなるので、大幅改善である。

 しかしながら、この券面は如何なものか。

 GOLDというよりは、茶色。1色刷りのために安っぽさが感じられる。全くプレミアム感が無い。この手のカードは見易さを考えて、文字と地色のコントラストを高めにするのが多いが、現物のカードは茶色も薄めのためコピーし損ねたカードの様である。

 ANAマイレージGLOBAL PASSは多色刷りで、こちらの方がずっとデザインが良い。

 通常のPRESTIA GLOBAL PASSもAMEXのパチモノみたいで、SMBCのデザイン能力は本当に良く判らない。

2019-10-14

 プログラムはN-BasicとZ80のアセンブラしか判りません。

 そこでPowershellでログ管理のプログラムを作成していた時に変数のスコープではまったので備忘録。

 N-Basicでは変数はプログラムのどこでも同様の働きをするし、同一のものとして扱われる。しかしながら、Powershellでは動きが異なる。

 例えば以下の様に、変数Switchを$TRUEとして、この変数を$FALSEへ切り替える場合を考えてみよう。
 ここで、N-Basic的にはサブルーチンの様な、functionであるChangeSwitchを呼び出せば変数Switchが$Falseに切替できると思うのだが、挙動は異なる。

 冒頭の変数Switchとfunctionの中にある変数Switchは同じ名称でも異なるものなってしまうのだ。
 functionの中にある変数Switchはfunction内だけで有効な変数なので、functionから抜けた時にはfunctionの中の変更は反映されない。




[Param](
[Boolean]$Switch = $TRUE
 )

function ChangeSwitch{

$Switch = $FALSE

}




 それではどうするのか?
 以下の様に 変数のスコープを明示的にスクリプト内に指定する。




[Param](
[Boolean]$Switch = $TRUE
 )

function ChangeSwitch{

$Script:Switch = $FALSE

}




自己紹介

自分の写真
東京都, Japan
憂鬱な凍死家です。こちらではmixiとは異なり固めの話題中心です。

Total Page View

Categories

Powered by Blogger.

Popular Posts

Blog Archive