استكشاف المشكلات المتعلقة بعامل Log Analytics لنظام التشغيل Windows وإصلاحها

توفر هذه المقالة المساعدة في استكشاف الأخطاء وإصلاحها التي قد تواجهها مع عامل Log Analytics ل Windows في Azure Monitor وتقترح الحلول الممكنة لحلها.

أداة استكشاف الأخطاء وإصلاحها في Log Analytics

عامل Log Analytics لأداة استكشاف الأخطاء وإصلاحها في Windows هو مجموعة من البرامج النصية PowerShell المصممة للمساعدة في العثور على المشكلات وتشخيصها باستخدام عامل Log Analytics. يتم تضمينه تلقائيًا مع العامل عند التثبيت. يجب أن يكون تشغيل الأداة هو الخطوة الأولى في تشخيص المشكلة.

استخدام أداة "استكشاف الأخطاء وإصلاحها"

  1. افتح موجه PowerShell كمسؤول على الجهاز حيث تم تثبيت عامل Log Analytics.

  2. انتقل إلى الدليل حيث توجد الأداة:

    cd "C:\Program Files\Microsoft Monitoring Agent\Agent\Troubleshooter"

  3. تنفيذ البرنامج النصي الرئيسي باستخدام هذا الأمر:

    .\GetAgentInfo.ps1

  4. حدد سيناريو استكشاف الأخطاء وإصلاحها.

  5. اتبع الإرشادات الموجودة على وحدة التحكم. لاحظ أن خطوات تتبع السجلات تتطلب تدخلا يدويا لإيقاف جمع السجل. استنادا إلى إمكانية إعادة إنتاج المشكلة، انتظر المدة الزمنية وحدد "s" لإيقاف جمع السجل والمتابعة إلى الخطوة التالية.

    يتم تسجيل موقع ملف النتائج عند الانتهاء ويتم فتح نافذة مستكشف جديدة تميزه.

التثبيت

يتم تضمين أداة استكشاف الأخطاء وإصلاحها تلقائيا عند تثبيت إصدار عامل تحليلات السجل 10.20.18053.0 وما بعده.

السيناريوهات التي تمت تغطيتها

تتحقق أداة "استكشاف الأخطاء وإصلاحها" من السيناريوهات التالية:

  • العامل لا يبلغ عن البيانات أو بيانات رسالة كشف أخطاء الاتصال مفقودة.
  • فشل نشر ملحق العامل.
  • العامل يتعطل.
  • يستهلك العامل وحدة المعالجة المركزية أو الذاكرة العالية.
  • فشل تجربة التثبيت وإلغاء التثبيت.
  • تحتوي السجلات المخصصة على مشكلات.
  • تحتوي بوابة OMS على مشكلات.
  • تحتوي عدادات الأداء على مشكلات.
  • لا يمكن جمع سجلات العامل.

إشعار

قم بتشغيل أداة استكشاف الأخطاء وإصلاحها عند مواجهة مشكلة. سيساعد الحصول على السجلات في البداية فريق الدعم لدينا في استكشاف مشكلتك وإصلاحها بشكل أسرع.

مصادر مهمة لاستكشاف الأخطاء وإصلاحها

للمساعدة في استكشاف المشكلات المتعلقة بعامل Log Analytics لنظام التشغيل Windows وإصلاحها، يسجل العامل الأحداث إلى سجل أحداث Windows، وتحديدا ضمن Application and Services\Operations Manager.

مشكلات الاتصال

إذا كان العامل يتصل من خلال خادم وكيل أو جدار حماية، فقد تكون هناك قيود تمنع الاتصال من الكمبيوتر المصدر وخدمة Azure Monitor. إذا تم حظر الاتصال بسبب التكوين الخاطئ، فقد يفشل التسجيل باستخدام مساحة عمل أثناء محاولة تثبيت العامل أو تكوين عامل ما بعد الإعداد لتقديم تقرير إلى مساحة عمل أخرى. قد يفشل اتصال العامل بعد التسجيل الناجح. يصف هذا القسم طرق استكشاف هذا النوع من المشكلات مع عامل Windows وإصلاحها.

تحقق مرة إضافية من تكوين جدار الحماية أو الوكيل للسماح بالمنافذ وعناوين URL التالية الموضحة في الجدول التالي. تأكد أيضا من عدم تمكين فحص HTTP لحركة مرور الويب. يمكن أن يمنع قناة TLS آمنة بين العامل وAzure Monitor.

