ค้นหาเว็บไซต์

เพิ่มการสนับสนุนข้อมูลรับรองให้กับฟังก์ชัน PowerShell


บันทึก

ต้นฉบับของบทความนี้ปรากฏบนบล็อกที่เขียนโดย @joshduffney บทความนี้ได้รับการแก้ไขเพื่อรวมไว้ในไซต์นี้ ทีม PowerShell ขอขอบคุณ Josh สำหรับการแบ่งปันเนื้อหานี้กับเรา โปรดตรวจสอบบล็อกของเขาที่ duffney.io

บทความนี้จะแสดงวิธีเพิ่มพารามิเตอร์ข้อมูลประจำตัวให้กับฟังก์ชัน PowerShell และเหตุผลที่คุณต้องการ พารามิเตอร์ข้อมูลรับรองคือการอนุญาตให้คุณเรียกใช้ฟังก์ชันหรือ cmdlet ในฐานะผู้ใช้อื่น การใช้งานทั่วไปมากที่สุดคือการเรียกใช้ฟังก์ชันหรือ cmdlet เป็นบัญชีผู้ใช้ที่มีการยกระดับ

ตัวอย่างเช่น cmdlet New-ADUser มีพารามิเตอร์ ข้อมูลรับรอง ซึ่งคุณสามารถระบุข้อมูลรับรองผู้ดูแลระบบโดเมนเพื่อสร้างบัญชีในโดเมนได้ สมมติว่าบัญชีปกติของคุณที่ใช้งานเซสชัน PowerShell ไม่มีสิทธิ์เข้าถึงนั้น

การสร้างวัตถุหนังสือรับรอง

ออบเจ็กต์ PSCredential แสดงถึงชุดข้อมูลรับรองความปลอดภัย เช่น ชื่อผู้ใช้และรหัสผ่าน วัตถุสามารถส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันที่ทำงานเป็นบัญชีผู้ใช้ในวัตถุข้อมูลประจำตัวนั้น คุณสามารถสร้างออบเจ็กต์หนังสือรับรองได้หลายวิธี วิธีแรกในการสร้างออบเจ็กต์ข้อมูลประจำตัวคือการใช้ PowerShell cmdlet Get-Credential เมื่อคุณทำงานโดยไม่มีพารามิเตอร์ ระบบจะขอให้คุณระบุชื่อผู้ใช้และรหัสผ่าน หรือคุณสามารถเรียก cmdlet ด้วยพารามิเตอร์ทางเลือกบางอย่างได้

หากต้องการระบุชื่อโดเมนและชื่อผู้ใช้ล่วงหน้า คุณสามารถใช้พารามิเตอร์ ข้อมูลประจำตัว หรือ ชื่อผู้ใช้ เมื่อคุณใช้พารามิเตอร์ ชื่อผู้ใช้ คุณจะต้องระบุค่า ข้อความ ด้วย รหัสด้านล่างสาธิตการใช้ cmdlet คุณยังสามารถจัดเก็บออบเจ็กต์หนังสือรับรองในตัวแปรเพื่อให้คุณสามารถใช้ข้อมูลรับรองได้หลายครั้ง ในตัวอย่างด้านล่าง ออบเจ็กต์ข้อมูลรับรองจะถูกจัดเก็บไว้ในตัวแปร $Cred

$Cred = Get-Credential
$Cred = Get-Credential -Credential domain\user
$Cred = Get-Credential -UserName domain\user -Message 'Enter Password'

บางครั้ง คุณไม่สามารถใช้วิธีการโต้ตอบในการสร้างออบเจ็กต์ข้อมูลรับรองที่แสดงในตัวอย่างก่อนหน้านี้ได้ เครื่องมืออัตโนมัติส่วนใหญ่ต้องการวิธีการแบบไม่โต้ตอบ หากต้องการสร้างข้อมูลรับรองโดยไม่ต้องโต้ตอบกับผู้ใช้ ให้สร้างสตริงที่ปลอดภัยที่มีรหัสผ่าน จากนั้นส่งสตริงที่ปลอดภัยและชื่อผู้ใช้ไปยังเมธอด System.Management.Automation.PSCredential()

