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

ทำไมตัวจับเวลาจึงเป็นทริกเกอร์ที่ผิด

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

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

คู่เหตุการณ์ และตัวที่ต้องระงับ

ไคลเอนต์ของ Remote Access Service เขียนบันทึกวงจรชีวิตลงในบันทึก Application ภายใต้ผู้ให้บริการ RasClient โดย 20226 หมายถึงการเชื่อมต่อที่จบลง และ 20227 หมายถึงความพยายามที่ล้มเหลว ทั้งสองจึงใช้ยืนยันการโทรใหม่ได้ ทุกอย่างที่เหลือในงานขึ้นอยู่กับการจับคู่ตัวระบุทั้งสองให้ตรงเป๊ะ ตัวระบุเหล่านี้คงที่มาหลายปี สูตรที่สร้างบนตัวระบุเหล่านี้จึงยังแพร่หลายอยู่ แต่บิลด์ที่เปลี่ยนชื่อผู้ให้บริการหรือตัวระบุจะทำให้คิวรีไม่คืนอะไรเลย ให้รันขั้นตอนพิสูจน์ซ้ำหลังการอัปเดตฟีเจอร์ทุกครั้ง แทนที่จะรอให้งานหยุดทำงาน

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

Get-WinEvent -LogName Application -MaxEvents 5 -FilterXPath "*[System[Provider[@Name='RasClient'] and EventID=20226]]" | Select-Object -First 1 -ExpandProperty ToXml

XML แสดงชื่อของ Data ที่ตรงเป๊ะในบันทึกนั้น ErrorCode คือการสะกดตามปกติ และบันทึกที่ใช้อย่างอื่นต้องแทนที่ชื่อนั้นในตัวกรองด้านล่าง

<QueryList><Query Id="0" Path="Application"><Select Path="Application">*[System[Provider[@Name='RasClient'] and (EventID=20226 or EventID=20227)]] and (EventData[Data[@Name='ErrorCode'] != '631'] or System[EventID=20227])</Select></Query></QueryList>

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

Get-WinEvent -LogName Application -MaxEvents 40 -FilterXPath "*[System[Provider[@Name='RasClient'] and (EventID=20226 or EventID=20227)]] and (EventData[Data[@Name='ErrorCode'] != '631'] or System[EventID=20227])" | Select-Object TimeCreated,Id,Message

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

การโทรล้มเหลวเพราะไม่มีใครพิมพ์รหัสผ่าน

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

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

rasdial
rasdial "Office VPN"
(Start-Process rasdial -ArgumentList '"Office VPN"' -Wait -PassThru -NoNewWindow).ExitCode

คำสั่งแรกแสดงรายชื่อที่ Windows รู้จัก คำสั่งที่สองโทรตามชื่อโดยใช้ข้อมูลรับรองที่แคชไว้ และคำสั่งที่สามคือรูปแบบที่การกระทำของ PowerShell ควรใช้ เพราะมันรอและคืนค่าที่งานบันทึกได้

อ่านรหัสออกแทนที่จะดูหน้าต่าง

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

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

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

พิสูจน์เส้นทางการกู้คืน

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

จากนั้นอ่านประวัติงานแทนที่จะดูไอคอนการเชื่อมต่อ ประวัติบันทึกว่างานรันเมื่อใด ใช้บัญชีใด และการกระทำคืนค่าอะไร และนั่นคือหลักฐานที่ต้องใช้เมื่อเครื่องเดิมล่มอีกในเดือนหน้า

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