مورد العامل منافذ الاتجاه مراقب Bypass HTTPS
*.ods.opinsights.azure.com منفذ 443 صادر ‏‏نعم‬
*.oms.opinsights.azure.com منفذ 443 صادر ‏‏نعم‬
*.blob.core.windows.net منفذ 443 صادر ‏‏نعم‬
*.agentsvc.azure-automation.net منفذ 443 صادر ‏‏نعم‬

للحصول على معلومات جدار الحماية المطلوبة لـAzure Government، راجع إدارة Azure Government. إذا كنت تخطط لاستخدام Azure Automation Hybrid Runbook Worker للاتصال بخدمة التنفيذ التلقائي والتسجيل فيها لاستخدام دفاتر التشغيل أو حلول الإدارة في بيئتك، فيجب أن يكون لديه حق الوصول إلى رقم المنفذ وعناوين URL الموضحة في تكوين شبكتك ل Hybrid Runbook Worker.

هناك عدة طرق يمكنك من خلالها التحقق مما إذا كان العامل يتواصل بنجاح مع Azure Monitor:

  • تمكين تقييم صحة عامل Azure Log Analytics في مساحة العمل. من لوحة معلومات Agent Health، اعرض العمود Count of unresponsive agents لمعرفة ما إذا كان العامل مدرجا بسرعة.

  • قم بتشغيل الاستعلام التالي للتأكد من أن العامل يرسل رسالة كشف أخطاء الاتصال إلى مساحة العمل التي تم تكوينها للإبلاغ عنها. استبدل <ComputerName> بالاسم الفعلي للجهاز.

    Heartbeat 
    | where Computer like "<ComputerName>"
    | summarize arg_max(TimeGenerated, * ) by Computer 
    

    إذا كان الكمبيوتر يتصل بالخدمة بنجاح، يجب أن يُرجع الاستعلام نتيجة. إذا لم يرجع الاستعلام نتيجة، فتحقق أولا من تكوين العامل لتقديم تقرير إلى مساحة العمل الصحيحة. إذا تم تكوينه بشكل صحيح، فانتقل إلى الخطوة 3 وابحث في سجل أحداث Windows لتحديد ما إذا كان العامل يسجل المشكلة التي قد تمنعه من الاتصال ب Azure Monitor.

  • طريقة أخرى لتحديد مشكلة الاتصال هي عن طريق تشغيل أداة TestCloud الاتصال ivity. يتم تثبيت الأداة بشكل افتراضي مع العامل في المجلد ٪SystemRoot٪\Program Files\Microsoft Monitoring Agent\Agent. من موجه أوامر غير مقيد، انتقل إلى المجلد وقم بتشغيل الأداة. تقوم الأداة بإرجاع النتائج وتمييز مكان فشل الاختبار. على سبيل المثال، ربما كان مرتبطا بمنفذ معين أو عنوان URL تم حظره.

    Screenshot that shows TestCloudConnection tool execution results.

  • قم بتصفية سجل أحداث ⁧⁩مدير العمليات⁩ حسب ⁧⁩مصادر الأحداث⁧وحدات الخدمة الصحية⁧⁩، و⁧⁩HealthService⁦، و⁧موصل الخدمة⁧⁩، وقم بالتصفية حسب ⁧مستوى الحدث⁧⁩⁧⁩تحذير⁧⁩ و⁧⁩خطأ⁧⁩؛ لتأكيد ما إذا كان قد كتب أحداثًا من الجدول التالي. إذا كانت كذلك، فراجع خطوات الحل المضمنة لكل حدث محتمل.

    معرف الحدث المصدر ‏‏الوصف نوع الحل
    2133 و2129 الخدمة الصحية فشل الاتصال إلى الخدمة من العامل. يمكن أن يحدث هذا الخطأ عندما لا يتمكن العامل من الاتصال مباشرة أو من خلال جدار حماية أو خادم وكيل إلى خدمة Azure Monitor. تحقق من إعدادات وكيل العامل أو أن جدار حماية الشبكة أو الوكيل يسمح بحركة مرور TCP من الكمبيوتر إلى الخدمة.
    2138 وحدات الخدمة الصحية يتطلب الوكيل المصادقة. تكوين إعدادات العامل، وتحديد اسم المستخدم/ كلمة المرور المطلوبة للمصادقة مع الخادم العامل.
    2129 وحدات الخدمة الصحية فشل الاتصال. فشل مفاوضات TLS. تحقق من إعدادات TCP / IP لمحول الشبكة، وإعدادات العامل.
    2127 وحدات الخدمة الصحية فشل إرسال البيانات تلقي رمز الخطأ. إذا حدث ذلك بشكل دوري فقط خلال النهار، فقد يكون ذلك شذوذا عشوائيا يمكن تجاهله. راقب لفهم عدد مرات حدوث ذلك. إذا حدث ذلك كثيرًا على مدار اليوم، فتحقق أولاً من تكوين الشبكة وإعدادات الوكيل. إذا تضمن الوصف رمز خطأ HTTP 404، وكانت هذه هي المرة الأولى التي يحاول فيها العامل إرسال البيانات إلى الخدمة، فسيتضمن خطأ 500 مع رمز خطأ 404 داخلي. رمز الخطأ 404 يعني "غير موجود"، مما يشير إلى أن منطقة التخزين لمساحة العمل الجديدة لا تزال قيد التوفير. في إعادة المحاولة التالية، ستكتب البيانات بنجاح إلى مساحة العمل كما هو متوقع. قد يشير خطأ HTTP 403 إلى وجود مشكلة في إذن، أو بيانات اعتماد. يتم تضمين مزيد من المعلومات مع الخطأ 403 للمساعدة في استكشاف المشكلة وإصلاحها.
    4000 موصل الخدمة فشل تحليل اسم DNS. تعذر على الجهاز حل عنوان الإنترنت المستخدم عند إرسال البيانات إلى الخدمة. قد تكون هذه المشكلة هي إعدادات محلل DNS على جهازك أو إعدادات وكيل غير صحيحة أو مشكلة DNS مؤقتة مع الموفر. إذا حدث ذلك بشكل دوري، فقد يكون ناتجًا عن مشكلة عابرة متعلقة بالشبكة.
    4001 موصل الخدمة فشل الاتصال بالخدمة. يمكن أن يحدث هذا الخطأ عندما لا يتمكن العامل من الاتصال مباشرة أو من خلال جدار حماية أو خادم وكيل إلى خدمة Azure Monitor. تحقق من إعدادات وكيل العامل أو أن جدار حماية الشبكة أو الوكيل يسمح بحركة مرور TCP من الكمبيوتر إلى الخدمة.
    4002 موصل الخدمة عرضت الخدمة رمز حالة HTTP 403 استجابةً لاستعلام. تحقق مع مدير الخدمة من صحة الخدمة. محاولة سيتم إعادة محاولة الاستعلام لاحقًا. تتم كتابة هذا الخطأ أثناء مرحلة التسجيل الأولية للعامل. سترى عنوان URL مشابها ل https:// workspaceID.oms.opinsights.azure.com/AgentService.svc/AgentTopologyRequest>.< رمز الخطأ 403 يعني "ممنوع" ويمكن أن يكون سببه معرف مساحة العمل أو المفتاح الذي تمت كتابة خطأ فيه. قد يكون التاريخ والوقت غير صحيحين أيضا على الكمبيوتر. إذا كان الوقت +/- 15 دقيقة من الوقت الحالي، يفشل الإعداد. لتصحيح هذه المشكلة، قم بتحديث تاريخ و/أو وقت الكمبيوتر الذي يعمل بنظام Windows.

مشكلات جمع البيانات

بعد تثبيت العامل وتقديم تقارير إلى مساحة العمل أو مساحات العمل التي تم تكوينها، قد يتوقف عن تلقي التكوين وجمع أو إعادة توجيه الأداء أو السجلات أو البيانات الأخرى إلى الخدمة اعتمادا على ما تم تمكينه واستهداف الكمبيوتر. تحتاج إلى تحديد:

  • هل هو نوع بيانات معين أو جميع البيانات غير المتوفرة في مساحة العمل؟
  • هل نوع البيانات محدد بواسطة أحد الحلول، أم تم تحديده كجزء من تكوين مجموعة بيانات مساحة العمل؟
  • كم عدد أجهزة الكمبيوتر المتأثرة؟ هل هو كمبيوتر واحد أو أجهزة كمبيوتر متعددة تقوم بإعداد تقارير إلى مساحة العمل؟
  • هل كانت تعمل، وهل توقفت في وقت معين من اليوم، أم لم يتم جمعها مطلقًا؟
  • هل استعلام بحث السجل الذي تستخدمه صحيحا من الناحية التركيبية؟
  • هل تلقى العامل تكوينه من Azure Monitor؟

تتمثل الخطوة الأولى في استكشاف الأخطاء وإصلاحها في تحديد ما إذا كان الكمبيوتر يرسل كشف أخطاء الاتصال.

