Workstation & Server Audit Script V3

One thing I wish I had was more time to re-visit my old scripts and re-write them as I often look at my old script and it sends a cold shiver down my spine as I now know a better way of doing things.

As I was away for the weekend and had no internet connection I took my old Audit Script with me, I had a few personal objectives that I wanted to achieve by re-writing this code and I was also asked by a friend who has started to adapt the code into other formats.

So, this is version 3 of the script, you can see how much I have learnt recently as V1 of this script was over 1000 lines, V2 of this script was 847 and now with the new improved code it is a miniscule 459 lines :)

My main objectives for this version of the script were:

  1. Apply my newly learnt PS Skills to optimise the code
  2. Use a HTML format that worked in all browsers
  3. Make the code easy to follow
  4. Make the code easy for other people to produce similar reports of other systems

When you see the code and use the output I hope you will agree I have achieved each of these.  The code now works with all browsers I have tested and is very easily customisable.

Check out a screenshot of the output below:

image

As before this script can be run in two modes, if you run it as it is you will produce an audit of your current machine or if you run it with a path to a text file it will read a list of server names and audit each machine saving a separate html file for each one.

{filelink=8}

<SMALL RANT> Someone took my last script and removed my name from the code and then posted it as their own code on a powershell site, whilst I do not mind people adjusting and re-using my code, in fact there is nothing better than seeing how other people use my code I would prefer that you at least make a reference to my site or me in your comments.

I have been under certain pressure to start charging for some of my code which I have resisted as I like contributing and making the life of my fellow admins easier, claiming my code as your own is just plain rude.</SMALL RANT>

Alan

Alan Renouf has a role of Automation Frameworks Product Manager at VMware responsible for providing the architects and operators of the cloud infrastructure with the toolkits/frameworks and command-line interfaces they require to build a fully automated software-defined datacenter. Alan is a frequent blogger at http://blogs.vmware.com/vipowershell and has a personal blog at http://virtu-al.net. You can follow Alan on twitter as @alanrenouf.

You may also like...

