質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

コマンドプロンプト

コマンドプロンプト(cmd.exe)はMicrosoftによって提供されているコマンドラインインタプリタです。OS/2・Windows CE・Windows NTで使用可能です。

Q&A

解決済

1回答

6322閲覧

PowerShell_ISE で 書いたスクリプト がpowershell で実行したときに失敗する

kamikazelight

総合スコア305

PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

コマンドプロンプト

コマンドプロンプト(cmd.exe)はMicrosoftによって提供されているコマンドラインインタプリタです。OS/2・Windows CE・Windows NTで使用可能です。

0グッド

2クリップ

投稿2019/02/16 04:54

編集2019/02/20 02:36

ベストアンサー後のまとめ

原因

  • コンソールとISEで最初に読み込まれているアセンブリが異なる
  • Using NameSpace では アセンブリのロードは行われない
  • スクリプトファイルが同じ場合Add-TypeよりもClass等の定義が優先して読み込まれる
  • Class等の定義時 利用されている 型 等が読み込まれていないとエラーになる

対策

  • 最初に実行するスクリプトファイルで極力Add-Typeは済ませておく
  • 最初に実行するスクリプトファイルは(コンソールだと)Add-Typeが必要な型などは使わない(使えない)

コンソールだとロードされていないアセンブリの一括ロード
私の環境だと0.5~2秒ほどでそこまで時間はかからない

powershell

1Using NameSpace System.IO 2 3$asms = foreach ($asm in [System.AppDomain]::CurrentDomain.GetAssemblies()) { 4 $asm | ?{$asm.Location -ne $null} | Select-Object -Property @{N='Assembly';E={$asm.GetName().Name}}, Location -Unique 5} 6 7$asmsFile = "ISE_LoadAssemblies.csv" 8 9if ($Host.Name -eq "Windows PowerShell ISE Host") 10{ 11 $asms | Export-Csv -Path ".$asmsFile" -NoTypeInformation 12 Write-host "Assembly write complete" 13} 14else 15{ 16 if (-not (Test-Path -Path ".$asmsFile")) 17 { 18 Write-Host "ISEで実行されたことがありません。" 19 return 20 } 21 $ISEAssembly = Import-Csv -Path ".$asmsFile" 22 23 $LoadedAssembly = $asms | foreach { $_.Location } 24 25 $Diff = $ISEAssembly | ?{ -not $LoadedAssembly.Contains($_.Location) } 26 27 $Error.Clear() 28 $Diff | ?{[Path]::GetExtension($_.Location) -eq ".dll"} | Foreach { 29 $Path = $_.Location 30 try 31 { 32 Add-Type -Path $Path -ErrorAction SilentlyContinue 33 } 34 catch 35 { 36 Write-Host "失敗 : アセンブリ名 = $($_.Assembly) パス = $Path" -ForegroundColor Red 37 } 38 } 39 if ($Error.count -ne 0) 40 { 41 Write-Host "失敗数 : $($Error.count)" 42 } 43 44 Write-host "Assembly loading completed" 45}

前提・実現したいこと

PowerShell_iseで作成したスクリプト(ControlOperation.ps1)が
iseでは問題なく実行できるのに
Cmd? から PowerShell を使い実行すると
失敗します。

実行方法は
バッチファイル、又はショートカットに
powershell -noexit -NoLogo -ExecutionPolicy Bypass -File %0..\ControlOperation.ps1 %*
っと割り当てて実行しました。

どうしたらPowerShellで使えるようになるのでしょうか?教えて頂きたいです。
あと出来るならばどのNameSpace がAdd-Typeしないといけないのかエラーを見てから
以外の確認方法があれば教えて頂きたいです。
お願い致します。

発生している問題・エラーメッセージ

[Control]と[Point]の型が見つからないと出ます。