Heartbeat 
    | where Computer like "<ComputerName>"
    | summarize arg_max(TimeGenerated, * ) by Computer

إذا أرجع الاستعلام النتائج، فستحتاج إلى تحديد ما إذا لم يتم جمع نوع بيانات معين وإعادة توجيهه إلى الخدمة. قد تكون هذه المشكلة بسبب عدم تلقي العامل التكوين المحدث من الخدمة أو بعض الأعراض الأخرى التي تمنع العامل من العمل بشكل طبيعي. قم بتنفيذ الخطوات التالية لاستكشاف الأخطاء وإصلاحها بشكل أكبر.

  1. افتح موجه أوامر غير مقيد على الكمبيوتر ثم أعد تشغيل خدمة العامل عن طريق إدخال net stop healthservice && net start healthservice.

  2. افتح سجل أحداث Operations Manager وابحث عن معرفاتالأحداث 7023 و7024 و7025 و7028 و1210 من مصدرالحدث HealthService. تشير هذه الأحداث إلى أن العامل يتلقى التكوين بنجاح من Azure Monitor ويراقب الكمبيوتر بنشاط. سيتم أيضًا تحديد وصف الحدث لID الحدث 1210 أيضًا في السطر الأخير جميع الحلول والرؤى المضمنة في نطاق المراقبة على العامل.

    Screenshot that shows an Event ID 1210 description.

  3. انتظر عدة دقائق. إذا كنت لا ترى البيانات المتوقعة في نتائج الاستعلام أو المرئيات، اعتمادا على ما إذا كنت تعرض البيانات من حل أو Insight، من سجل أحداث Operations Manager، فابحث عن مصادر الأحداث HealthService و Health Service Modules. قم بالتصفية حسب تحذير مستوىالحدث والخطأ لتأكيد ما إذا كان قد كتب أحداثا من الجدول التالي.

    معرف الحدث المصدر ‏‏الوصف نوع الحل
    8000 HealthService سيحدد هذا الحدث ما إذا كان سير العمل المرتبط بالأداء أو الحدث، أو أي نوع بيانات آخر تم تجميعه غير قادر على إعادة التوجيه إلى الخدمة لاستيعابها في مساحة العمل. تتم كتابة معرف الحدث 2136 من HealthService المصدر مع هذا الحدث ويمكن أن يشير إلى أن العامل غير قادر على الاتصال بالخدمة. قد تكون الأسباب المحتملة هي التكوين الخاطئ لإعدادات الوكيل والمصادقة أو انقطاع الشبكة أو أن جدار حماية الشبكة أو الوكيل لا يسمح بنسبة استخدام الشبكة TCP من الكمبيوتر إلى الخدمة.
    10102 و10103 وحدات الخدمة الصحية تعذر على سير العمل حل مصدر البيانات. يمكن أن تحدث هذه المشكلة إذا لم يكن عداد أو مثيل الأداء المحدد موجودا على الكمبيوتر أو تم تعريفه بشكل غير صحيح في إعدادات بيانات مساحة العمل. إذا كان هذا عداد أداء محددا من قبل المستخدم، فتحقق من أن المعلومات المحددة تتبع التنسيق الصحيح وتوجد على أجهزة الكمبيوتر الهدف.
    26002 وحدات الخدمة الصحية تعذر على سير العمل حل مصدر البيانات. يمكن أن تحدث هذه المشكلة إذا لم يكن سجل أحداث Windows المحدد موجودا على الكمبيوتر. يمكن تجاهل هذا الخطأ بأمان إذا لم يكن من المتوقع أن يكون الكمبيوتر مسجلا في سجل الأحداث هذا. وإلا، إذا كان هذا سجل أحداث محدد من قبل المستخدم، فتحقق من صحة المعلومات المحددة.

