كيفية استخدام المعلمات -Verbose و -debug بشكل صحيح
-
29-09-2019 - |
سؤال
بشكل افتراضي ، تقبل أي وظيفة تسمي بها سمة [cmdletbinding ()] -debug و -verbose (وعدد قليل من الآخرين) ولديها متغيرات $ المحددة و $ idbose. ما أحاول اكتشافه هو كيفية نقلها إلى CMDLT الأخرى التي يتم استدعاؤها في الوظيفة.
دعنا نقول أن لدي cmdlet مثل هذا:
function DoStuff() {
[CmdletBinding()]
PROCESS {
new-item Test -type Directory
}
}
إذا -debug
أو -verbose
تم تمريره إلى وظيفتي ، أريد نقل هذا العلم إلى new-item
cmdlet. ما هو النمط الصحيح للقيام بذلك؟
المحلول
ربما يبدو الأمر غريبًا ولكن لا توجد طريقة سهلة ل CMDLT لمعرفة وضع المطوّل أو التصحيح. ألق نظرة على السؤال ذي الصلة:
كيف يعرف cmdlet متى يجب أن يتصل حقًا بالكتابة ()؟
واحد غير مثالي ولكنه معقول من الناحية العملية هو تقديم معلمات cmdlet الخاصة بك (على سبيل المثال $MyVerbose
, $MyDebug
) واستخدامها في الكود بشكل صريح.
function DoStuff {
[CmdletBinding()]
param
(
# unfortunately, we cannot use Verbose name with CmdletBinding
[switch]$MyVerbose
)
process {
if ($MyVerbose) {
# do verbose stuff
}
# pass $MyVerbose in the cmdlet explicitly
New-Item Test -Type Directory -Verbose:$MyVerbose
}
}
DoStuff -MyVerbose
تحديث
عندما نحتاج فقط إلى مفتاح (لا ، على سبيل المثال ، قيمة مستوى الفعل) ثم النهج مع $PSBoundParameters
ربما يكون أفضل من المقترح أعلاه معلمات إضافية:
function DoStuff {
[CmdletBinding()]
param()
process {
if ($PSBoundParameters['Verbose']) {
# do verbose stuff
}
New-Item Test -Type Directory -Verbose:($PSBoundParameters['Verbose'] -eq $true)
}
}
DoStuff -Verbose
كل شيء ليس مثاليًا على أي حال. إذا كانت هناك حلول أفضل ، فأود حقًا أن أعرفهم بنفسي.
نصائح أخرى
$PSBoundParameters
ليس ما تبحث عنه. استخدام [CmdletBinding()]
السمة تسمح باستخدام $PSCmdlet
ضمن البرنامج النصي الخاص بك ، بالإضافة إلى توفير علامة مطوّلة. في الواقع هذا هو نفس المطالبة التي من المفترض أن تستخدمها.
خلال [CmdletBinding()]
, ، يمكنك الوصول إلى المعلمات المربوطة من خلال $PSCmdlet.MyInvocation.BoundParameters
. فيما يلي وظيفة تستخدم cmdletbinding وتدخل ببساطة مطالبة متداخلة على الفور من أجل فحص المتغيرات المتاحة داخل نطاق الوظيفة.
PS D:\> function hi { [CmdletBinding()]param([string] $Salutation) $host.EnterNestedPrompt() }; hi -Salutation Yo -Verbose
PS D:\>>> $PSBoundParameters
____________________________________________________________________________________________________
PS D:\>>> $PSCmdlet.MyInvocation.BoundParameters
Key Value
--- -----
Salutation Yo
Verbose True
لذلك في مثالك ، تريد ما يلي:
function DoStuff `
{
[CmdletBinding()]
param ()
process
{
new-item Test -type Directory `
-Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true)
}
}
هذا يغطي -Verbose ، -Verbose: $ false ، -Verbose: $ true ، والحالة التي يكون فيها المفتاح غير موجود على الإطلاق.
لا حاجة لذلك. PowerShell يفعل هذا بالفعل كما يثبت الرمز أدناه.
function f { [cmdletbinding()]Param()
"f is called"
Write-Debug Debug
Write-Verbose Verbose
}
function g { [cmdletbinding()]Param()
"g is called"
f
}
g -Debug -Verbose
الإخراج هو
g is called
f is called
DEBUG: Debug
VERBOSE: Verbose
لم يتم ذلك مباشرة مثل تمرير -debug إلى cmdlet التالي رغم ذلك. يتم ذلك من خلال $ debugpreference ومتغيرات $ verbrosepreference. تتصرف الكتابة والكتابة والكتابة كما تتوقع ، ولكن إذا كنت ترغب في القيام بشيء مختلف مع التصحيح أو المطالبة يمكنك القراءة هنا كيفية التحقق من نفسك.
مع خطر الإحياء والخيط القديم. هذا هو الحل.
function DoStuff {
[CmdletBinding()]
param ()
BEGIN
{
$CMDOUT=@{
Verbose=If ($PSBoundParameters.Verbose -eq $true) { $true } else { $false };
Debug=If ($PSBoundParameters.Debug -eq $true) { $true } else { $false }
}
} # BEGIN ENDS
PROCESS
{
New-Item Example -ItemType Directory @CMDOUT
} # PROCESS ENDS
END
{
} #END ENDS
}
ما يفعله هذا مختلف عن الأمثلة الأخرى هو أنه سوف يطرح "verbose: $ false" أو "-debug: $ false". سيتم تعيين verbose/-debug فقط على $ true إذا كنت تستخدم ما يلي:
DoStuff -Verbose
DoStuff -Verbose:$true
DoStuff -Debug
DoStuff -Debug:$true
يمكنك إنشاء جدول تجزئة جديد استنادًا إلى معلمات التصحيح أو المطوّل المرتبط ثم قم بتثبيته إلى الأمر الداخلي. إذا كنت تحدد فقط المفاتيح (ولم تقم بتمرير مفتاح خاطئ ، مثل $ debug: $ false) ، يمكنك فقط التحقق من وجود تصحيح أو مطوّل:
function DoStuff() {
[CmdletBinding()]
PROCESS {
$HT=@{Verbose=$PSBoundParameters.ContainsKey'Verbose');Debug=$PSBoundParameters.ContainsKey('Debug')}
new-item Test -type Directory @HT
}
}
إذا كنت ترغب في تمرير قيمة المعلمة ، فستكون أكثر تعقيدًا ، ولكن يمكن القيام بها مع:
function DoStuff {
[CmdletBinding()]
param()
PROCESS {
$v,$d = $null
if(!$PSBoundParameters.TryGetValue('Verbose',[ref]$v)){$v=$false}
if(!$PSBoundParameters.TryGetValue('Debug',[ref]$d)){$d=$false}
$HT=@{Verbose=$v;Debug=$d}
new-item Test -type Directory @HT
}
}
أفضل طريقة للقيام بذلك هي عن طريق ضبط $VerbosePreference
. سيمكن هذا المستوى المطول للنص بأكمله. لا تنسى تعطيله بنهاية النص.
Function test
{
[CmdletBinding()]
param( $param1)
if($psBoundParameters['verbose'])
{
$VerbosePreference = "Continue"
Write-verbose " Verbose mode is on"
}
else
{
$VerbosePreference = "SilentlyContinue"
Write-verbose " Verbose mode is Off"
}
<<your code>>
}
يمكنك تعيين FerboSepreference كمتغير عالمي في بدء البرنامج النصي الخاص بك ثم التحقق من المتغير العالمي في CMDLET المخصص.
النصي:
$global:VerbosePreference = $VerbosePreference
Your-CmdLet
لك cmdlet:
if ($global:VerbosePreference -eq 'Continue') {
# verbose code
}
يتيح التحقق بشكل صريح لـ "متابعة" البرنامج النصي مساوياً له -verbose:$false
عندما تتصل بـ cmdlet من البرنامج النصي الذي لا يضبط المتغير العالمي (وفي هذه الحالة يكون الأمر كذلك $null
)
أعتقد أن هذه هي أسهل طريقة:
Function Test {
[CmdletBinding()]
Param (
[parameter(Mandatory=$False)]
[String]$Message
)
Write-Host "This is INFO message"
if ($PSBoundParameters.debug) {
Write-Host -fore cyan "This is DEBUG message"
}
if ($PSBoundParameters.verbose) {
Write-Host -fore green "This is VERBOSE message"
}
""
}
Test -Verbose -Debug