発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:20 文字:25 + [Void] SetLocation([Control] $Control, [Position] $Position, [Poi ... + ~~~~~~~ 型 [Control] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:20 文字:67 + ... SetLocation([Control] $Control, [Position] $Position, [Point] $Point ... + ~~~~~ 型 [Point] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:54 文字:10 + [Point]$OfPoint = [Point]::new($Width, $Height) + ~~~~~ 型 [Point] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:54 文字:28 + [Point]$OfPoint = [Point]::new($Width, $Height) + ~~~~~ 型 [Point] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:62 文字:6 + [Point] GetLocation([Control] $Control, [Position] $Position) + ~~~~~ 型 [Point] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:62 文字:26 + [Point] GetLocation([Control] $Control, [Position] $Position) + ~~~~~~~ 型 [Control] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:66 文字:10 + [Point]$Point = $Control.Location + ~~~~~ 型 [Point] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:97 文字:10 + [Point]$OfPoint = [Point]::new($Width, $Height) + ~~~~~ 型 [Point] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:97 文字:28 + [Point]$OfPoint = [Point]::new($Width, $Height) + ~~~~~ 型 [Point] が見つかりません。 発生場所 J:\PwshScript\ReuseScript\ControlOperation.ps1:105 文字:26 + [Void] SetGoldWidth([Control] $Control, [int] $Height) + ~~~~~~~ 型 [Control] が見つかりません。 報告されていない解析エラーもあります。報告されたエラーを修正して再試行してください。 + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : TypeNotFound

該当のソースコード

ControlOperation.ps1

poweshell

1<# 2 System.Windows.Forms の操作補助 3#> 4 5Using NameSpace System.Windows.Forms 6Using NameSpace System.Drawing 7 8Add-Type -AssemblyName System.Windows.Forms 9Add-Type -AssemblyName System.Drawing 10 11class ControlOperation 12{ 13 [Type]$Position = [Position] 14 [Type]$AnchorStyleEx = [AnchorStyleEx] 15 [Type]$Direction = [Direction] 16 17 <# 18 Position指定位置がPointになるように設定 19 #> 20 [Void] SetLocation([Control] $Control, [Position] $Position, [Point] $Point) 21 { 22 [int] $Width = $Control.Size.Width 23 [int] $Height = $Control.Size.Height 24 25 26 $XFull = @( 27 'TopLeft' 28 'MiddleLeft' 29 'BottomLeft' 30 ) 31 $YFull = @( 32 'TopLeft' 33 'TopCenter' 34 'TopRight' 35 ) 36 $XHerf = @( 37 'TopCenter' 38 'MiddleCenter' 39 'BottomCenter' 40 ) 41 $YHerf = @( 42 'MiddleLeft' 43 'MiddleCenter' 44 'MiddleRight' 45 ) 46 47 switch ([String]$Position) 48 { 49 {$_ -in $XFull} {$Width = 0} 50 {$_ -in $XHerf} {$Width *= 0.5} 51 {$_ -in $YFull} {$Height = 0} 52 {$_ -in $YHerf} {$Height *= 0.5} 53 } 54 [Point]$OfPoint = [Point]::new($Width, $Height) 55 $Control.Location = $Point - $OfPoint 56 } 57 58 59 <# 60 Position指定位置の座標を取得 61 #> 62 [Point] GetLocation([Control] $Control, [Position] $Position) 63 { 64 [int] $Width = $Control.Size.Width 65 [int] $Height = $Control.Size.Height 66 [Point]$Point = $Control.Location 67 68 69 $XFull = @( 70 'TopLeft' 71 'MiddleLeft' 72 'BottomLeft' 73 ) 74 $YFull = @( 75 'TopLeft' 76 'TopCenter' 77 'TopRight' 78 ) 79 $XHerf = @( 80 'TopCenter' 81 'MiddleCenter' 82 'BottomCenter' 83 ) 84 $YHerf = @( 85 'MiddleLeft' 86 'MiddleCenter' 87 'MiddleRight' 88 ) 89 90 switch ([String]$Position) 91 { 92 {$_ -in $XFull} {$Width = 0} 93 {$_ -in $XHerf} {$Width *= 0.5} 94 {$_ -in $YFull} {$Height = 0} 95 {$_ -in $YHerf} {$Height *= 0.5} 96 } 97 [Point]$OfPoint = [Point]::new($Width, $Height) 98 return ($Point + $OfPoint) 99 } 100 101 102 <# 103 高さと黄金比を基にサイズを設定 104 #> 105 [Void] SetGoldWidth([Control] $Control, [int] $Height) 106 { 107 [Double] $GoldenRatio = 1.618 108 109 [int] $Width = $Height * $GoldenRatio 110 111 [Size]$Size = [Size]::new($Width, $Height) 112 $Control.Size = $Size 113 } 114 115 [Size] Scale([Size] $Size, [Double] $Rate, [Direction] $Direction) 116 { 117 $Width = $Size.Width 118 $Height = $Size.Height 119 120 switch ([String]$Direction) 121 { 122 {$_ -in 'None','Vertical'} {$Height *= $Rate} 123 {$_ -in 'None','Horizontal'} {$Width *= $Rate} 124 } 125 126 $NSize = [Size]::new($Width, $Height) 127 return $NSize 128 } 129 [Size] Scale([Size] $Size, [Double] $Rate) 130 { 131 return $This.Scale([Size] $Size, [Double] $Rate, [Direction]::None) 132 } 133} 134 135Enum Position 136{ 137 TopLeft 138 TopCenter 139 TopRight 140 MiddleLeft 141 MiddleCenter 142 MiddleRight 143 BottomLeft 144 BottomCenter 145 BottomRight 146} 147 148Enum AnchorStyleEx 149{ 150 T = [AnchorStyles]::Top 151 L = [AnchorStyles]::Left 152 R = [AnchorStyles]::Right 153 B = [AnchorStyles]::Bottom 154 155 TL = [AnchorStyles]::Top + [AnchorStyles]::Left 156 TR = [AnchorStyles]::Top + [AnchorStyles]::Right 157 TB = [AnchorStyles]::Top + [AnchorStyles]::Bottom 158 LR = [AnchorStyles]::Left + [AnchorStyles]::Right 159 LB = [AnchorStyles]::Left + [AnchorStyles]::Bottom 160 RB = [AnchorStyles]::Right + [AnchorStyles]::Bottom 161 162 TLR = [AnchorStyles]::Top + [AnchorStyles]::Left + [AnchorStyles]::Right 163 TLB = [AnchorStyles]::Top + [AnchorStyles]::Left + [AnchorStyles]::Bottom 164 TRB = [AnchorStyles]::Top + [AnchorStyles]::Right + [AnchorStyles]::Bottom 165 LRB = [AnchorStyles]::Left + [AnchorStyles]::Right + [AnchorStyles]::Bottom 166 167 TLRB = [AnchorStyles]::Top + [AnchorStyles]::Left + [AnchorStyles]::Right + [AnchorStyles]::Bottom 168 169} 170 171Enum Direction 172{ 173 None 174 Vertical 175 Horizontal 176} 177 178 179return [ControlOperation]::new()

試したこと

他のスクリプトでも同じような問題があり
確認したところ
Using NameSpaceを使っていた場合 ise では問題なく実行できるが
PowerShell だと加えてAdd-Type -AssemblyNameも必要なことが分かったので
全てのスクリプトに書き加えた

そのあと再確認したところ
Add-Type -AssemblyNameが不要で指定すると逆にエラーになってしまうものもあることが分かったのでエラーを見ながらそれらは抜いた

他はそれで使えるようになったが何故か ControlOperation.ps1 だけは

powershell

1Add-Type -AssemblyName System.Windows.Forms 2Add-Type -AssemblyName System.Drawing

を加えてもエラーが消えず 新しいエラーも発生しなかった。

補足情報(FW/ツールのバージョンなど)

Win10
Powershell v5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Uning NameSpaceは有効になっていると思いますが、Add-Typeが実行されるよりも先にクラス定義が先に処理されるためエラーになります。
今回は、プロファイル($PROFILEで指定されるファイル)や、作成されるツールの前処理スクリプトを作るなどして、クラス定義をするスクリプト実行前にAdd-Typeしておくのが対応策になると思います。

とりあえず、Add-Type部分だけを別スクリプトに移動し、そのスクリプトから作成されたスクリプトを呼ぶようにしてエラー無く実行できることは確認しました。(結果が期待通りかまでは未確認)

PowerShell

1Add-Type -AssemblyName System.Windows.Forms 2Add-Type -AssemblyName System.Drawing 3& ".\ControlOperation.ps1"

私より詳しいと思いますので、ご存じかもしれませんが、一応、状況を確認した方法も。

PowerShell

1[System.AppDomain]::CurrentDomain.GetAssemblies() | % { $_.GetName().Name } | sort

起動後のISEで上記を実行すると、スクリプトでAdd-Typeしているアセンブリは、はじめからロード済みであることがわかります。

対して、PowerShellコンソールではロードされていません。では、スクリプトを実行した後はというと、やっぱりロードされていません。クラス定義の時点でエラーになり、その他のコードが実行されていません。

プロファイルは、PowerShellコンソールとISEだけでなく、その他のPowerShellツールも、それぞれ別に設定されるようなので、設定の際はご注意を。

投稿2019/02/16 06:46

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kamikazelight

2019/02/16 07:49 編集

今回もありがとうございます。 > とりあえず、Add-Type部分だけを別スクリプトに移動し、そのスクリプトから作成されたスクリプトを呼ぶようにしてエラー無く実行できることは確認しました。 こちらでも同様の結果でした。 期待していた動作です。 ですがファイルを分け無いといけないというのが何とも... スクリプトブロックにしてみたりしたのですがだめでした。 Enum とか クラス定義 の優先度はかなり高そうですね... やらないですが 私だと文字列にして 処理することしか案が浮かびませんでした。 後は同じようなスクリプトがあるのにそちらは問題にならなかったので見てみたのですが そちらは全て Add-Type いりませんでした。 ここで疑問がわいたのですが 例えば そのうちの一つに System.Runtime.InteropServices があるのですが こちらは教えて頂いた方法ではじめからロード済みのアセンブリを 見てもその中に見当たりません。 どこかの内訳として入っていたりするのでしょうか? そのあたりも 全くの無知なので出来れば教えて頂きたいです。 お願い致します。
imihito

2019/02/18 13:56

横から失礼します。 名前空間とアセンブリは1対1の関係では無く、多対多の関係でもOKです。 例えば`[System.Int32]`は`System`名前空間にありますが`mscorlib.dll`内に含まれています。 `[System.Uri]`も`System`名前空間にありますが、こちらは`System.dll`に含まれています。 型からアセンブリを辿ることはできますが、名前空間(例:System.Runtime.InteropServices)だけでは、どのアセンブリかわかりません。 型から辿りたい場合は、PowerShellであれば`[System.Runtime.InteropServices.Marshal].Assembly`のようにすると確認できます。 参考までに、lazybones2000さんの処理をベースに名前空間とアセンブリを出力するスクリプトです。 ```ps1 $(foreach ($asm in [System.AppDomain]::CurrentDomain.GetAssemblies()) { $asm.GetTypes() | ?{$_.IsPublic} | Select-Object -Property @{N='Assembly';E={$asm.GetName().Name}}, NameSpace -Unique }) | Format-Table -AutoSize ```
kamikazelight

2019/02/19 04:45

ありがとうございます。 教えて頂いた方法でISE Hostでロードされていて Console Host ではロードされない NameSpace を見てみたのですが GUI 系が多いなというのは 分かったのですが 140程あって 覚えられそうになかったので ISEで確認時は動作したのに使おうと思ったら動作しないトラブル回避のために ISEでの実行時に読み込まれているアセンブリを記録して Console 実行時に記録されているアセンブリのうち読み込まれていないもののみ自動で ロードしてしまおうと思ったのですが 私の環境ではConsoleHost では読まれていない アセンブリ 20 のうち 4つ 1.MetadataViewProxies_745b6766-9dfb-4447-8ea8-222a2a724382 2.Microsoft.GeneratedCode 3.PresentationFramework.Aero2 4.Windows.UI がAdd-Type -AssemblyName で失敗します。 それぞれ調べてみたのですがどれも解決策が分からず 上記2つはなんの用途に使うのかもわかりませんでした。 なぜ ロードできないのでしょうか?
imihito

2019/02/19 12:34

上二つはアセンブリ名から予想するに、動的に生成したコードが含まれているオンメモリのアセンブリ(ファイルとして存在しないアセンブリ)だと思われます(Locationも空文字列)。 また、`Add-Type -AssemblyName `はある程度アセンブリを自動探索してくれますが、探索範囲外のものは`-AssemblyName`指定で読み込めません。今回では`PresentationFramework.Aero2`が該当します。 Windows.UIに関しては.winmdという拡張子になっており、パス指定でも読み込めませんでした。こちらはUWP関連のものみたいなので、普段使うことは少ないかとは思いますが…
kamikazelight

2019/02/20 01:35

上記2つは 何が起こるか分かりませんが 直ちに問題は出なさそうなので 一先ず諦めることにします。 `PresentationFramework.Aero2`は教えて頂いた通り Add-Type -Pass で読み込み可能なことが 確認できました。 Add-Type -Pass の存在を今回初めて知りました。 Windows.UI は使っている人がいたので https://nyanshiba.hatenablog.com/entry/2018/03/16/014246 試してみたらAdd-type 無しで ConsoleHostでも動作しました。 そこで Add-Type -AssemblyNam ではなく Add-Type -Pass を使い Locationが存在して尚且つ拡張子がdllのもの のみインポート? してみたのですが うまくいきました。 すごく高評価ボタンを押したいのですが コメントなので押せませんね 別の質問にすればよかったかもしれないですね.... コードは一応 軽く書いたものを後で載せたいと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問