مشكلات الشهادة مثبتة مع وكلاء مراقبة Microsoft الأقدم - كسر التغيير

نظرة عامة على تغيير المرجع المصدق الجذري

اعتبارا من 30 يونيو 2023، لن تقبل الواجهة الخلفية ل Log Analytics الاتصالات من MMA التي تشير إلى شهادة جذر قديمة. تعد MMAs هذه إصدارات أقدم قبل إصدار شتاء 2020 (عامل تحليلات السجل) وقبل SCOM 2019 UR3 (SCOM). أي إصدار، الحزمة: 10.20.18053 / الملحق: 1.0.18053.0، أو أحدث لن تواجه أي مشكلات، بالإضافة إلى أي إصدار أعلى من SCOM 2019 UR3. أي عامل أقدم من ذلك سيتعطل ولن يعمل ويحمل إلى Log Analytics.

ما الذي يتغير بالضبط؟

كجزء من جهد أمني مستمر عبر خدمات Azure المختلفة، سيتحول Azure Log Analytics رسميا من جذر Baltimore CyberTrust CA إلى جذر DigiCert Global G2 CA. سيؤثر هذا التغيير على اتصالات TLS مع Log Analytics إذا كانت شهادة DigiCert Global G2 CA Root الجديدة مفقودة من نظام التشغيل، أو كان التطبيق يشير إلى المرجع المصدق الجذر Baltimore القديم. ما يعنيه هذا هو أن Log Analytics لن يقبل الاتصالات من MMA التي تستخدم المرجع المصدق الجذري القديم هذا بعد إيقافه.

منتجات الحلول

ربما تلقيت إشعار التغيير العاجل حتى إذا لم تقم بتثبيت عامل مراقبة Microsoft شخصيا. وذلك لأن منتجات Azure المختلفة تستفيد من عامل مراقبة Microsoft. إذا كنت تستخدم أحد هذه المنتجات، فقد تتأثر لأنها تستفيد من Windows Log Analytics Agent. بالنسبة إلى هذه المنتجات ذات الارتباطات أدناه، قد تكون هناك إرشادات محددة تتطلب منك الترقية إلى أحدث عامل.

تحديد عوامل التعطل وإعادة تعيينها

بالنسبة إلى عمليات النشر التي تحتوي على عدد محدود من الوكلاء، نوصي بشدة بترقية وكيلك لكل عقدة عبر إرشادات الإدارة هذه.

بالنسبة إلى عمليات النشر ذات العقد المتعددة، قمنا بكتابة برنامج نصي سيكشف عن أي MMAs معطلة متأثرة لكل اشتراك ثم ترقيتها لاحقا إلى أحدث إصدار. يجب تشغيل هذه البرامج النصية بشكل تسلسلي، بدءا من UpdateMMA.ps1 ثم UpgradeMMA.ps1. اعتمادا على الجهاز، قد يستغرق البرنامج النصي بعض الوقت. مطلوب PowerShell 7 أو أكثر للتشغيل لتجنب المهلة.

UpdateMMA.ps1 سيمر هذا البرنامج النصي عبر الأجهزة الظاهرية في اشتراكاتك، والتحقق من تثبيت MMAs الموجودة ثم إنشاء ملف .csv من العوامل التي تحتاج إلى ترقية.

UpgradeMMA.ps1 سيستخدم هذا البرنامج النصي . ملف CSV الذي تم إنشاؤه في UpdateMMA.ps1 لترقية كافة MMAs العاجلة.

قد يستغرق إكمال كلا البرنامجين النصيين بعض الوقت.

# UpdateMMA.ps1
# This script is to be run per subscription, the customer has to set the az subscription before running this within the terminal scope.
# This script uses parallel processing, modify the $parallelThrottleLimit parameter to either increase or decrease the number of parallel processes
# PS> .\UpdateMMA.ps1 GetInventory
# The above command will generate a csv file with the details of VM's and VMSS that require MMA upgrade. 
# The customer can modify the csv by adding/removing rows if needed
# Update the MMA by running the script again and passing the csv file as parameter as shown below:
# PS> .\UpdateMMA.ps1 Upgrade
# If you don't want to check the inventory, then run the script wiht an additional -no-inventory-check
# PS> .\UpdateMMA.ps1 GetInventory & .\UpdateMMA.ps1 Upgrade


