Menambahkan dukungan Kredensial ke fungsi PowerShell

Catatan

Versi asli artikel ini muncul di blog yang ditulis oleh @joshduffney. Artikel ini telah diedit untuk dimasukkan di situs ini. Tim PowerShell berterima kasih kepada Josh karena telah membagikan konten ini kepada kami. Silakan lihat blognya di duffney.io.

Artikel ini memperlihatkan kepada Anda cara menambahkan parameter kredensial ke fungsi PowerShell dan alasan yang Anda inginkan. Parameter kredensial adalah memungkinkan Anda menjalankan fungsi atau cmdlet sebagai pengguna yang berbeda. Penggunaan yang paling umum adalah menjalankan fungsi atau cmdlet sebagai akun pengguna yang ditingkatkan.

Misalnya, cmdlet New-ADUser memiliki parameter Kredensial , yang dapat Anda berikan kredensial admin domain untuk membuat akun di domain. Dengan asumsi akun normal Anda yang menjalankan sesi PowerShell belum memiliki akses tersebut.

Membuat objek kredensial

Objek PSCredential mewakili sekumpulan kredensial keamanan seperti nama pengguna dan kata sandi. Objek dapat diteruskan sebagai parameter ke fungsi yang berjalan sebagai akun pengguna di objek kredensial tersebut. Ada beberapa cara untuk membuat objek kredensial. Cara pertama untuk membuat objek kredensial adalah dengan menggunakan cmdlet Get-CredentialPowerShell . Saat Anda menjalankan tanpa parameter, itu meminta anda untuk nama pengguna dan kata sandi. Atau Anda dapat memanggil cmdlet dengan beberapa parameter opsional.

Untuk menentukan nama domain dan nama pengguna sebelumnya, Anda dapat menggunakan parameter Kredensial atau Nama Pengguna . Saat Anda menggunakan parameter UserName , Anda juga diharuskan untuk memberikan nilai Pesan . Kode di bawah ini menunjukkan menggunakan cmdlet . Anda juga dapat menyimpan objek kredensial dalam variabel sehingga Anda dapat menggunakan kredensial beberapa kali. Dalam contoh di bawah ini, objek kredensial disimpan dalam variabel $Cred.

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

Terkadang, Anda tidak dapat menggunakan metode interaktif untuk membuat objek kredensial yang ditunjukkan dalam contoh sebelumnya. Sebagian besar alat otomatisasi memerlukan metode non-interaktif. Untuk membuat kredensial tanpa interaksi pengguna, buat string aman yang berisi kata sandi. Kemudian teruskan string aman dan nama pengguna ke System.Management.Automation.PSCredential() metode .

Gunakan perintah berikut untuk membuat string aman yang berisi kata sandi:

ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force

Parameter AsPlainText dan Force diperlukan. Tanpa parameter tersebut, Anda menerima peringatan pesan bahwa Anda tidak boleh meneruskan teks biasa ke dalam string aman. PowerShell mengembalikan peringatan ini karena kata sandi teks biasa direkam dalam berbagai log. Setelah string aman dibuat, Anda perlu meneruskannya ke PSCredential() metode untuk membuat objek kredensial. Dalam contoh berikut, variabel $password berisi string $Cred aman berisi objek kredensial.

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

Sekarang setelah Anda tahu cara membuat objek kredensial, Anda dapat menambahkan parameter kredensial ke fungsi PowerShell Anda.

Menambahkan Parameter Kredensial

Sama seperti parameter lainnya, Anda memulai dengan menambahkannya di param blok fungsi Anda. Disarankan agar Anda memberi nama parameter $Credential karena itulah yang digunakan cmdlet PowerShell yang ada. Jenis parameter harus [System.Management.Automation.PSCredential].

Contoh berikut menunjukkan blok parameter untuk fungsi yang disebut Get-Something. Ini memiliki dua parameter: $Name dan $Credential.

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

Kode dalam contoh ini cukup untuk memiliki parameter kredensial yang berfungsi, namun ada beberapa hal yang dapat Anda tambahkan untuk membuatnya lebih kuat.

  • [ValidateNotNull()] Tambahkan atribut validasi untuk memeriksa apakah nilai yang diteruskan ke Kredensial. Jika nilai parameter null, atribut ini mencegah fungsi dijalankan dengan kredensial yang tidak valid.

  • Tambahkan [System.Management.Automation.Credential()]. Ini memungkinkan Anda untuk meneruskan nama pengguna sebagai string dan memiliki permintaan interaktif untuk kata sandi.

  • Atur nilai default untuk parameter ke $Credential[System.Management.Automation.PSCredential]::Empty. Fungsi Anda mungkin meneruskan objek ini $Credential ke cmdlet PowerShell yang ada. Memberikan nilai null ke cmdlet yang disebut di dalam fungsi Anda menyebabkan kesalahan. Menyediakan objek kredensial kosong menghindari kesalahan ini.

Tip

Beberapa cmdlet yang menerima parameter kredensial tidak mendukung [System.Management.Automation.PSCredential]::Empty sebagaimana mestinya. Lihat bagian Menangani Cmdlet Warisan untuk solusinya.

Menggunakan parameter kredensial

Contoh berikut menunjukkan cara menggunakan parameter kredensial. Contoh ini menunjukkan fungsi yang disebut Set-RemoteRegistryValue, yang berada di luar Buku Pester. Fungsi ini mendefinisikan parameter kredensial menggunakan teknik yang dijelaskan di bagian sebelumnya. Fungsi memanggil Invoke-Command menggunakan variabel yang $Credential dibuat oleh fungsi . Ini memungkinkan Anda untuk mengubah pengguna yang menjalankan Invoke-Command. Karena nilai $Credential default adalah kredensial kosong, fungsi dapat berjalan tanpa memberikan kredensial.

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
}