50 Responses

  1. Anand says:

    hi ,

    can any one share update script. so that will really help to check all the servers in one click.

  2. Raj says:

    Hi Alan,

    i have put the script & server txt file in a place and when I am running this I am getting information about local system & not for Servers..

    E:\rishir\Scripts>Audit.ps1 servers.txt
    No list specified, using YTGGNLP3593
    Collating Detail for YTGGNLP3593
    ..Regional Options
    ..Hotfix Information

    Please suggest how to get this run for all servers.

  3. Thanks for your script. I used the HTML portion of it in my own SQL Server best practices review scripts

  4. pbilat says:

    Hi Alan,

    Could you add all installed “MS Office 200x AddIns” (HKML and HKU) in your next release ? Pascal

  5. pbilat says:

    Question to Derekt M.
    Where and how do You have added user and group enumeration in the script?
    Pascal

  6. Derek M says:

    I added the following to get local user and group enumeration. Thanks for the great script!

    Write-Output “..Users”
    $Users = Get-WmiObject -ComputerName $Target Win32_UserAccount -filter “LocalAccount=True” | Select-Object Name,Disabled
    $MyReport += Get-CustomHeader “1” “Users”
    $MyReport += Get-HTMLTable ($Users)
    $MyReport += Get-CustomHeaderClose
    Write-Output “..Groups”
    $Groups = Get-WmiObject -ComputerName $Target Win32_Group -filter “LocalAccount=True” | Select-Object Name
    $MyReport += Get-CustomHeader “1” “Groups”
    $MyReport += Get-HTMLTable ($Groups)
    $MyReport += Get-CustomHeaderClose

  7. Richard Powers says:

    After spending 2 hours looks for a better inventory script then I could write…. (bang head on desk) I should have have figured Alan had something like this… After all he is a legend

  8. Abdul Waheed says:

    Script is really greate could you help me in how can i convert this into csv format appreciate your support.

  9. nortel says:

    Hi All

    Please help me…im getting this error msg

    PS C:\Users\Administrator\Desktop> C:\Users\Administrator\Desktop\audit.ps1
    No list specified, using SGGSINTSYSVW212
    Collating Detail for SGGSINTSYSVW212
    Get-WmiObject :
    At C:\Users\Administrator\Desktop\audit.ps1:165 char:33
    + $ComputerSystem = Get-WmiObject <<<< -computername $Target Win32_ComputerSystem
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    Get-WmiObject :
    At C:\Users\Administrator\Desktop\audit.ps1:176 char:35
    + $OperatingSystems = Get-WmiObject <<<< -computername $Target Win32_OperatingSystem
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    Get-WmiObject :
    At C:\Users\Administrator\Desktop\audit.ps1:177 char:27
    + $TimeZone = Get-WmiObject <<<< -computername $Target Win32_Timezone
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    Get-WmiObject :
    At C:\Users\Administrator\Desktop\audit.ps1:178 char:28
    + $Keyboards = Get-WmiObject <<<< -computername $Target Win32_Keyboard
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    Get-WmiObject :
    At C:\Users\Administrator\Desktop\audit.ps1:179 char:29
    + $SchedTasks = Get-WmiObject <<<< -computername $Target Win32_ScheduledJob
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    Get-WmiObject :
    At C:\Users\Administrator\Desktop\audit.ps1:181 char:34
    + $RecoveryOptions = Get-WmiObject <<<< -computername $Target Win32_OSRecoveryConfiguration
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    You cannot call a method on a null-valued expression.
    At C:\Users\Administrator\Desktop\audit.ps1:190 char:45
    + $LBTime=$OperatingSystems.ConvertToDateTime <<<< ($OperatingSystems.Lastbootuptime)
    + CategoryInfo : InvalidOperation: (ConvertToDateTime:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    ..Regional Options
    Get-WmiObject :
    At C:\Users\Administrator\Desktop\audit.ps1:192 char:31
    + $ObjKeyboards = Get-WmiObject <<<< -ComputerName $Target Win32_Keyboard
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    ..Hotfix Information
    Get-WmiObject :
    At C:\Users\Administrator\Desktop\audit.ps1:280 char:33
    + $colQuickFixes = Get-WmiObject <<<< Win32_QuickFixEngineering
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

  10. Jamal says:

    Thanks Alan for the quick reply. That did the trick

  11. Jamal says:

    Hi Alan,

    Love the script. One problem I am running into is when I execute the script against a list of servers, I only get patching information for the current machine that I am executing the script on. I get all of the outputs the way it is supposed to be, except the wrong patching information. I am using WIN7 enterprise and executing the script agains Win2k3 servers.

    I do have admin access to the remote servers. Please help. To execute, I put the script as well as the list of servers (auditlist.txt) in the same directory. I am using the following to execute .\Audit.ps1 auditlist.txt. Please help.

    • Alan says:

      Ahh, well found – there is a mistake in the script, there is a line which reads:

      $colQuickFixes = Get-WmiObject Win32_QuickFixEngineering

      change it to

      $colQuickFixes = Get-WmiObject -ComputerName $Target Win32_QuickFixEngineering

  12. Waffles says:

    Thanks for the great scripts. For some odd reason having this data up to date and internally public keeps my auditors off my back.

  13. Paul says:

    Great script! any chance you could update it to include the following
    1) Obtain page swap file size in MB
    2) Check for software installed eg sysmantec, Altiris
    3) Diplay WINS settings “Enable LMHOSTS Lookup” and “Enable NetBIOS over TCP/IP
    4) Data Execution Prevention settings
    5) System variables
    6) Remote desktop settings

  14. Dazzpowder says:

    Al, Thanks for this script I learnt about through a class
    with T Lee. It has taught me so much

  15. Dazzpowder says:

    Al, Thanks for this script I learnt about through a class
    with T Lee. It has taught so much

  16. Daniel Hong says:

    Great script!

    I was running into a bit of an issue with Win32_Product class, getting following error message:

    Get-WmiObject : Generic failure
    At C:\temp\AuditScript\Audit.ps1:330 char:46
    + $MyReport += Get-HTMLTable (get-wmiobject <<<< Win32_Product | select Name,Version,Vendor,InstallDate)
    + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], ManagementException
    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    I had to change"get-wmiobject" to "Get-wmiobject" and it worked fine. I'm not sure why there was a case sensitivity issue, since running "get-wmiobject Win32_Product" directly worked fine.

    Anyhow, great work!

  17. Virtu-Al says:

    @Rob P.
    Will do Rob, although you could add it yourslef, honestly the code is very easy to change !

  18. Rob P. says:

    Hi Alan,

    Could you possibly add in the OS Build number in you next release ?

    Have a great Christmas. Rob…

  19. Virtu-Al says:

    @Lucas
    Nice one, love it

  20. Lucas says:

    Great script!

    A couple of changes I made when I used it in my environment:

    1. Started with a ping check (using Win32_PingStatus) to make sure that the target computers are online

    2. Added the following code to get software inventory on Windows 2003 servers where the Win32_Product had not been installed (code goes in the Else portion of the Win32_Product check):

    $colApps = @()
    $hklm = 2147483650
    $key = “SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall”
    $wmi = [wmiclass]”\\$Target\root\default:stdRegProv”
    $subkeys = $wmi.EnumKey($hklm,$key)
    foreach ($subkey in $subkeys.sNames){
    #Filter out hotfixes
    if ($subkey -notmatch “KB*”)
    {
    $appName = ($wmi.GetStringValue($hklm,”$key\$subkey”,”DisplayName”)).sValue
    $appVersion = ($wmi.GetStringValue($hklm,”$key\$subkey”,”DisplayVersion”)).sValue
    $appVendor = ($wmi.GetStringValue($hklm,”$key\$subkey”,”Publisher”)).sValue
    $appInstalldate = ($wmi.GetStringValue($hklm,”$key\$subkey”,”InstallDate”)).sValue

    #Format installation date if it exists
    #Set a trap to catch exceptions thrown by ParseExact if date is not in the expected format
    Trap {
    continue
    }
    if ($appInstalldate)
    {
    $appInstalldate = [datetime]::ParseExact($appInstallDate,’yyyyMMdd’,$null).Date.ToShortDateString()
    }

    $objApps = New-Object System.Object | Add-Member NoteProperty Name $appName -PassThru | Add-Member NoteProperty Version $appVersion -PassThru | Add-Member NoteProperty Vendor $appVendor -PassThru | Add-Member NoteProperty “Install Date” $appInstalldate -PassThru

    $colApps += $objApps
    }
    }
    Write-Output “..Software (via registry)”
    $MyReport += Get-CustomHeader “2” “Software”
    $MyReport += Get-HTMLTable $colApps
    $MyReport += Get-CustomHeaderClose

    Write-Output “..Software WMI class was not installed, used registry instead.”

  21. Rob P says:

    Hi Alan, could I suggest having the Computer Description on the ‘General’ section. Would be nice for us as the computer name isn’t always very helpful.

    Cheers mate.

  22. Sudharsan says:

    Yes , Attachement as a Single HTML file also would hold good since we can schedule it as per convenience . For that i think we might need to remove the Error logs part since error logs might increase the Size of the HTML File that is being atatched and most organizations would have restrictions on the attachment size. Thanks Again for the Great Script !!
    @Virtu-Al

  23. Virtu-Al says:

    @bwuch
    Ahh yeah, I think i need to put a trap in for that one, thanks.

  24. bwuch says:

    Hey, this is a great script! Ran it on a couple machines and really like the output/format. Did run into one small problem that I thought I should report — on certain machines I get a divide by zero error on line 296. I believe this is because of a Q: drive that is 0 bytes (it was created by the Microsoft AppV client).

  25. Alan Renouf says:

    @Rob P
    Great idea mate, let me know if you need any more info in there too.

  26. Alan Renouf says:

    @Cory
    Thanks for the comment, hopefully you will find it very easy to use

  27. Rob P says:

    Hi Alan… Thanks for the great script, once again you have done yourself proud. I’ve run this again out entire server farm, 300+ boxes and will schedule it to run every week to keep it up to date. Everyone here thinks it’s awesome. Even got James using it.

    Could I make a suggestion for the next version. When you run the script, could it include a switch to either run a list of servers, something like “Audit.ps1 -L serverlist.txt” and a switch to audit individual servers, something like “Audit.ps1 -S servername”. Just a thought.

  28. Cory says:

    Wow…great script! Cant wait to dissect this and uncover all of the HTML goodness you’ve got going on here.

  29. Omarr says:

    @Omarr

    It cut out the command that I had typed. It should read

    Get-Credential | commandlet or script name

  30. Virtu-Al says:

    @Omarr
    Thanks for the comment, I wonder if people could use this or would prefer an option to provide a different username/password for each server/workstation ?

    Thoughts ?

  31. Omarr says:

    You can use this with any powershell script or command.

    Get-Credential |

    This will prompt you for your login and then run the commandlet or script as the new login

  32. Virtu-Al says:

    @UppyJC
    Nice one James, hope all is well at WW, say Hi to all for me.

  33. Virtu-Al says:

    @za_mkh
    Thanks for taking the time to leave such a nice comment, this is exactly why I give my scripts away for nothing !

  34. Virtu-Al says:

    @Sudharsan
    Sure, shouldnt be a problem, only issue is that Outlook will not allow the expand part to work so it will be a very long file unless i attach a single html ? Would that be suitable ?! Thanks for the comment

  35. Virtu-Al says:

    @Aaron
    Thanks for pointing me at that, its a great resource, I can certainly move whatever you need from there into this script, which areas do you find most useful ?

    As for the word part, I can also do this as have created a word export script before but would prefer to get all the details in there first.

    Thanks for your comments, i can see this being a great help.

    Alan

  36. UppyJC says:

    Great script Alan.
    An absolutely perfect solution to WW’s latest Microsoft licence audit.
    Hope all’s well.
    James

  37. za_mkh says:

    Hi Alan,

    Just came across your site recently. In fact I book marked it in a blog post a few months back and then went to find it last week now that our new vsphere infrastructure is humming away. Your daily healthcheck script is awesome and I would like to thank you for that. It also showed us errors in our vSphere servers that we are now troubleshooting!

    Since I’m just starting out with Powershell, VESI, I hope too that one day I can contribute a script as userfriendly and as powerful as yours! Thank you.

    za_mkh

  38. Sudharsan says:

    Thanks for the great Script . Can we have a method where in we can have the output in a single HTML file and then mail it to a Specific EMail ID ? may be we can look at removing Error logs to reduce the size of the HTML File .

    looking forward to many more great scripts from you !!

  39. Aaron says:

    The ability to pass it username and password from the text file would be a GREAT feature to this script. I have used a couple other scripts that have done this. One script that i love, that would love to see your script replace is SYDI (http://sydiproject.com/) Patrick is a great guy, but he doesn’t have much time to update his script any more. I would love to see some of the same things in his script in yours. Many of the features are already there, but the ability to write out the file to a word document or generate an overview file is great in my environment.

    Keep up the great work Alan.

    app

  40. Virtu-Al says:

    @Andy

    @Chris

    @dboftlp

    Thanks for the kind comments

  41. Virtu-Al says:

    @DJLO
    Thanks for the comment, im glad the Daily Report is working out ok for you, it has found a few issues for me too 😉

    Just a quick note to say that this is a PowerShell script not specific to PowerCLI although it can be used with PowerCLI to audit your windows VMs, I will work on the permissions side of things and see what I can come up with.

    Thanks for your information, it is useful when progressing the script.

    Alan

  42. Andy says:

    Thanks again Alan. A joy to see …

  43. DJLO says:

    @Virtu-Al
    Hi Alan,

    We host development servers for a number of different teams here so the admin password is usually one of 3. We never keep it the same as our ESX password and my powercli resides on the VC host itself. It would be nice if the txt file could contain an admin password it could use (not sure about security there) or have it prompt for an Admin password and have it keep using it on each subsequent server until it requires it to be changed, then it can prompt for the new password

    I can see huge value for this script because once i host the server, the developers put it on me to make sure their environment is ok and healthy. I usually have to RDP into these hosts and check logs weekly. If the script could somehow do what i’ve asked it would be pure gold. Also could it email the results as well (something like your Dailyreport does).

    Keep up the fantastic job. Your scripts have made my day to day stuff go much smoother and even helped us find a problem in our VC logs we didn’t even know existed !

  44. Virtu-Al says:

    @Paolo
    This is one of the things I was thinking about adding, how would you see it working, do all servers have the same credentials, would you prefer to pass the script a -username and -password parameter ?

    Would you prefer to put the username and password in the text file next to each server ?

    Would you prefer the script to prompt you for a username/passowrd if it doesnt have access to the server ?

    Thanks

    Alan

  45. Paolo says:

    Hi Alan

    How to i make this run if my servers have different passwords? It seems to run just fine on the local box i have powercli installed on but when i add a list of stand alone windows hosts off my ESX box, it fails to run (these boxes have a different administrator password than the one i am on)

  46. Chris says:

    Awesome script as usual. Your contributions are appreciated.

  47. dboftlp says:

    Thanks for the new code Alan. Your work is greatly appreciated!

  1. November 29, 2010

    […] have setup http://www.virtu-al.net/2009/10/26/workstation-server-audit-script-v3/ this in the past.. basic but very useful. It could be modified to output data to a database for you […]

Leave a Reply

%d bloggers like this: