سؤال

بشكل افتراضي ، تقبل أي وظيفة تسمي بها سمة [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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top