# This version of the script requires Powershell version >= 7 in order to improve performance via ForEach-Object -Parallel
# https://docs.microsoft.com/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.1
if ($PSVersionTable.PSVersion.Major -lt 7) 
{
    Write-Host "This script requires Powershell version 7 or newer to run. Please see https://docs.microsoft.com/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.1."
    exit 1
}

$parallelThrottleLimit = 16
$mmaFixVersion = [version]"10.20.18053.0"

function GetVmsWithMMAInstalled
{
    param(
        $fileName
    )

    $vmList = az vm list --show-details --query "[?powerState=='VM running'].{ResourceGroup:resourceGroup, VmName:name}" | ConvertFrom-Json
    
    if(!$vmList)
    {
        Write-Host "Cannot get the VM list, this script can only detect the running VM's"
        return
    }

    $vmsCount = $vmList.Length
    
    $vmParallelThrottleLimit = $parallelThrottleLimit
    if ($vmsCount -lt $vmParallelThrottleLimit) 
    {
        $vmParallelThrottleLimit = $vmsCount
    }

    if($vmsCount -eq 1)
    {
        $vmGroups += ,($vmList[0])
    }
    else
    {
        # split the vm's into batches to do parallel processing
        for ($i = 0; $i -lt $vmsCount; $i += $vmParallelThrottleLimit) 
        { 
            $vmGroups += , ($vmList[$i..($i + $vmParallelThrottleLimit - 1)]) 
        }
    }

    Write-Host "Detected $vmsCount Vm's running in this subscription."
    $hash = [hashtable]::Synchronized(@{})
    $hash.One = 1

    $vmGroups | Foreach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $len = $using:vmsCount
        $hash = $using:hash
        $_ | ForEach-Object {
            $percent = 100 * $hash.One++ / $len
            Write-Progress -Activity "Getting VM Inventory" -PercentComplete $percent
            $vmName = $_.VmName
            $resourceGroup = $_.ResourceGroup
            $responseJson = az vm run-command invoke --command-id RunPowerShellScript --name $vmName -g $resourceGroup --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
            if($responseJson)
            {
                $mmaVersion = $responseJson.Value[0].message
                if ($mmaVersion) 
                {
                    $extensionName = az vm extension list -g $resourceGroup --vm-name $vmName --query "[?name == 'MicrosoftMonitoringAgent'].name" | ConvertFrom-Json
                    if ($extensionName) 
                    {
                        $installType = "Extension"
                    }
                    else 
                    {
                        $installType = "Installer"
                    }
                    $csvObj = New-Object -TypeName PSObject -Property @{
                        'Name'           = $vmName
                        'Resource_Group' = $resourceGroup
                        'Resource_Type'  = "VM"
                        'Install_Type'   = $installType
                        'Version'        = $mmaVersion
                        "Instance_Id"    = ""
                    }
                    $csvObj | Export-Csv $using:fileName -Append -Force
                } 
            } 
        }
    }
}