Bagian berikut menunjukkan metode yang berbeda untuk memberikan kredensial ke Set-RemoteRegistryValue.

Meminta kredensial

Menggunakan Get-Credential dalam tanda kurung () pada durasi menyebabkan Get-credential eksekusi terlebih dahulu. Anda dimintai nama pengguna dan kata sandi. Anda dapat menggunakan parameter Get-credentialKredensial atau Nama Pengguna untuk mengisi nama pengguna dan domain terlebih dahulu. Contoh berikut menggunakan teknik yang disebut splatting untuk meneruskan parameter ke Set-RemoteRegistryValue fungsi. Untuk informasi selengkapnya tentang percikan, lihat artikel about_Splatting .

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

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

Mendapatkan kredensial saat runtime

Menggunakan (Get-Credential) tampaknya rumit. Biasanya, ketika Anda menggunakan parameter Kredensial hanya dengan nama pengguna, cmdlet secara otomatis meminta kata sandi. Atribut [System.Management.Automation.Credential()] memungkinkan perilaku ini.

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

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney

Prompt untuk kredensial

Catatan

Untuk mengatur nilai registri yang diperlihatkan, contoh-contoh ini mengasumsikan Anda telah menginstal fitur Server Web Windows. Jalankan Install-WindowsFeature Web-Server dan Install-WindowsFeature web-mgmt-tools jika diperlukan.

Menyediakan kredensial dalam variabel

Anda juga dapat mengisi variabel kredensial sebelumnya dan meneruskannya ke parameter Set-RemoteRegistryValueKredensial fungsi. Gunakan metode ini dengan alat Integrasi Berkelanjutan /Penyebaran Berkelanjutan (CI/CD) seperti Jenkins, TeamCity, dan Octopus Deploy. Misalnya menggunakan Jenkins, lihat posting blog Hodge Mengotomatiskan dengan Jenkins dan PowerShell di Windows - Bagian 2.

Contoh ini menggunakan metode .NET untuk membuat objek kredensial dan string aman untuk meneruskan kata sandi.

$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

Untuk contoh ini, string aman dibuat menggunakan kata sandi teks yang jelas. Semua CI/CD yang disebutkan sebelumnya memiliki metode yang aman untuk menyediakan kata sandi tersebut pada durasi. Saat menggunakan alat tersebut, ganti kata sandi teks biasa dengan variabel yang ditentukan dalam alat CI/CD yang Anda gunakan.

Jalankan tanpa kredensial

Karena $Credential default ke objek kredensial kosong, Anda dapat menjalankan perintah tanpa kredensial, seperti yang ditunjukkan dalam contoh ini:

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

Set-RemoteRegistryValue @remoteKeyParams

Berurusan dengan cmdlet warisan

Tidak semua cmdlet mendukung objek kredensial atau mengizinkan kredensial kosong. Sebagai gantinya, cmdlet menginginkan parameter nama pengguna dan kata sandi sebagai string. Ada beberapa cara untuk mengatasi batasan ini.

Menggunakan if-else untuk menangani kredensial kosong

Dalam skenario ini, cmdlet yang ingin Anda jalankan tidak menerima objek kredensial kosong. Contoh ini menambahkan parameter Kredensial ke Invoke-Command hanya jika tidak kosong. Jika tidak, ia menjalankan Invoke-Command tanpa parameter Kredensial .

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
        }
    }
}

Menggunakan splatting untuk menangani kredensial kosong

Contoh ini menggunakan percikan parameter untuk memanggil cmdlet warisan. Objek $Credential ditambahkan secara kondisional ke tabel hash untuk splatting dan menghindari kebutuhan untuk mengulangi Invoke-Command blok skrip. Untuk mempelajari selengkapnya tentang splatting di dalam fungsi, lihat posting blog Splatting Parameters Inside Advanced Functions .

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
}

Bekerja dengan kata sandi string

Cmdlet Invoke-Sqlcmd adalah contoh cmdlet yang menerima string sebagai kata sandi. Invoke-Sqlcmd memungkinkan Anda menjalankan pernyataan penyisipan, pembaruan, dan penghapusan SQL sederhana. Invoke-Sqlcmd memerlukan nama pengguna dan kata sandi teks yang jelas daripada objek kredensial yang lebih aman. Contoh ini menunjukkan cara mengekstrak nama pengguna dan kata sandi dari objek kredensial.

Fungsi Get-AllSQLDatabases dalam contoh ini memanggil Invoke-Sqlcmd cmdlet untuk mengkueri server SQL untuk semua databasenya. Fungsi ini mendefinisikan parameter Kredensial dengan atribut yang sama yang digunakan dalam contoh sebelumnya. Karena nama pengguna dan kata sandi ada dalam variabel, Anda dapat mengekstrak nilai-nilai tersebut $Credential untuk digunakan dengan Invoke-Sqlcmd.

Nama pengguna tersedia dari properti UserName variabel $Credential . Untuk mendapatkan kata sandi, Anda harus menggunakan GetNetworkCredential() metode $Credential objek . Nilai diekstrak ke dalam variabel yang ditambahkan ke tabel hash yang digunakan untuk splatting parameter ke Invoke-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

Manajemen kredensial pembelajaran berkelanjutan

Membuat dan menyimpan objek kredensial dengan aman bisa sulit. Sumber daya berikut ini dapat membantu Anda mempertahankan kredensial PowerShell.