ใช้คำสั่งต่อไปนี้เพื่อสร้างสตริงที่ปลอดภัยที่มีรหัสผ่าน:

ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force

ต้องใช้ทั้งพารามิเตอร์ AsPlainText และ Force หากไม่มีพารามิเตอร์เหล่านั้น คุณจะได้รับข้อความเตือนว่าคุณไม่ควรส่งข้อความธรรมดาไปยังสตริงที่ปลอดภัย PowerShell ส่งคืนคำเตือนนี้เนื่องจากรหัสผ่านข้อความธรรมดาได้รับการบันทึกในบันทึกต่างๆ เมื่อคุณสร้างสตริงที่ปลอดภัยแล้ว คุณจะต้องส่งผ่านไปยังเมธอด PSCredential() เพื่อสร้างออบเจ็กต์ข้อมูลรับรอง ในตัวอย่างต่อไปนี้ ตัวแปร $password มีสตริงที่ปลอดภัย $Cred มีวัตถุหนังสือรับรอง

$password = ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ("username", $password)

ตอนนี้คุณรู้วิธีสร้างออบเจ็กต์หนังสือรับรองแล้ว คุณสามารถเพิ่มพารามิเตอร์หนังสือรับรองให้กับฟังก์ชัน PowerShell ของคุณได้

การเพิ่มพารามิเตอร์ข้อมูลรับรอง

เช่นเดียวกับพารามิเตอร์อื่นๆ คุณเริ่มต้นด้วยการเพิ่มลงในบล็อก param ของฟังก์ชันของคุณ ขอแนะนำให้คุณตั้งชื่อพารามิเตอร์ $Credential เนื่องจากนั่นคือสิ่งที่ PowerShell cmdlets ที่มีอยู่ใช้ ประเภทของพารามิเตอร์ควรเป็น [System.Management.Automation.PSCredential]

ตัวอย่างต่อไปนี้แสดงบล็อกพารามิเตอร์สำหรับฟังก์ชันที่เรียกว่า Get-Something มีพารามิเตอร์สองตัว: $Name และ $Credential

