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

2020-06-25


 以下は勘違いでした。
 Windows PowerShell Compatibilityを導入済みであった事を失念していました。

----
 PowerShell Coreになってから、Windows OSに依存するcmd-letが削除されている。MSの資料によればWrite-EventLogも削除されていたのだが、7.0.2で再度利用可能になっていた。
 自作スクリプト集でログ出力用途で使用しており、Core系ではNLogによる再実装を検討していたが、不要になりそう。

PowerShell 7.0.2
Copyright (c) Microsoft Corporation. All rights reserved.

https://aka.ms/powershell
Type 'help' to get help.

PS C:\Users\doctor_d> get-help write-eventlog

NAME
    Write-EventLog

SYNTAX
    Write-EventLog [-LogName] [-Source] [-EventId] [[-EntryType] {Error | Information | Failure
    Audit | SuccessAudit | Warning}] [-Message] []


ALIASES
    なし


REMARKS
    Get-Help を実行しましたが、このコンピューターにこのコマンドレットのヘルプ ファイルは見つかりませんでした。ヘルプの
    一部だけが表示されています。
        -- このコマンドレットを含むモジュールのヘルプ ファイルをダウンロードしてインストールするには、Update-Help を使
    用してください。
        -- このコマンドレットのヘルプ トピックをオンラインで確認するには、「Get-Help Write-EventLog -Online」と入力する
    か、
           https://go.microsoft.com/fwlink/?LinkID=135281 を参照してください。


PS C:\Users\doctor_d>

2020-05-20

 謎事象のメモ。

 Get-ChildItemでUNCパスを指定。
 ISEから実行すると、結果取得可能。
 JP1から実行すると、パスが無いとエラー。(正確には出力結果をout-fileでリダイレクトして観察)JP1から明示的に64bit PowerShellを起動しても同一結果。

 以下を参照して、直前でcd c:としてみたが、結果は同一。

 JP1での実行ユーザはlocal administrator権限を持つ。

 追記。

 上記の.ps1を起動する.batを作成。

 手動で.batを起動すると、結果取得可能。
 JP1から.batを起動すると、 パスが無いとエラー。

 ユーザ権限の問題の様である。

2020-05-09

GitHubにてFileMaintenance version 2.0.1をリリースしました。

Destinationのスペルがコメントと出力メッセージでtypoしていました。が変数名では正しくなっていた....。

2020-04-24


 テレビでも良く宣伝をしている某社が納品したPowerShellスクリプトで凄いbugを発見。
 どうも作成者はWindows外部コマンドとPowerShell cmdletとを等価に扱っている様で、cmdletのファイル削除エラーを$LASTEXITCODEで拾えると思ったらしい。他の個所のWindows外部コマンド.exe起動後エラー判定も、同一処理としている。

 ErrorActionPreferenceは設定されていないので、この処理でエラーが発生すると一般的にはContinueされて#エラー判定 以降に進むのだがエラーがキャッチされる事は無い。

 PowerShellではエラーをtry{} catch[exception]{}で判定する必要があるのだが、他のスクリプトにも一切出現していない事から見て、根本的な理解誤りの様だ。
 cmdletで実際にエラーを起こすのは難しい場面もあるが、テストを良く通過したなと思った。
  この会社の「お任せあれ」は怪しいな。

 なお、筆者ならファイルの属性変更して削除できなくしてわざとエラーを起こす等でテストします。
  

  Get-ChildItem $Logs -Recurse -include *.log | Where-object{((Get-Date) – $_.LastWriteTime).Days(後略)   
    #エラー判定
    if($LASTEXITCODE -ne 0)
    {
        "正常に終了しました。"

2020-04-18

PS C:\WINDOWS\system32> Find-PackageProvider
警告: URI 'https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409' から '' へダウンロードできません。
警告: 利用可能なプロバイダーの一覧をダウンロードできません。インターネット接続を確認してください。

1. Open Powershell (As Admin)
2. [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
3. Try it again!


https://answers.microsoft.com/en-us/windows/forum/windows_7-performance/trying-to-install-program-using-powershell-and/4c3ac2b2-ebd4-4b2a-a673-e283827da143

2020-04-06

 現在作成中のFileMaintenaceで備忘録。

 PowerShellは変数の型指定は必須ではない。が、判読性の観点で極力型指定をしていた。functionのParam()で[Boolean]指定時の留意点。


 FileMaintenanceではfunctionの呼び出しで呼び出し毎に引数を全て指定していない。スクリプト全体で指定しているもの(定数と考えて良い)は、上位のスコープから落ちてくるのでParamで特段指定をする必要がないため。
 しかしながらfunctionの判読性の観点では何が入力になっているのかが判る方が良い。そのため、スクリプト全体用に定義しているものは以下例で言うところの$GlobalSwitch,$GlobalValueの様に引数として必須ではないが、定数として使用しているのが判りやすい様に記述してみた。


 ここで、[int]は良いのだが、[Boolean]に落とし穴がある。[Boolean]は$NULLを許容しないので、値を定義していないとエラーになってしまう。$TRUE,$FALSE,数値のみを受け入れる。
 特定の状況のみで必要なフラグなどでは未定義状態の場合があるため、これは問題である。仕方がないので、[Boolean]だけは型指定をしない実装としておく、


Param(
[String]$Name ,

[int]$GlobalValue = $GlobalValue
[Boolean]$GlobalSwitch = $GlobalSwitch
)

2020-03-29

 プログラム歴を振り返ると、太古の時代に触れたPC-8001に搭載されていてたN-BASICとZ80のアセンブラが原体験である。その後長年に渡ってプログラミングと縁は殆ど無かったのである。
 大学時代にFORTRANの授業はあったが、体系的に勉強した訳ではない。

 その経歴を踏まえると、現代に生きる筆者がオブジェクト指向を理解せずにPowerShellでプログラミングしても誰が責めようか。

 そして、何となくオブジェクト指向の存在に気付き、GitHubで公開中のFileMaintenanceの致命的な基本設計ミスが遂に修正された。今まで対象ファイル(フォルダ)の処理ループ内では対象をパス文字列として扱っていたのであるが、これをオブジェクトとして各種パス情報はオブジェクトのプロパティとして取り出す事にした。
 今にして見返せば、お手本では正しくオブジェクト指向で設計実装されていたのだが、理解不測の筆者は何故かパスのStringだけを取り出して処理する実装をしていたという馬鹿さ加減に先日までの自分を殴ってやりたい気分である。

 OOPの深淵にちょっとだけ近づいた!

2020-02-13

 プログラミングはN-BASICとZ80アセンブラしか経験が無いのですが、数十年ぶりにPowerShellを習得。ログメンテナンススクリプトを作成してみた。
 いろいろあって、当初は職場向けを想定していたのだが、全社的にこの手のものをメンテナンスする体制が無い、品質保証を考慮してApache License 2.0でGit Hubへ公開とした。

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-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-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