โฮมเพจ » ทำอย่างไร » วิธีใช้ไฟล์แบตช์เพื่อสร้างสคริปต์ PowerShell ให้ทำงานง่ายขึ้น

    วิธีใช้ไฟล์แบตช์เพื่อสร้างสคริปต์ PowerShell ให้ทำงานง่ายขึ้น

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

    ทำไมฉันไม่สามารถคัดลอกไฟล์. PS1 ของฉันไปยังคอมพิวเตอร์เครื่องอื่นแล้วเรียกใช้?

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

    1. PowerShell ไม่เกี่ยวข้องกับนามสกุลไฟล์. PS1 ตามค่าเริ่มต้น.
      เรานำสิ่งนี้มาเริ่มแรกในซีรี่ส์ PowerShell Geek School ของเรา Windows จะเชื่อมโยงไฟล์. PS1 ไปยัง Notepad ตามค่าเริ่มต้นแทนที่จะส่งไปยังตัวแปลคำสั่ง PowerShell เพื่อป้องกันการเรียกใช้สคริปต์ที่เป็นอันตรายโดยไม่ตั้งใจเพียงคลิกสองครั้งที่สคริปต์เหล่านั้น มีหลายวิธีที่คุณสามารถเปลี่ยนพฤติกรรมนี้ได้ แต่อาจไม่ใช่สิ่งที่คุณต้องการจะทำในคอมพิวเตอร์ทุกเครื่องที่คุณถือสคริปต์ไปโดยเฉพาะถ้าคอมพิวเตอร์บางเครื่องไม่ใช่ของคุณเอง.
    2. PowerShell ไม่อนุญาตการเรียกใช้สคริปต์ภายนอกตามค่าเริ่มต้น.
      การตั้งค่า ExecutionPolicy ใน PowerShell ป้องกันการเรียกใช้สคริปต์ภายนอกโดยค่าเริ่มต้นใน Windows ทุกรุ่น ใน Windows บางรุ่นค่าเริ่มต้นไม่อนุญาตให้มีการเรียกใช้สคริปต์เลย เราแสดงวิธีเปลี่ยนการตั้งค่านี้ในวิธีอนุญาตให้ใช้งานสคริปต์ PowerShell ใน Windows 7 อย่างไรก็ตามนี่เป็นสิ่งที่คุณไม่ต้องการทำบนคอมพิวเตอร์ทุกเครื่อง.
    3. สคริปต์ PowerShell บางตัวจะไม่ทำงานหากไม่ได้รับอนุญาตจากผู้ดูแลระบบ.
      แม้จะใช้งานกับบัญชีระดับผู้ดูแลระบบคุณยังคงต้องผ่านการควบคุมบัญชีผู้ใช้ (UAC) เพื่อดำเนินการบางอย่าง เราไม่ต้องการปิดใช้งานสิ่งนี้ แต่ก็ยังดีเมื่อเราสามารถทำให้จัดการได้ง่ายขึ้น.
    4. ผู้ใช้บางคนอาจมีสภาพแวดล้อม PowerShell ที่กำหนดเอง.
      คุณอาจจะไม่เจอกับสิ่งนี้บ่อยครั้ง แต่เมื่อคุณทำมันจะทำให้การรันและการแก้ไขปัญหาสคริปต์ของคุณน่าผิดหวังเล็กน้อย โชคดีที่เราสามารถแก้ไขได้โดยไม่ต้องทำการเปลี่ยนแปลงอย่างถาวรเช่นกัน.

    ขั้นตอนที่ 1: ดับเบิลคลิกเพื่อเรียกใช้.

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

    ดังนั้นเราไม่จำเป็นต้องเขียนไฟล์แบตช์ใหม่สำหรับทุกสคริปต์หรือทุกครั้งที่เราย้ายสคริปต์ไปรอบ ๆ มันจะใช้ประโยชน์จากตัวแปรอ้างอิงตนเองเพื่อสร้างพา ธ ไฟล์สำหรับสคริปต์ PowerShell ในการทำให้งานนี้ไฟล์แบตช์จะต้องอยู่ในโฟลเดอร์เดียวกันกับสคริปต์ PowerShell ของคุณและมีชื่อไฟล์เดียวกัน ดังนั้นหากสคริปต์ PowerShell ของคุณชื่อ“ MyScript.ps1” คุณจะต้องตั้งชื่อไฟล์แบตช์ของคุณ“ MyScript.bat” และตรวจสอบให้แน่ใจว่ามันอยู่ในโฟลเดอร์เดียวกัน จากนั้นใส่บรรทัดเหล่านี้ในแบทช์สคริปต์:

    @ECHO OFF PowerShell.exe - คำสั่ง "& '% ~ dpn0.ps1'" หยุดชั่วคราว

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

    @ECHO OFF ปิดคำสั่ง echoing สิ่งนี้จะป้องกันไม่ให้คำสั่งอื่นของคุณแสดงบนหน้าจอเมื่อไฟล์แบตช์ทำงาน บรรทัดนี้ถูกซ่อนอยู่โดยใช้สัญลักษณ์ at (@) ที่อยู่ด้านหน้า.

    PowerShell.exe - รับคำสั่ง“ & '% ~ dpn0.ps1'” เรียกใช้สคริปต์ PowerShell แน่นอนว่า PowerShell.exe สามารถเรียกใช้จากหน้าต่าง CMD หรือไฟล์แบตช์ใดก็ได้เพื่อเปิด PowerShell ไปยังคอนโซลเปล่าเหมือนปกติ คุณยังสามารถใช้เพื่อเรียกใช้คำสั่งโดยตรงจากแบตช์ไฟล์โดยรวมถึงพารามิเตอร์ -Command และอาร์กิวเมนต์ที่เหมาะสม วิธีนี้ใช้เพื่อกำหนดเป้าหมายไฟล์. PS1 ของเราด้วยตัวแปร% ~ dpn0 พิเศษ เรียกใช้จากแฟ้มแบตช์% ~ dpn0 ประเมินเป็นอักษรชื่อไดรฟ์พา ธ โฟลเดอร์และชื่อไฟล์ (ไม่มีส่วนขยาย) ของไฟล์แบตช์ เนื่องจากแบตช์ไฟล์และสคริปต์ PowerShell จะอยู่ในโฟลเดอร์เดียวกันและมีชื่อเดียวกัน% ~ dpn0.ps1 จะแปลเป็นพา ธ ไฟล์แบบเต็มของสคริปต์ PowerShell.

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

    ดังนั้นไฟล์แบตช์พื้นฐานจะถูกติดตั้ง เพื่อการสาธิตไฟล์นี้จะถูกบันทึกเป็น“ D: \ Script Lab \ MyScript.bat” และมี“ MyScript.ps1” ในโฟลเดอร์เดียวกัน มาดูกันว่าจะเกิดอะไรขึ้นเมื่อเราดับเบิลคลิก MyScript.bat.

    เห็นได้ชัดว่าสคริปต์ PowerShell ไม่ได้ทำงาน แต่คาดว่าจะเกิดขึ้นเราได้ทำการแก้ไขปัญหาแรกของเราแล้วเท่านั้น อย่างไรก็ตามมีบางส่วนที่สำคัญแสดงให้เห็นถึงที่นี่:

    1. ชื่อหน้าต่างแสดงให้เห็นว่าสคริปต์ชุดงานเปิดตัว PowerShell ได้สำเร็จ.
    2. บรรทัดแรกของเอาต์พุตแสดงว่ามีการใช้โปรไฟล์ PowerShell แบบกำหนดเอง นี่คือปัญหาที่อาจเกิดขึ้น # 4 ที่ระบุไว้ข้างต้น.
    3. ข้อความแสดงข้อผิดพลาดแสดงให้เห็นถึงข้อ จำกัด ExecutionPolicy ที่มีผลบังคับใช้ นั่นคือปัญหาของเรา # 2.
    4. ส่วนที่ขีดเส้นใต้ของข้อความแสดงข้อผิดพลาด (ซึ่งทำโดยกำเนิดจากข้อผิดพลาดของ PowerShell) แสดงว่าชุดสคริปต์ได้อย่างถูกต้องกำหนดเป้าหมายสคริปต์ PowerShell ที่ตั้งใจ (D: \ Script Lab \ MyScript.ps1) อย่างน้อยเราก็รู้ว่าส่วนมากทำงานได้ดี.

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

    เขียนผลลัพธ์ 'โปรไฟล์ PowerShell ที่กำหนดเองมีผล!'

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

    เพิ่มเนื้อหา -Path 'D: \ Script Lab \ MyScript.ps1' - ค่า "[ZoneTransfer] 'nZoneId = 3" - สตรีม' Zone.Identifier '

    ที่ตั้งค่ากระแสข้อมูลสำรอง Zone.Identifier บน MyScript.ps1 เพื่อให้ Windows คิดว่าไฟล์นั้นมาจากอินเทอร์เน็ต มันสามารถย้อนกลับได้อย่างง่ายดายด้วยคำสั่งต่อไปนี้:

    ล้างเนื้อหา -Path 'D: \ Script Lab \ MyScript.ps1' - สตรีม 'Zone.Identifier'

    ขั้นตอนที่ 2: รู้จัก ExecutionPolicy.

    การหลีกเลี่ยงการตั้งค่า ExecutionPolicy จาก CMD หรือสคริปต์ชุดเป็นเรื่องง่ายมาก เราเพิ่งแก้ไขบรรทัดที่สองของสคริปต์เพื่อเพิ่มพารามิเตอร์อีกหนึ่งพารามิเตอร์ลงในคำสั่ง PowerShell.exe.

    PowerShell.exe - ExecutionPolicy Bypass -Command "& '% ~ dpn0.ps1'"

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

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

    ถ้า (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity] :: GetCurrent ()). IsInRole ([Security.Principal.WindowsBuiltInRole] "ผู้ดูแลระบบ")) เขียนเอาท์พุท 'ทำงานเป็นผู้ดูแลระบบ!' อื่น ๆ เขียน - เอาท์พุท 'Running Limited!' หยุดชั่วคราว

    คุณจะสังเกตเห็นว่าขณะนี้มีการดำเนินการ“ หยุดชั่วคราว” สองครั้งในเอาต์พุตสคริปต์ - อีกอันหนึ่งจากสคริปต์ PowerShell และอีกไฟล์หนึ่งจากแบตช์ไฟล์ เหตุผลนี้จะชัดเจนมากขึ้นในขั้นตอนต่อไป.

    ขั้นตอนที่ 3: การเข้าถึงของผู้ดูแลระบบ.

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

    น่าเสียดายที่ไม่มีวิธีการกระตุ้น UAC สำหรับการยกระดับจากภายในแบตช์ไฟล์หรือเซสชัน CMD อย่างไรก็ตาม PowerShell ทำให้เราสามารถทำสิ่งนี้ได้ด้วย Start-Process เมื่อใช้กับ“ -Verb RunAs” ในการโต้แย้ง Start-Process จะพยายามเปิดแอปพลิเคชันที่มีสิทธิ์ผู้ดูแลระบบ หากเซสชัน PowerShell ยังไม่ได้รับการยกระดับสิ่งนี้จะทริกเกอร์พรอมต์ UAC ในการใช้สิ่งนี้จากไฟล์แบตช์สำหรับเปิดตัวสคริปต์ของเราเราจะวางไข่กระบวนการ PowerShell สองกระบวนการ - อันหนึ่งเพื่อเริ่มกระบวนการเริ่มต้นและอีกกระบวนการหนึ่งเริ่มจากกระบวนการเริ่มต้นเพื่อเรียกใช้สคริปต์ บรรทัดที่สองของไฟล์แบตช์ต้องเปลี่ยนเป็น:

    PowerShell.exe - บังคับ "& เริ่มกระบวนการ PowerShell.exe -ArgumentList '- ExecutionPolicy Bypass - ไฟล์" "% ~ dpn0.ps1" "-Verb RunAs"

    เมื่อเรียกใช้ไฟล์แบตช์บรรทัดแรกของเอาต์พุตที่เราจะเห็นคือจากสคริปต์โปรไฟล์ PowerShell จากนั้นจะมีพรอมต์ UAC เมื่อ Start-Process พยายามเปิด MyScript.ps1.

    หลังจากคลิกผ่านพรอมต์ UAC อินสแตนซ์ PowerShell ใหม่จะวางไข่ เพราะนี่เป็นตัวอย่างใหม่แน่นอนเราจะเห็นการแจ้งเตือนสคริปต์โปรไฟล์อีกครั้ง จากนั้น MyScript.ps1 จะทำงานและเราเห็นว่าเราอยู่ในช่วงการยกระดับ.

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

    ขั้นตอนที่ 4: ดูโปรไฟล์ PowerShell ที่กำหนดเอง.

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

    PowerShell.exe -NoProfile -Command "& เริ่มต้นกระบวนการ PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File" "% ~ dpn0.ps1" "-Verb RunAs"

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

    หากคุณไม่ต้องการสิทธิ์ผู้ดูแลระบบในสคริปต์ PowerShell ของคุณและคุณข้ามขั้นตอนที่ 3 คุณสามารถทำได้โดยไม่มีอินสแตนซ์ PowerShell ที่สองและบรรทัดที่สองของไฟล์แบตช์ของคุณควรมีลักษณะดังนี้:

    PowerShell.exe -NoProfile -ExecutionPolicy Bypass - คำสั่ง "& '% ~ dpn0.ps1'"

    ผลลัพธ์จะมีลักษณะดังนี้:

    (แน่นอนว่าสำหรับสคริปต์ที่ไม่ใช่ผู้ดูแลระบบคุณสามารถทำได้โดยไม่ต้องหยุดสคริปต์ตอนท้ายในสคริปต์ PowerShell ของคุณที่จุดนี้เช่นกันเนื่องจากทุกสิ่งถูกจับในหน้าต่างคอนโซลเดียวกันและจะหยุดอยู่ตรงนั้นในตอนท้ายของ ไฟล์แบตช์ต่อไป)

    ไฟล์แบตช์ที่เสร็จสมบูรณ์.

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

    ไม่มีการเข้าถึงของผู้ดูแลระบบ:

    @ECHO OFF PowerShell.exe -NoProfile - ExecutionPolicy Bypass - คำสั่ง "& '% ~ dpn0.ps1'" หยุดชั่วคราว

    ด้วยการเข้าถึงของผู้ดูแลระบบ:

    @ECHO OFF PowerShell.exe -NoProfile - คำสั่ง "& เริ่มกระบวนการ PowerShell.exe -ArgumentList '-NoProfile - ExecutionPolicy Bypass - ไฟล์" "% ~ dpn0.ps1" "-Verb RunAs"

    อย่าลืมวางไฟล์แบตช์ไว้ในโฟลเดอร์เดียวกันกับสคริปต์ PowerShell ที่คุณต้องการใช้และตั้งชื่อเดียวกัน จากนั้นไม่ว่าคุณจะใช้ระบบไฟล์ใดคุณจะสามารถเรียกใช้สคริปต์ PowerShell ได้โดยไม่ต้องยุ่งกับการตั้งค่าความปลอดภัยใด ๆ ในระบบ คุณสามารถทำการเปลี่ยนแปลงเหล่านั้นได้ด้วยตนเองทุกครั้ง แต่การทำเช่นนี้จะช่วยคุณประหยัดปัญหานั้นและคุณไม่ต้องกังวลกับการคืนค่าการเปลี่ยนแปลงในภายหลัง.


    อ้างอิง:

    • การเรียกใช้สคริปต์ PowerShell จากไฟล์แบตช์ - บล็อกการเขียนโปรแกรมของ Daniel Schroeder
    • กำลังตรวจสอบสิทธิ์ผู้ดูแลระบบใน PowerShell - เฮ้ Scripting Guy! บล็อก