PowerShell推荐的编码风格是什么?

有没有推荐的编码风格如何编写PowerShell脚本? 这不是关于如何构造代码(有多lessfunction,如果使用模块,…)。 这是关于“ 如何编写代码,使其可读 ”。

在编程语言中,有一些推荐的编码风格 (什么缩进 ,如何缩进 – 空格/制表符,在哪里做新行 ,放置花括号 ,…),但我还没有看到任何PowerShell的build议。

我特别感兴趣的是:


如何写参数

function New-XYZItem ( [string] $ItemName , [scriptblock] $definition ) { ... 

(我发现它更像'V1'语法)或者

 function New-PSClass { param([string] $ClassName ,[scriptblock] $definition )... 

或(为什么要添加空的属性?)

 function New-PSClass { param([Parameter()][string] $ClassName ,[Parameter()][scriptblock] $definition )... 

或者(我在Jaykul的代码中看到的其他格式)

 function New-PSClass { param( [Parameter()] [string] $ClassName , [Parameter()] [scriptblock] $definition )... 

要么 ..?


如何编写复杂的pipe道

 Get-SomeData -param1 abc -param2 xyz | % { $temp1 = $_ 1..100 | % { Process-somehow $temp1 $_ } } | % { Process-Again $_ } | Sort-Object -desc 

或(新行cmdlet的名称)

 Get-SomeData -param1 abc -param2 xyz | % { $temp1 = $_ 1..100 | % { Process-somehow $temp1 $_ } } | % { Process-Again $_ } | Sort-Object -desc | 

以及如果有开始 – 进程 – 结束参数? 如何使它最可读?

 Get-SomeData -param1 abc -param2 xyz | % -begin { init } -process { Process-somehow2 ... } -end { Process-somehow3 ... } | % -begin { } .... 

要么

 Get-SomeData -param1 abc -param2 xyz | % ` -begin { init } ` -process { Process-somehow2 ... } ` -end { Process-somehow3 ... } | % -begin { } .... 

这里的重要性是重要的,什么元素也被放在新的行中。


我只经常提到我所想到的问题。 还有一些其他的,但我想保持这个“短”的问题。

欢迎任何其他build议。

花了几年时间,深入到Powershell v2.0深入了解,这就是我已经解决:

 <# .SYNOPSIS Cmdlet help is awesome. Autogenerate via template so I never forget. .DESCRIPTION .PARAMETER .PARAMETER .INPUTS .OUTPUTS .EXAMPLE .EXAMPLE .LINK #> function Get-Widget { [CmdletBinding()] param ( # Think about which params users might loop over. If there is a clear # favorite (80/20 rule), make it ValueFromPipeline and name it InputObject. [parameter(ValueFromPipeline=$True)] [alias("Server")] [string]$InputObject, # All other loop candidates are marked pipeline-able by property name. Use Aliases to ensure the most # common objects users want to feed in will "just work". [parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$True)] [alias("FullName")] [alias("Path")] [string[]]$Name, # Provide & document defaults for optional params whenever possible. [parameter(Position=1)] [int]$Minimum = 0, [parameter(Position=2)] [int]$ComputerName = "localhost", # Stick to standardized parameter names when possible. *Especially* with switches. Use Aliases to support # domain-specific terminology and/or when you want to expose the parameter name of the .Net API you're wrapping. [parameter()] [Alias("IncludeFlibbles")] [switch]$All, ) # The three main function blocks use this format if & only if they are short one-liners begin { $buf = new-list string } # Otherwise they use spacing comparable to a C# method process { # Likewise, control flow statements have a special style for one-liners try { # Side Note: internal variables (which may be inherited from a parent scope) # are lowerCamelCase. Direct parameters are UpperCamelCase. if ($All) { $flibbles = $Name | Get-Flibble } elseif ($Minimum -eq 0) { $flibbles = @() } else { return } $path = $Name | ? { $_.Length -gt $Minimum } | % { $InputObject.InvokeGetAPI($_, $flibbles) } | ConvertTo-FullPath } finally { Cleanup } # In general, though, control flow statements also stick to the C# style guidelines while($true) { Do-Something if ($true) { try { Do-Something Do-Something $buf.Add("abc") } catch { Do-Something Do-Something } } } } } <# Pipelines are a form of control flow, of course, and in my opinion the most important. Let's go into more detail. I find my code looks more consistent when I use the pipeline to nudge all of Powershell's supported language constructs (within reason) toward an "infix" style, regardless of their legacy origin. At the same time, I get really strict about avoiding complexity within each line. My style encourages a long, consistent "flow" of command-to-command-to-command, so we can ensure ample whitespace while remaining quite compact for a .Net language. Note - from here on out I use aliases for the most common pipeline-aware cmdlets in my stable of tools. Quick extract from my "meta-script" module definition: sal ?? Invoke-Coalescing sal ?: Invoke-Ternary sal im Invoke-Method sal gpv Get-PropertyValue sal spv Set-PropertyValue sal tp Test-Path2 sal so Select-Object2 sal eo Expand-Object % and ? are your familiar friends. Anything else that begins with a ? is a pseudo-infix operator autogenerated from the Posh syntax reference. #> function PipelineExamples { # Only the very simplest pipes get to be one-liners: $profileInfo = dir $profile | so @{Path="fullname"; KBs={$_.length/1kb}} $notNull = $someString | ?? "" $type = $InputObject -is [Type] | ?: $InputObject $InputObject.GetType() $ComObject | spv Enabled $true $foo | im PrivateAPI($param1, $param2) if ($path | tp -Unc) { Do-Something } # Any time the LHS is a collection (ie we're going to loop), the pipe character ends the line, even # when the expression looks simple. $verySlowConcat = "" $buf | % { $verySlowConcat += $_ } # Always put a comment on pipelines that have uncaptured output [destined for the caller's pipeline] $buf | ? { $_ -like "*a*" } # Multi-line blocks inside a pipeline: $orders | ? { $_.SaleDate -gt $thisQuarter -and ($_ | Get-Customer | Test-Profitable) -and $_.TastesGreat -and $_.LessFilling } | so Widgets | % { if ($ReviewCompetition) { $otherFirms | Get-Factory | Get-ManufactureHistory -Filter $_ | so HistoryEntry.Items.Widgets } else { $_ } } | Publish-WidgetReport -Format HTML # Mix COM, reflection, native commands, etc seamlessly $flibble = Get-WmiObject SomethingReallyOpaque | spv AuthFlags 0xf -PassThru | im Put() -PassThru | gpv Flibbles | select -first 1 # The coalescing operator is particularly well suited to this sort of thing $initializeMe = $OptionalParam | ?? $MandatoryParam.PropertyThatMightBeNullOrEmpty | ?? { pwd | Get-Something -Mode Expensive } | ?? { throw "Unable to determine your blahblah" } $uncFolderPath = $someInput | Convert-Path -ea 0 | ?? $fallback { tp -Unc -Folder } # String manipulation $myName = "First{0} Last{1} " | ?+ "Suffix{2}" | ?replace "{", ": {" | ?f {eo richard berg jr | im ToUpper} # Math algorithms written in this style start to approach the elegance of functional languages $weightedAvg = $values | Linq-Zip $weights {$args[0] * $args[1]} | Linq-Sum | ?/ ($weights | Linq-Sum) } # Don't be afraid to define helper functions. Thanks to the script:Name syntax, you don't have to cram them into # the begin{} block or anything like that. Name, params, etc don't always need to follow the cmdlet guidelines. # Note that variables from outer scopes are automatically available. (even if we're in another file!) function script:Cleanup { $buf.Clear() } # In these small helpers where the logic is straightforward and the correct behavior well known, I occasionally # condense the indentation to something in between the "one liner" and "Microsoft C# guideline" styles filter script:FixComputerName { if ($ComputerName -and $_) { # handle UNC paths if ($_[1] -eq "\") { $uncHost = ($_ -split "\\")[2] $_.Replace($uncHost, $ComputerName) } else { $drive = $_[0] $pathUnderDrive = $_.Remove(0,3) "\\$ComputerName\$drive`$\$pathUnderDrive" } } else { $_ } } 

哎呀,这比我预期的要长。 希望你想要的答案在那里:)

编辑 – StackOverflow的语法荧光笔完全放弃了我。 将其粘贴到ISE中。

我最近在PowerShell中遇到了有关缩进样式的优点 。 正如链接的评论所述,观察这些相同的语法之间的区别:

 1..10 | Sort-Object { -$_ } 

 1..10 | Sort-Object { -$_ } 

虽然我的意图是“像罗马人一样做”,并使用标准的C#缩进样式( Allman ,或多或less),但我对这个例外以及与之类似的其他问题持有异议。

这使我个人倾向于使用我喜欢的1TBS ,但我可以说服其他方面。 出于好奇,你是如何解决的?

为了logging,还有“PowerShell最佳实践和风格指南” 。

这是远远不够官方,但有几个好点。

我知道这是一个老问题,但唐琼斯12 PowerShell的最佳实践 。 通过阅读这12个最佳实践,我已经将我的脚本提高了100%。 之前他们真的很糟糕。 特别糟糕。 慢慢清理起来。