function Get-Something {
    param(
        $Name,
        [System.Management.Automation.PSCredential]$Credential
    )

โค้ดในตัวอย่างนี้เพียงพอที่จะมีพารามิเตอร์ข้อมูลประจำตัวที่ใช้งานได้ อย่างไรก็ตาม มีบางสิ่งที่คุณสามารถเพิ่มเพื่อให้มีประสิทธิภาพมากขึ้น

  • เพิ่มแอตทริบิวต์การตรวจสอบ [ValidateNotNull()] เพื่อตรวจสอบว่าค่าถูกส่งไปที่ ข้อมูลรับรอง หากค่าพารามิเตอร์เป็น null แอ็ตทริบิวต์นี้จะป้องกันไม่ให้ฟังก์ชันดำเนินการด้วยข้อมูลรับรองที่ไม่ถูกต้อง

  • เพิ่ม [System.Management.Automation.Credential()] วิธีนี้ช่วยให้คุณสามารถส่งชื่อผู้ใช้เป็นสตริงและมีพร้อมท์โต้ตอบสำหรับรหัสผ่าน

  • ตั้งค่าเริ่มต้นสำหรับพารามิเตอร์ $Credential เป็น [System.Management.Automation.PSCredential]::Empty ฟังก์ชันของคุณที่คุณอาจส่งผ่านออบเจ็กต์ $Credential นี้ไปยัง PowerShell cmdlets ที่มีอยู่ การระบุค่า Null ให้กับ cmdlet ที่ถูกเรียกภายในฟังก์ชันของคุณทำให้เกิดข้อผิดพลาด การระบุออบเจ็กต์ข้อมูลรับรองที่ว่างเปล่าจะหลีกเลี่ยงข้อผิดพลาดนี้

คำแนะนำที่เป็นประโยชน์

cmdlet บางตัวที่ยอมรับพารามิเตอร์ข้อมูลประจำตัวไม่สนับสนุน [System.Management.Automation.PSCredential]::Empty ตามที่ควร ดูส่วนการจัดการกับ Cmdlets ดั้งเดิมสำหรับวิธีแก้ปัญหา

การใช้พารามิเตอร์หนังสือรับรอง

ตัวอย่างต่อไปนี้สาธิตวิธีการใช้พารามิเตอร์ข้อมูลรับรอง ตัวอย่างนี้แสดงฟังก์ชันชื่อ Set-RemoteRegistryValue ซึ่งไม่ได้อยู่ใน The Pester Book ฟังก์ชันนี้กำหนดพารามิเตอร์ข้อมูลรับรองโดยใช้เทคนิคที่อธิบายไว้ในส่วนก่อนหน้า ฟังก์ชันเรียกใช้ Invive-Command โดยใช้ตัวแปร $Credential ที่สร้างโดยฟังก์ชัน ซึ่งช่วยให้คุณสามารถเปลี่ยนผู้ใช้ที่กำลังเรียกใช้ Inrigg-Command เนื่องจากค่าเริ่มต้นของ $Credential เป็นข้อมูลประจำตัวที่ว่างเปล่า ฟังก์ชันจึงสามารถทำงานได้โดยไม่ต้องระบุข้อมูลประจำตัว

function Set-RemoteRegistryValue {
    param(
        $ComputerName,
        $Path,
        $Name,
        $Value,
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )
        $null = Invoke-Command -ComputerName $ComputerName -ScriptBlock {
            Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
        } -Credential $Credential
}

ส่วนต่อไปนี้แสดงวิธีการต่างๆ ในการให้ข้อมูลประจำตัวแก่ Set-RemoteRegistryValue

แจ้งขอหนังสือรับรอง

การใช้ Get-Credential ในวงเล็บ () ในขณะรันไทม์จะทำให้ Get-credential รันก่อน คุณได้รับพร้อมท์ให้ใส่ชื่อผู้ใช้และรหัสผ่าน คุณสามารถใช้พารามิเตอร์ ข้อมูลรับรอง หรือ ชื่อผู้ใช้ ของ Get-credential เพื่อเติมชื่อผู้ใช้และโดเมนล่วงหน้า ตัวอย่างต่อไปนี้ใช้เทคนิคที่เรียกว่า splatting เพื่อส่งพารามิเตอร์ไปยังฟังก์ชัน Set-RemoteRegistryValue สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ Splatting โปรดดูบทความ about_Splatting

$remoteKeyParams = @{
    ComputerName = $env:COMPUTERNAME
    Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
    Name = 'EnableRemoteManagement'
    Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential (Get-Credential)

การใช้ (Get-Credential) ดูยุ่งยาก โดยปกติ เมื่อคุณใช้พารามิเตอร์ ข้อมูลประจำตัว กับชื่อผู้ใช้เท่านั้น cmdlet จะถามรหัสผ่านโดยอัตโนมัติ แอตทริบิวต์ [System.Management.Automation.Credential()] เปิดใช้งานลักษณะการทำงานนี้

$remoteKeyParams = @{
    ComputerName = $env:COMPUTERNAME
    Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
    Name = 'EnableRemoteManagement'
    Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney

บันทึก

หากต้องการตั้งค่ารีจิสทรีที่แสดง ตัวอย่างเหล่านี้จะถือว่าคุณได้ติดตั้งคุณลักษณะ เว็บเซิร์ฟเวอร์ ของ Windows แล้ว เรียกใช้ Install-WindowsFeature Web-Server และ Install-WindowsFeature web-mgmt-tools หากจำเป็น

ระบุข้อมูลรับรองในตัวแปร

คุณยังสามารถเติมตัวแปรข้อมูลรับรองล่วงหน้าและส่งผ่านไปยังพารามิเตอร์ ข้อมูลรับรอง ของฟังก์ชัน Set-RemoteRegistryValue ใช้วิธีนี้กับเครื่องมือการผสานรวมอย่างต่อเนื่อง/การปรับใช้อย่างต่อเนื่อง (CI/CD) เช่น Jenkins, TeamCity และ Octopus Deploy สำหรับตัวอย่างการใช้ Jenkins โปรดดูบล็อกโพสต์ของ Hodge การทำอัตโนมัติด้วย Jenkins และ PowerShell บน Windows - ตอนที่ 2

ตัวอย่างนี้ใช้เมธอด .NET เพื่อสร้างออบเจ็กต์หนังสือรับรองและสตริงที่ปลอดภัยเพื่อส่งผ่านรหัสผ่าน

$password = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ("duffney", $password)

$remoteKeyParams = @{
    ComputerName = $env:COMPUTERNAME
    Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
    Name = 'EnableRemoteManagement'
    Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential $Cred

สำหรับตัวอย่างนี้ สตริงที่ปลอดภัยจะถูกสร้างขึ้นโดยใช้รหัสผ่านข้อความที่ชัดเจน CI/CD ที่กล่าวถึงก่อนหน้านี้ทั้งหมดมีวิธีการที่ปลอดภัยในการระบุรหัสผ่านนั้นในขณะดำเนินการ เมื่อใช้เครื่องมือเหล่านั้น ให้แทนที่รหัสผ่านข้อความธรรมดาด้วยตัวแปรที่กำหนดไว้ภายในเครื่องมือ CI/CD ที่คุณใช้

ดำเนินการโดยไม่มีหนังสือรับรอง

เนื่องจาก $Credential มีค่าเริ่มต้นเป็นออบเจ็กต์ข้อมูลรับรองที่ว่างเปล่า คุณจึงสามารถรันคำสั่งได้โดยไม่ต้องมีข้อมูลรับรอง ดังที่แสดงในตัวอย่างนี้:

$remoteKeyParams = @{
    ComputerName = $env:COMPUTERNAME
    Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
    Name = 'EnableRemoteManagement'
    Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams

การจัดการกับ cmdlets ดั้งเดิม

cmdlet ของทั้งหมดไม่สนับสนุนวัตถุข้อมูลประจำตัวหรืออนุญาตให้ข้อมูลประจำตัวว่างเปล่า cmdlet ต้องการพารามิเตอร์ชื่อผู้ใช้และรหัสผ่านเป็นสตริงแทน มีหลายวิธีในการแก้ไขข้อจำกัดนี้

การใช้ if-else เพื่อจัดการข้อมูลประจำตัวที่ว่างเปล่า

ในสถานการณ์สมมตินี้ cmdlet ที่คุณต้องการเรียกใช้ไม่ยอมรับวัตถุข้อมูลประจำตัวที่ว่างเปล่า ตัวอย่างนี้เพิ่มพารามิเตอร์ ข้อมูลประจำตัว ให้กับ Inrigger-Command เฉพาะในกรณีที่ไม่ว่างเปล่า มิฉะนั้น จะรัน Inrigger-Command โดยไม่มีพารามิเตอร์ Credential

function Set-RemoteRegistryValue {
    param(
        $ComputerName,
        $Path,
        $Name,
        $Value,
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    if($Credential -ne [System.Management.Automation.PSCredential]::Empty) {
        Invoke-Command -ComputerName:$ComputerName -Credential:$Credential  {
            Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
        }
    } else {
        Invoke-Command -ComputerName:$ComputerName {
            Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
        }
    }
}

การใช้ splatting เพื่อจัดการข้อมูลประจำตัวที่ว่างเปล่า

ตัวอย่างนี้ใช้การแบ่งพารามิเตอร์เพื่อเรียก cmdlet ดั้งเดิม ออบเจ็กต์ $Credential จะถูกเพิ่มอย่างมีเงื่อนไขไปยังตารางแฮชเพื่อการแบ่งแยก และหลีกเลี่ยงความจำเป็นในการบล็อกสคริปต์ Inrigger-Command ซ้ำ หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการแบ่งส่วนภายในฟังก์ชัน โปรดดูโพสต์บล็อกการแบ่งส่วนพารามิเตอร์ภายในฟังก์ชันขั้นสูง

function Set-RemoteRegistryValue {
    param(
        $ComputerName,
        $Path,
        $Name,
        $Value,
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

        $Splat = @{
            ComputerName = $ComputerName
        }

        if ($Credential -ne [System.Management.Automation.PSCredential]::Empty) {
            $Splat['Credential'] = $Credential
        }

        $null = Invoke-Command -ScriptBlock {
            Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
        } @splat
}

การทำงานกับรหัสผ่านสตริง

Invoke-Sqlcmd cmdlet เป็นตัวอย่างของ cmdlet ที่ยอมรับสตริงเป็นรหัสผ่าน Invivo-Sqlcmd ช่วยให้คุณสามารถเรียกใช้คำสั่ง SQL แทรก อัปเดต และลบคำสั่งง่ายๆ ได้ Invivo-Sqlcmd ต้องใช้ชื่อผู้ใช้และรหัสผ่านที่เป็นข้อความที่ชัดเจน แทนที่จะเป็นวัตถุข้อมูลรับรองที่ปลอดภัยกว่า ตัวอย่างนี้แสดงวิธีแยกชื่อผู้ใช้และรหัสผ่านจากออบเจ็กต์ข้อมูลรับรอง

ฟังก์ชัน Get-AllSQLDatabases ในตัวอย่างนี้เรียก cmdlet Invoke-Sqlcmd เพื่อสอบถามเซิร์ฟเวอร์ SQL สำหรับฐานข้อมูลทั้งหมด ฟังก์ชันนี้จะกำหนดพารามิเตอร์ ข้อมูลรับรอง ด้วยแอตทริบิวต์เดียวกันกับที่ใช้ในตัวอย่างก่อนหน้านี้ เนื่องจากชื่อผู้ใช้และรหัสผ่านมีอยู่ในตัวแปร $Credential คุณจึงสามารถแยกค่าเหล่านั้นเพื่อใช้กับ Intake-Sqlcmd ได้

ชื่อผู้ใช้สามารถดูได้จากคุณสมบัติ ชื่อผู้ใช้ ของตัวแปร $Credential หากต้องการรับรหัสผ่าน คุณต้องใช้เมธอด GetNetworkCredential() ของออบเจ็กต์ $Credential ค่าจะถูกแยกออกเป็นตัวแปรที่เพิ่มลงในตารางแฮชที่ใช้สำหรับการแบ่งพารามิเตอร์เป็น Intake-Sqlcmd

function Get-AllSQLDatabases {
    param(
        $SQLServer,
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

        $UserName = $Credential.UserName
        $Password = $Credential.GetNetworkCredential().Password

        $splat = @{
            UserName = $UserName
            Password = $Password
            ServerInstance = 'SQLServer'
            Query = "Select * from Sys.Databases"
        }

        Invoke-Sqlcmd @splat
}

$credSplat = @{
    TypeName = 'System.Management.Automation.PSCredential'
    ArgumentList = 'duffney',('P@ssw0rd' | ConvertTo-SecureString -AsPlainText -Force)
}
$Credential = New-Object @credSplat

Get-AllSQLDatabases -SQLServer SQL01 -Credential $Credential

การจัดการข้อมูลรับรองการเรียนรู้อย่างต่อเนื่อง

การสร้างและจัดเก็บออบเจ็กต์หนังสือรับรองอย่างปลอดภัยอาจเป็นเรื่องยาก แหล่งข้อมูลต่อไปนี้สามารถช่วยคุณรักษาข้อมูลประจำตัวของ PowerShell ได้

  • BetterCredentials
  • Azure Key Vault
  • โครงการห้องนิรภัย
  • โมดูลการจัดการความลับ

บทความที่เกี่ยวข้อง