function GetVmssWithMMAInstalled
{
    param(
        $fileName
    )

    # get the vmss list which are successfully provisioned
    $vmssList = az vmss list --query "[?provisioningState=='Succeeded'].{ResourceGroup:resourceGroup, VmssName:name}" | ConvertFrom-Json   

    $vmssCount = $vmssList.Length
    Write-Host "Detected $vmssCount Vmss running in this subscription."
    $hash = [hashtable]::Synchronized(@{})
    $hash.One = 1

    $vmssList | Foreach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $len = $using:vmssCount
        $hash = $using:hash
        $percent = 100 * $hash.One++ / $len
        Write-Progress -Activity "Getting VMSS Inventory" -PercentComplete $percent
        $vmssName = $_.VmssName
        $resourceGroup = $_.ResourceGroup

        # get running vmss instance ids
        $vmssInstanceIds = az vmss list-instances --resource-group $resourceGroup --name $vmssName --expand instanceView --query "[?instanceView.statuses[1].displayStatus=='VM running'].instanceId" | ConvertFrom-Json
        if ($vmssInstanceIds.Length -gt 0) 
        {
            $isMMAExtensionInstalled = az vmss extension list -g $resourceGroup --vmss-name $vmssName --query "[?name == 'MicrosoftMonitoringAgent'].name" | ConvertFrom-Json
            if ($isMMAExtensionInstalled ) 
            {
                # check an instance in vmss, if it needs an MMA upgrade. Since the extension is installed at VMSS level, checking for bad version in 1 instance should be fine.
                $responseJson = az vmss run-command invoke --command-id RunPowerShellScript --name $vmssName -g $resourceGroup --instance-id $vmssInstanceIds[0] --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
                $mmaVersion = $responseJson.Value[0].message
                if ($mmaVersion) 
                {
                    $csvObj = New-Object -TypeName PSObject -Property @{
                        'Name'           = $vmssName
                        'Resource_Group' = $resourceGroup
                        'Resource_Type'  = "VMSS"
                        'Install_Type'   = "Extension"
                        'Version'        = $mmaVersion
                        "Instance_Id"    = ""
                    }
                    $csvObj | Export-Csv $using:fileName -Append -Force
                }
            }
            else 
            {
                foreach ($instanceId in $vmssInstanceIds) 
                {
                    $responseJson = az vmss run-command invoke --command-id RunPowerShellScript --name $vmssName -g $resourceGroup --instance-id $instanceId --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
                    $mmaVersion = $responseJson.Value[0].message
                    if ($mmaVersion) 
                    {
                        $csvObj = New-Object -TypeName PSObject -Property @{
                            'Name'           = $vmssName
                            'Resource_Group' = $resourceGroup
                            'Resource_Type'  = "VMSS"
                            'Install_Type'   = "Installer"
                            'Version'        = $mmaVersion
                            "Instance_Id"    = $instanceId
                        }
                        $csvObj | Export-Csv $using:fileName -Append -Force
                    }
                }
            }
        }      
    }
}

function Upgrade
{
    param(
        $fileName = "MMAInventory.csv"
    )
    Import-Csv $fileName | ForEach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $mmaVersion = [version]$_.Version
        if($mmaVersion -lt $using:mmaFixVersion)
        {
            if ($_.Install_Type -eq "Extension") 
            {
                if ($_.Resource_Type -eq "VMSS") 
                {
                    # if the extension is installed with a custom name, provide the name using the flag: --extension-instance-name <extension name>
                    az vmss extension set --name MicrosoftMonitoringAgent --publisher Microsoft.EnterpriseCloud.Monitoring --force-update --vmss-name $_.Name --resource-group $_.Resource_Group --no-wait --output none
                }
                else 
                {
                    # if the extension is installed with a custom name, provide the name using the flag: --extension-instance-name <extension name>
                    az vm extension set --name MicrosoftMonitoringAgent --publisher Microsoft.EnterpriseCloud.Monitoring --force-update --vm-name $_.Name --resource-group $_.Resource_Group --no-wait --output none
                }
            }
            else {
                if ($_.Resource_Type -eq "VMSS") 
                {
                    az vmss run-command invoke --command-id RunPowerShellScript --name $_.Name -g $_.Resource_Group --instance-id $_.Instance_Id --scripts '@UpgradeMMA.ps1' --parameters "functionName=UpgradeMMA" --output none
                }
                else 
                {
                    az vm run-command invoke --command-id RunPowerShellScript --name $_.Name -g $_.Resource_Group --scripts '@UpgradeMMA.ps1' --parameters "functionName=UpgradeMMA" --output none
                }
            }
        }
    }
}

function GetInventory
{
    param(
        $fileName = "MMAInventory.csv"
    )

    # create a new file 
    New-Item -Name $fileName -ItemType File -Force
    GetVmsWithMMAInstalled $fileName
    GetVmssWithMMAInstalled $fileName
}

switch ($args.Count)
{
    0 {
        Write-Host "The arguments provided are incorrect."
        Write-Host "To get the Inventory: Run the script as: PS> .\UpdateMMA.ps1 GetInventory"
        Write-Host "To update MMA from Inventory: Run the script as: PS> .\UpdateMMA.ps1 Upgrade"
        Write-Host "To do the both steps together: PS> .\UpdateMMA.ps1 GetInventory & .\UpdateMMA.ps1 Upgrade"
    }
    1 {
        $funcname = $args[0]
        Invoke-Expression "& $funcname"
    }
    2 {
        $funcname = $args[0]
        $funcargs = $args[1]
        Invoke-Expression "& $funcname $funcargs"
    }
}