#Requires -Version 3.0 #requires -Module ActiveDirectory #requires -Module GroupPolicy #This File is in Unicode format. Do not edit in an ASCII editor. Notepad++ UTF-8-BOM <# .SYNOPSIS Creates a complete inventory of a Microsoft Active Directory Forest. .DESCRIPTION Creates a complete inventory of a Microsoft Active Directory Forest using Microsoft PowerShell, Word, plain text, or HTML. Creates a Word or PDF document, text or HTML file named after the Active Directory Forest. Word and PDF document includes a Cover Page, Table of Contents and Footer. Includes support for the following language versions of Microsoft Word: Catalan Chinese Danish Dutch English Finnish French German Norwegian Portuguese Spanish Swedish The script requires at least PowerShell version 3 but runs best in version 5. Word is NOT needed to run the script. This script will output in Text and HTML. You do NOT have to run this script on a domain controller. This script was developed and run from a Windows 10 VM. While most of the script can be run with a non-admin account, there are some features that will not or may not work without domain admin or enterprise admin rights. The Hardware and Services parameters require domain admin privileges. Version 2.0 of the script adds gathering information on Time Server and AD database, log file, and SYSVOL locations. Those require access to the registry on each domain controller, which means the script should now always be run from an elevated PowerShell session with an account with a minimum of domain admin rights. Running the script in a forest with multiple domains requires Enterprise Admin rights. The count of all users may not be accurate if the user running the script doesn't have the necessary permissions on all user objects. In that case, there may be user accounts classified as "unknown". To run the script from a workstation, RSAT is required. Remote Server Administration Tools for Windows 7 with Service Pack 1 (SP1) http://www.microsoft.com/en-us/download/details.aspx?id=7887 Remote Server Administration Tools for Windows 8 http://www.microsoft.com/en-us/download/details.aspx?id=28972 Remote Server Administration Tools for Windows 8.1 http://www.microsoft.com/en-us/download/details.aspx?id=39296 Remote Server Administration Tools for Windows 10 http://www.microsoft.com/en-us/download/details.aspx?id=45520 .PARAMETER HTML Creates an HTML file with an .html extension. This parameter is disabled by default. .PARAMETER MSWord SaveAs DOCX file This parameter is set True if no other output format is selected. .PARAMETER PDF SaveAs PDF file instead of DOCX file. This parameter is disabled by default. The PDF file is roughly 5X to 10X larger than the DOCX file. This parameter requires Microsoft Word to be installed. This parameter uses the Word SaveAs PDF capability. .PARAMETER Text Creates a formatted text file with a .txt extension. This parameter is disabled by default. .PARAMETER AddDateTime Adds a date time stamp to the end of the file name. The timestamp is in the format of yyyy-MM-dd_HHmm. June 1, 2020 at 6PM is 2020-06-01_1800. Output filename will be ReportName_2020-06-01_1800.docx (or .pdf). This parameter is disabled by default. .PARAMETER ADDomain Specifies an Active Directory domain object by providing one of the following property values. The identifier in parentheses is the LDAP display name for the attribute. All values are for the domainDNS object that represents the domain. Distinguished Name Example: DC=tullahoma,DC=corp,DC=labaddomain,DC=com GUID (objectGUID) Example: b9fa5fbd-4334-4a98-85f1-3a3a44069fc6 Security Identifier (objectSid) Example: S-1-5-21-3643273344-1505409314-3732760578 DNS domain name Example: tullahoma.corp.labaddomain.com NetBIOS domain name Example: Tullahoma If both ADForest and ADDomain are specified, ADDomain takes precedence. .PARAMETER ADForest Specifies an Active Directory forest object by providing one of the following attribute values. The identifier in parentheses is the LDAP display name for the attribute. Fully qualified domain name Example: labaddomain.com GUID (objectGUID) Example: 599c3d2e-e61e-4d20-7b77-030d99495e19 DNS host name Example: labaddomain.com NetBIOS name Example: labaddomain Default value is $Env:USERDNSDOMAIN If both ADForest and ADDomain are specified, ADDomain takes precedence. .PARAMETER CompanyAddress Company Address to use for the Cover Page, if the Cover Page has the Address field. The following Cover Pages have an Address field: Banded (Word 2013/2016) Contrast (Word 2010) Exposure (Word 2010) Filigree (Word 2013/2016) Ion (Dark) (Word 2013/2016) Retrospect (Word 2013/2016) Semaphore (Word 2013/2016) Tiles (Word 2010) ViewMaster (Word 2013/2016) This parameter is only valid with the MSWORD and PDF output parameters. This parameter has an alias of CA. .PARAMETER CompanyEmail Company Email to use for the Cover Page, if the Cover Page has the Email field. The following Cover Pages have an Email field: Facet (Word 2013/2016) This parameter is only valid with the MSWORD and PDF output parameters. This parameter has an alias of CE. .PARAMETER CompanyFax Company Fax to use for the Cover Page, if the Cover Page has the Fax field. The following Cover Pages have a Fax field: Contrast (Word 2010) Exposure (Word 2010) This parameter is only valid with the MSWORD and PDF output parameters. This parameter has an alias of CF. .PARAMETER CompanyName Company Name to use for the Cover Page. Default value is contained in HKCU:\Software\Microsoft\Office\Common\UserInfo\CompanyName or HKCU:\Software\Microsoft\Office\Common\UserInfo\Company, whichever is populated on the computer running the script. This parameter has an alias of CN. If either registry key does not exist and this parameter is not specified, the report will not contain a Company Name on the cover page. This parameter is only valid with the MSWORD and PDF output parameters. .PARAMETER CompanyPhone Company Phone to use for the Cover Page if the Cover Page has the Phone field. The following Cover Pages have a Phone field: Contrast (Word 2010) Exposure (Word 2010) This parameter is only valid with the MSWORD and PDF output parameters. This parameter has an alias of CPh. .PARAMETER CoverPage What Microsoft Word Cover Page to use. Only Word 2010, 2013 and 2016 are supported. (default cover pages in Word en-US) Valid input is: Alphabet (Word 2010. Works) Annual (Word 2010. Doesn't work well for this report) Austere (Word 2010. Works) Austin (Word 2010/2013/2016. Doesn't work in 2013 or 2016, mostly works in 2010 but Subtitle/Subject & Author fields need to be moved after title box is moved up) Banded (Word 2013/2016. Works) Conservative (Word 2010. Works) Contrast (Word 2010. Works) Cubicles (Word 2010. Works) Exposure (Word 2010. Works if you like looking sideways) Facet (Word 2013/2016. Works) Filigree (Word 2013/2016. Works) Grid (Word 2010/2013/2016. Works in 2010) Integral (Word 2013/2016. Works) Ion (Dark) (Word 2013/2016. Top date doesn't fit; box needs to be manually resized or font changed to 8 point) Ion (Light) (Word 2013/2016. Top date doesn't fit; box needs to be manually resized or font changed to 8 point) Mod (Word 2010. Works) Motion (Word 2010/2013/2016. Works if top date is manually changed to 36 point) Newsprint (Word 2010. Works but date is not populated) Perspective (Word 2010. Works) Pinstripes (Word 2010. Works) Puzzle (Word 2010. Top date doesn't fit; box needs to be manually resized or font changed to 14 point) Retrospect (Word 2013/2016. Works) Semaphore (Word 2013/2016. Works) Sideline (Word 2010/2013/2016. Doesn't work in 2013 or 2016, works in 2010) Slice (Dark) (Word 2013/2016. Doesn't work) Slice (Light) (Word 2013/2016. Doesn't work) Stacks (Word 2010. Works) Tiles (Word 2010. Date doesn't fit unless changed to 26 point) Transcend (Word 2010. Works) ViewMaster (Word 2013/2016. Works) Whisp (Word 2013/2016. Works) The default value is Sideline. This parameter has an alias of CP. This parameter is only valid with the MSWORD and PDF output parameters. .PARAMETER ComputerName Specifies which domain controller to use to run the script against. If ADForest is a trusted forest, then ComputerName is required to detect the existence of ADForest. ComputerName can be entered as the NetBIOS name, FQDN, localhost or IP Address. If entered as localhost, the actual computer name is determined and used. If entered as an IP address, an attempt is made to determine and use the actual computer name. This parameter has an alias of ServerName. Default value is $Env:USERDNSDOMAIN .PARAMETER DCDNSInfo Use WMI to gather, for each domain controller, the IP Address, and each DNS server configured. This parameter requires the script be run from an elevated PowerShell session using an account with permission to retrieve hardware information (i.e. Domain Admin). Selecting this parameter will add an extra section to the report. This parameter is disabled by default. .PARAMETER Dev Clears errors at the beginning of the script. Outputs all errors to a text file at the end of the script. This is used when the script developer requests more troubleshooting data. The text file is placed in the same folder from where the script is run. This parameter is disabled by default. .PARAMETER Folder Specifies the optional output folder to save the output report. .PARAMETER GPOInheritance In the Group Policies by OU section, adds Inherited GPOs in addition to the GPOs directly linked. Adds a second column to the table GPO Type. The text file is placed in the same folder from where the script is run. This parameter is disabled by default. This parameter has an alias of GPO. .PARAMETER Hardware Use WMI to gather hardware information on Computer System, Disks, Processor, and Network Interface Cards This parameter requires the script be run from an elevated PowerShell session using an account with permission to retrieve hardware information (i.e. Domain Admin). Selecting this parameter will add to both the time it takes to run the script and size of the report. This parameter is disabled by default. .PARAMETER IncludeUserInfo For the User Miscellaneous Data section outputs a table with the SamAccountName and DistinguishedName of the users in the All Users counts: Disabled users Unknown users Locked out users All users with password expired All users whose password never expires All users with password not required All users who cannot change password All users with SID History All users with Homedrive set in ADUC All users whose Primary Group is not Domain Users All users with RDS HomeDrive set in ADUC The Text output option is limited to the first 25 characters of the SamAccountName and the first 116 characters of the DistinguishedName. This parameter is disabled by default. This parameter has an alias of IU. .PARAMETER Log Generates a log file for troubleshooting. .PARAMETER MaxDetails Adds maximum detail to the report. This is the same as using the following parameters: DCDNSInfo GPOInheritance Hardware IncludeUserInfo Services WARNING: Using this parameter can create an extremely large report and can take a very long time to run. This parameter has an alias of MAX. .PARAMETER ScriptInfo Outputs information about the script to a text file. The text file is placed in the same folder from where the script is run. This parameter is disabled by default. This parameter has an alias of SI. .PARAMETER Services Gather information on all services running on domain controllers. Servers that are configured to automatically start but are not running will be colored in red. Used on Domain Controllers only. This parameter requires the script be run from an elevated PowerShell session using an account with permission to retrieve service information (i.e. Domain Admin). Selecting this parameter will add to both the time it takes to run the script and size of the report. This parameter is disabled by default. .PARAMETER Section Processes one or more sections of the report. Valid options are: Forest Sites Domains (includes Domain Controllers and optional Hardware, Services and DCDNSInfo) OUs (Organizational Units) Groups GPOs Misc (Miscellaneous data) All This parameter defaults to All sections. Multiple sections are separated by a comma. -Section forest, domains .PARAMETER UserName Username to use for the Cover Page and Footer. Default value is contained in $env:username This parameter has an alias of UN. This parameter is only valid with the MSWORD and PDF output parameters. .PARAMETER SmtpServer Specifies the optional email server to send the output report. .PARAMETER SmtpPort Specifies the SMTP port. The default is 25. .PARAMETER UseSSL Specifies whether to use SSL for the SmtpServer. The default is False. .PARAMETER From Specifies the username for the From email address. If SmtpServer is used, this is a required parameter. .PARAMETER To Specifies the username for the To email address. If SmtpServer is used, this is a required parameter. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. ADForest defaults to the value of $Env:USERDNSDOMAIN. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -ADForest company.tld Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. company.tld for the AD Forest. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -ADDomain child.company.tld Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. child.company.tld for the AD Domain. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -ADForest parent.company.tld -ADDomain child.company.tld Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. Because both ADForest and ADDomain are specified, ADDomain wins and child.company.tld is used for AD Domain. ADForest is set to the value of ADDomain. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -ADForest company.tld -ComputerName DC01 Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. company.tld for the AD Forest The script will be run remotely on the DC01 domain controller. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -PDF -ADForest corp.carlwebster.com Will use all default values and save the document as a PDF file. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. corp.carlwebster.com for the AD Forest. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -Text -ADForest corp.carlwebster.com Will use all default values and save the document as a formatted text file. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator. Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. corp.carlwebster.com for the AD Forest. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -HTML -ADForest corp.carlwebster.com Will use all default values and save the document as an HTML file. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator. Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. corp.carlwebster.com for the AD Forest. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -hardware Will use all default values and add additional information for each domain controller about its hardware. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator. Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. ADForest defaults to the value of $Env:USERDNSDOMAIN. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -services Will use all default values and add additional information for the services running on each domain controller. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator. Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. ADForest defaults to the value of $Env:USERDNSDOMAIN. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -DCDNSInfo Will use all default values and add additional information for each domain controller about its DNS IP configuration. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. An extra section will be added to the end of the report. ADForest defaults to the value of $Env:USERDNSDOMAIN. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript .\ADDS_Inventory_V2.ps1 -CompanyName "Carl Webster Consulting" -CoverPage "Mod" -UserName "Carl Webster" -ComputerName ADDC01 Will use: Carl Webster Consulting for the Company Name. Mod for the Cover Page format. Carl Webster for the User Name. ADForest defaults to the value of $Env:USERDNSDOMAIN. Domain Controller named ADDC01 for the ComputerName. .EXAMPLE PS C:\PSScript .\ADDS_Inventory_V2.ps1 -CN "Carl Webster Consulting" -CP "Mod" -UN "Carl Webster" Will use: Carl Webster Consulting for the Company Name (alias CN). Mod for the Cover Page format (alias CP). Carl Webster for the User Name (alias UN). ADForest defaults to the value of $Env:USERDNSDOMAIN. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript .\ADDS_Inventory_V2.ps1 -CompanyName "Sherlock Holmes Consulting" -CoverPage Exposure -UserName "Dr. Watson" -CompanyAddress "221B Baker Street, London, England" -CompanyFax "+44 1753 276600" -CompanyPhone "+44 1753 276200" Will use: Sherlock Holmes Consulting for the Company Name. Exposure for the Cover Page format. Dr. Watson for the User Name. 221B Baker Street, London, England for the Company Address. +44 1753 276600 for the Company Fax. +44 1753 276200 for the Company Phone. ADForest defaults to the value of $Env:USERDNSDOMAIN. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript .\ADDS_Inventory_V2.ps1 -CompanyName "Sherlock Holmes Consulting" -CoverPage Facet -UserName "Dr. Watson" -CompanyEmail SuperSleuth@SherlockHolmes.com Will use: Sherlock Holmes Consulting for the Company Name. Facet for the Cover Page format. Dr. Watson for the User Name. SuperSleuth@SherlockHolmes.com for the Company Email. ADForest defaults to the value of $Env:USERDNSDOMAIN. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -ADForest company.tld -AddDateTime Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator. Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. company.tld for the AD Forest. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. Adds a date time stamp to the end of the file name. The timestamp is in the format of yyyy-MM-dd_HHmm. June 1, 2020 at 6PM is 2020-06-01_1800. Output filename will be company.tld_2020-06-01_1800.docx. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -PDF -ADForest corp.carlwebster.com -AddDateTime Will use all default values and save the document as a PDF file. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. corp.carlwebster.com for the AD Forest. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. Adds a date time stamp to the end of the file name. The timestamp is in the format of yyyy-MM-dd_HHmm. June 1, 2020 at 6PM is 2020-06-01_1800. Output filename will be corp.carlwebster.com_2020-06-01_1800.PDF .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -ADForest corp.carlwebster.com -Folder \\FileServer\ShareName Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. corp.carlwebster.com for the AD Forest. ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. The output file will be saved in the path \\FileServer\ShareName. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -Section Forest Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. ADForest defaults to the value of $Env:USERDNSDOMAIN ComputerName defaults to the value of $Env:USERDNSDOMAIN, then the script queries for a domain controller that is also a global catalog server and will use that as the value for ComputerName. The report will include only the Forest section. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -Section groups, misc -ADForest WebstersLab.com -ServerName PrimaryDC.websterslab.com Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. WebstersLab.com for ADForest. PrimaryDC.websterslab.com for ComputerName. The report will include only the Groups and Miscellaneous sections. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -MaxDetails Will use all Default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. Set the following parameter values: DCDNSInfo = True GPOInheritance = True Hardware = True IncludeUserInfo = True Services = True Section = "All" .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -ADForest corp.carlwebster.com -SmtpServer mail.domain.tld -From XDAdmin@domain.tld -To ITGroup@domain.tld -ComputerName Server01 Will use all Default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\CompanyName="Carl Webster" or HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Sideline for the Cover Page format. Administrator for the User Name. corp.carlwebster.com for the AD Forest. The script will be run remotely against server Server01. The script will use the email server mail.domain.tld, sending from XDAdmin@domain.tld, sending to ITGroup@domain.tld. The script will use the default SMTP port 25 and will not use SSL. If the current user's credentials are not valid to send email, the user will be prompted to enter valid credentials. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -SmtpServer mailrelay.domain.tld -From Anonymous@domain.tld -To ITGroup@domain.tld ***SENDING UNAUTHENTICATED EMAIL*** The script will use the email server mailrelay.domain.tld, sending from anonymous@domain.tld, sending to ITGroup@domain.tld. To send unauthenticated email using an email relay server requires the From email account to use the name Anonymous. The script will use the default SMTP port 25 and will not use SSL. ***GMAIL/G SUITE SMTP RELAY*** https://support.google.com/a/answer/2956491?hl=en https://support.google.com/a/answer/176600?hl=en To send email using a Gmail or g-suite account, you may have to turn ON the "Less secure app access" option on your account. ***GMAIL/G SUITE SMTP RELAY*** The script will generate an anonymous secure password for the anonymous@domain.tld account. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -SmtpServer labaddomain-com.mail.protection.outlook.com -UseSSL -From SomeEmailAddress@labaddomain.com -To ITGroupDL@labaddomain.com ***OFFICE 365 Example*** https://docs.microsoft.com/en-us/exchange/mail-flow-best-practices/how-to-set-up-a-multifunction-device-or-application-to-send-email-using-office-3 This uses Option 2 from the above link. ***OFFICE 365 Example*** The script will use the email server labaddomain-com.mail.protection.outlook.com, sending from SomeEmailAddress@labaddomain.com, sending to ITGroupDL@labaddomain.com. The script will use the default SMTP port 25 and will use SSL. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -SmtpServer smtp.office365.com -SmtpPort 587 -UseSSL -From Webster@CarlWebster.com -To ITGroup@CarlWebster.com The script will use the email server smtp.office365.com on port 587 using SSL, sending from webster@carlwebster.com, sending to ITGroup@carlwebster.com. If the current user's credentials are not valid to send email, the user will be prompted to enter valid credentials. .EXAMPLE PS C:\PSScript > .\ADDS_Inventory_V2.ps1 -SmtpServer smtp.gmail.com -SmtpPort 587 -UseSSL -From Webster@CarlWebster.com -To ITGroup@CarlWebster.com *** NOTE *** To send email using a Gmail or g-suite account, you may have to turn ON the "Less secure app access" option on your account. *** NOTE *** The script will use the email server smtp.gmail.com on port 587 using SSL, sending from webster@gmail.com, sending to ITGroup@carlwebster.com. If the current user's credentials are not valid to send email, the user will be prompted to enter valid credentials. .INPUTS None. You cannot pipe objects to this script. .OUTPUTS No objects are output from this script. This script creates a Word or PDF document. .NOTES NAME: ADDS_Inventory_V2.ps1 VERSION: 2.26 AUTHOR: Carl Webster and Michael B. Smith LASTEDIT: May 8, 2020 #> #thanks to @jeffwouters and Michael B. Smith for helping me with these parameters [CmdletBinding(SupportsShouldProcess = $False, ConfirmImpact = "None", DefaultParameterSetName = "Word") ] Param( [parameter(ParameterSetName="HTML",Mandatory=$False)] [Switch]$HTML=$False, [parameter(ParameterSetName="Word",Mandatory=$False)] [Switch]$MSWord=$False, [parameter(ParameterSetName="PDF",Mandatory=$False)] [Switch]$PDF=$False, [parameter(ParameterSetName="Text",Mandatory=$False)] [Switch]$Text=$False, [parameter(Mandatory=$False)] [Switch]$AddDateTime=$False, [parameter(Mandatory=$False)] [string]$ADDomain="", [parameter(Mandatory=$False)] [string]$ADForest=$Env:USERDNSDOMAIN, [parameter(ParameterSetName="Word",Mandatory=$False)] [parameter(ParameterSetName="PDF",Mandatory=$False)] [Alias("CA")] [ValidateNotNullOrEmpty()] [string]$CompanyAddress="", [parameter(ParameterSetName="Word",Mandatory=$False)] [parameter(ParameterSetName="PDF",Mandatory=$False)] [Alias("CE")] [ValidateNotNullOrEmpty()] [string]$CompanyEmail="", [parameter(ParameterSetName="Word",Mandatory=$False)] [parameter(ParameterSetName="PDF",Mandatory=$False)] [Alias("CF")] [ValidateNotNullOrEmpty()] [string]$CompanyFax="", [parameter(ParameterSetName="Word",Mandatory=$False)] [parameter(ParameterSetName="PDF",Mandatory=$False)] [Alias("CN")] [ValidateNotNullOrEmpty()] [string]$CompanyName="", [parameter(ParameterSetName="Word",Mandatory=$False)] [parameter(ParameterSetName="PDF",Mandatory=$False)] [Alias("CPh")] [ValidateNotNullOrEmpty()] [string]$CompanyPhone="", [parameter(Mandatory=$False)] [Alias("ServerName")] [string]$ComputerName=$Env:USERDNSDOMAIN, [parameter(ParameterSetName="Word",Mandatory=$False)] [parameter(ParameterSetName="PDF",Mandatory=$False)] [Alias("CP")] [ValidateNotNullOrEmpty()] [string]$CoverPage="Sideline", [parameter(Mandatory=$False)] [Switch]$DCDNSInfo=$False, [parameter(Mandatory=$False)] [Switch]$Dev=$False, [parameter(Mandatory=$False)] [string]$Folder="", [parameter(Mandatory=$False)] [Switch]$GPOInheritance=$False, [parameter(Mandatory=$False)] [Switch]$Hardware=$False, [parameter(Mandatory=$False)] [Alias("IU")] [Switch]$IncludeUserInfo=$False, [parameter(Mandatory=$False)] [Switch]$Log=$False, [parameter(Mandatory=$False)] [Alias("MAX")] [Switch]$MaxDetails=$False, [parameter(Mandatory=$False)] [Alias("SI")] [Switch]$ScriptInfo=$False, [parameter(Mandatory=$False)] [array]$Section="All", [parameter(Mandatory=$False )] [Switch]$Services=$False, [parameter(ParameterSetName="Word",Mandatory=$False)] [parameter(ParameterSetName="PDF",Mandatory=$False)] [Alias("UN")] [ValidateNotNullOrEmpty()] [string]$UserName=$env:username, [parameter(Mandatory=$False)] [string]$SmtpServer="", [parameter(Mandatory=$False)] [int]$SmtpPort=25, [parameter(Mandatory=$False)] [switch]$UseSSL=$False, [parameter(Mandatory=$False)] [string]$From="", [parameter(Mandatory=$False)] [string]$To="" ) #webster@carlwebster.com #Created by Carl Webster and Michael B. Smith #webster@carlwebster.com #@carlwebster on Twitter #https://www.CarlWebster.com # #michael@smithcons.com #@essentialexch on Twitter #https://www.essential.exchange/blog/ # #Created on April 10, 2014 #Version 1.0 released to the community on May 31, 2014 # #Version 2.0 is based on version 1.20 # #Version 2.26 8-May-2020 # Add checking for a Word version of 0, which indicates the Office installation needs repairing # Add Receive Side Scaling setting to Function OutputNICItem # Change color variables $wdColorGray15 and $wdColorGray05 from [long] to [int] # Change location of the -Dev, -Log, and -ScriptInfo output files from the script folder to the -Folder location (Thanks to Guy Leech for the "suggestion") # Change Text output to use [System.Text.StringBuilder] # Updated Functions Line and SaveAndCloseTextDocument # Reformatted the terminating Write-Error messages to make them more visible and readable in the console # Update Function SetWordCellFormat to change parameter $BackgroundColor to [int] # Update Functions GetComputerWMIInfo and OutputNicInfo to fix two bugs in NIC Power Management settings # #Version 2.25 21-Apr-2020 # Remove the SMTP parameterset and manually verify the parameters # Reorder parameters # Update Function SendEmail to handle anonymous unauthenticated email # Update Help Text with examples # #Version 2.24 13-Feb-2020 # Fixed several variable name typos # General code cleanup # Updated the following Exchange Schema Versions: # "15312" = "Exchange 2013 CU7 through CU23" # "15317" = "Exchange 2016 Preview and RTM" # "15332" = "Exchange 2016 CU7 through CU15" # "17000" = "Exchange 2019 RTM/CU1" # "17001" = "Exchange 2019 CU2-CU4" # #Version 2.23 17-Dec-2019 # Fix Swedish Table of Contents (Thanks to Johan Kallio) # From # 'sv-' { 'Automatisk innehållsförteckning2'; Break } # To # 'sv-' { 'Automatisk innehållsförteckn2'; Break } # Updated help text # #Version 2.22 14-Feb-2019 # Added a line under the OU table stating how many OUs are not protected # Added color $wdColorYellow # Added Exchange schema version 17000 for Exchange 2019 # Added to the "Gathering user misc data" section, the following console message if there are more than 100,000 user accounts in AD: # There are $($UsersCount) user accounts to process. The following 17 actions will take a long time. Be patient. # Changed section heading "Domain trusts" to "Domain Trusts" to match the capitalization of other sections # Changed several $Var -eq $Null to $Null -eq $Var and on Get-Process line for WinWord (thanks to MBS) # Changed test for "No Certification Authority Root(s) were retrieved" by Michael B. Smith who contributed the original code # For HTML and Text output, for Heading1 and Heading2 output, added "/// " and " \\\" surrounding the heading text # This will help for those of us who read reports that contain > 100,000 OUs and users # and > 1,000 GPOs # Removed "Preview" from Windows Server 2019 AD Schema version 88 # Remove unused variables # Updated help text # #Version 2.21 11-Nov-2018 # For HTML output, reverted the output Hardware and Service functions back to using $rowdata = @() # Using $rowdata = New-Object System.Collections.ArrayList did not always work, which is weird # #Version 2.20 28-Sep-2018 # Added Domain Functional Level of 7 for Windows Server 2016 # Added Forest Functional Level of 7 for Windows Server 2016 # Added Domain Schema version 88 for Server 2019 Preview # Added to Domain Information: # Last logon replication interval # Public key required password rolling (2012+) # Added to Forest Information, Domain Controllers: # Operation System # Server Core (Y/N) # Changed "renamed" to "changed" as it was freaking people out thinking I was renaming their domain or computer # Changed all but the Word and HTML arrays from "@() +=" to "New-Object System.Collections.ArrayList .Add()" # Changed the code where I checked for Singletons and -is [array] to use @() around the cmdlets so the result # is always an array. Thanks to fellow CTP Sam Jacobs for the tip. This reduced the code by almost 500 lines. # Changed the functions getting the computer WMI hardware and service info to use # "New-Object System.Collections.ArrayList .Add()" for Word and HTML tables # Changed the width of the Domain Controllers table to accommodate the new columns # Change the width of the AD Schema Items table to match the other tables # Remove all the duplicate $VarName = $Null from Function ProcessDomains # Reorder Change Log so the most recent is on top and the oldest is at the bottom # Reorder most of the domain properties to be in alphabetical order # Reorder most of the forest properties to be in alphabetical order # Updated Exchange schema version information # #Version 2.19 5-Apr-2018 # Added Event Log information to each domain controller and an appendix # If the script is run from an elevated PowerShell session by a user with Domain Admin rights # Added Operating System information to Functions GetComputerWMIInfo and OutputComputerItem # Code clean-up for most recommendations made by Visual Studio Code # #Version 2.18 10-Mar-2018 # Added Log switch to create a transcript log # #Version 2.17 8-Dec-2017 # Updated Function WriteHTMLLine with fixes from the script template # #Version 2.16 4-Dec-2017 # Add checking for users with home drive set in Active Directory Users and Computers (ADUC) # Added function OutputHDUserInfo # Add checking for users with RDS home drive set in ADUC # Added function from Jeff Hicks Get-RDUserSetting # Added function OutputRDSHDUserInfo # Add checking for users whose Primary Group is not Domain Users # Added function OutputPGUserInfo # Add "DC: " in fron tof the domain controller name, in text output, for domain controller information # Add new parameter ADDomain to restrict report to a single domain in a multi-domain Forest # Add schema extension checking for the following items and add to Forest section: # 'User-Account-Control', #Flags that control the behavior of a user account # 'msNPAllowDialin', #RAS Server # 'ms-Mcs-AdmPwd', #LAPS # 'ms-Mcs-AdmPwdExpirationTime', #LAPS # 'ms-SMS-Assignment-Site-Code', #SCCM # 'ms-SMS-Capabilities', #SCCM # 'msRTCSIP-UserRoutingGroupId', #Lync/SfB # 'msRTCSIP-MirrorBackEndServer' #Lync/SfB # 'ms-exch-schema-version-pt' #Exchange # Add "Site: " in front of Site name when listing Subnets, Servers, and Connection Objects # Remove several large blocks of code that had been commented out # Revise how $LinkedGPOs and $InheritedGPOs variables are set to work around invalid property # name DisplayName when collection is empty # Sort Enabled Scopes in AD Optional Features # Text output changes to tabular data: # Domain Controllers (in Forest section) # AD Schema Items (in Forest section) # Services # Organizational Units # Domain Admins # Enterprise Admins # Schema Admins # Users with AdminCount=1 # Updated Exchange schema versions # Updated help text # When reporting on the domain controllers in the Forest, if unable to get data from a domain controller, # instead of reporting "Unknown", use: # Unable to retrieve Global Catalog status on # Unable to retrieve Read-only status on # When run for a single domain in a multi-domain forest # Revise gathering list of domains # Revise testing for $ComputerName # Revise variable $ADContext in Function ProcessAllDCsInTheForest # #Version 2.15 26-Jun-2017 # Added new parameter MaxDetails: # This is the same as using the following parameters: # DCDNSInfo # GPOInheritance # HardWare # IncludeUserInfo # Services # Fixed wrong loop variable for CA # Removed code that made sure all Parameters were set to default values if for some reason they did exist or values were $Null # Reordered the parameters in the help text and parameter list so they match and are grouped better # Replaced _SetDocumentProperty function with Jim Moyle's Set-DocumentProperty function # Updated Function ProcessScriptEnd for the new Cover Page properties and Parameters # Updated Function ShowScriptOptions for the new Cover Page properties and Parameters # Updated Function UpdateDocumentProperties for the new Cover Page properties and Parameters # Updated help text # #Version 2.14 12-May-2017 # Add Certificate Authority Information section to Forest Information # Check for the following CA related errors: # Possible error: There are more than one Certification Authority Root(s) # Error: Certification Authority Root(s) exist, but no Certification Authority Issuers(s) (also known as Enrollment Agents) exist # Error: More Certification Authority Root(s) exist than there are Certification Authority Issuers(s) (also known as Enrollment Agents) # Error: Certification Authority Issuers(s) (also known as Enrollment Agents) exist, but no Certification Authority Root(s) exist # Change "Users with AdminCount=1 ($($AdminsCountStr) members):" to "Users with AdminCount=1 ($($AdminsCountStr) users):" # Reorder the Forest Information section # #Version 2.13 13-Feb-2017 # Fix French wording for Table of Contents 2 # #Version 2.12 10-Nov-2016 # Add Chinese language support # Add table for Time Server information if script is run from an elevated PowerShell session # Remove "Appendix A" from DC DNS Info table # #Version 2.11 6-Nov-2016 # Fixed Domain Trust Attributes (thanks GT) # Fixed several Write-Warning statements that had no message # Fixed using -AddDateTime with -HTML # Remove duplicate setting for $Script:Title # Reworked the use of [gc]::Collect() # #Version 2.10 released on 19-Oct-2016 (Happy Birthday Linz) # Add a new parameter, IncludeUserInfo # Add to the User Miscellaneous Data section, outputs a table with the SamAccountName # and DistinguishedName of the users in the All Users counts # Add to the Domain section, listing Fine Grained Password Policies # Add to the Forest section, Tombstone Lifetime # Changed the HTML header for AD Optional Features from a table header to a section header # Changed "Site and Services" heading to "Sites and Services" # Fixed formatting issues with HTML headings output # The $AdminsCountStr variable was used, when it should not have been used, # when privileged groups had no members or members could not be retrieved # Update Forest and Domain schema tables for the released Server 2016 product # #Version 2.0 released 26-Sep-2016 # # Added a parameter, GPOInheritance, to set whether to use the new GPOs by OU with linked and inherited GPOs # By default, the script will use the original GPOs by OU with only directly linked GPOs # Added a function, ElevatedSession, to test if the PowerShell session running the script is elevated # Added a Section parameter to allow specific sections only to be in the report # Valid options are: # Forest # Sites # Domains (includes Domain Controllers and optional Hardware, Services and DCDNSInfo) # OUs (Organizational Units) # Groups # GPOs # Misc (Miscellaneous data) # All (Default value) # Added AD Database, logfile and SYSVOL locations along with AD Database size # Added AD Optional Features # Added an alias to the ComputerName parameter to ServerName # Added checking the NIC's "Allow the computer to turn off this device to save power" setting # Added requires line for the GroupPolicy module # Added Text and HTML output # Added Time Server information # Change checking for both DA rights and an elevated session for the Time Server and AD file locations # If the check fails, added a warning message as write-host with white foreground # Change object created for DCDNSINFO to storing blank data for DNS properties # HTML output would not display a row if any of the DNS values were blank or Null # Fix test for domain admin rights for the user account # Fix text and HTML output for the -Hardware parameter # Fix the DC DNS Info table to handle two IP Addresses # Fix the ProcessScriptSetup function # Add checking for an elevated PowerShell session # Add checking for DA rights and elevated session if using DCDNSINFO parameter # Add checking for elevated session if using the Hardware and Services parameters # Change the elevated session warning to write-host with a white foreground to make it stand out # Fix where variables were not being set properly # Fix the user name not being displayed in the warning message about not having domain admin rights # If no ComputerName value is entered and $ComputerName –eq $Env:USERDNSDOMAIN then the script queries for # a domain controller that is also a global catalog server and will use that as the value for ComputerName # Modified GPOs by OU to show if the GPO is Linked or Inherited # This necessitated a change in the Word/PDF/HTML table format # Modified GPOs by OU to use the Get-GPInheritance cmdlet to list all directly linked and inherited GPOs # Organize script into functions and regions # Replace Jeremy Saunder's Get-ComputerCountByOS function with his latest version # The ADForest parameter is no longer mandatory. It will now default to the value in $Env:USERDNSDOMAIN # The ComputerName parameter will also now default to the value in $Env:USERDNSDOMAIN # Update forest and domain schema information for the latest updates for Exchange 2013/2016 and Server 2016 TP4/5 # Update help text # Update Verbose messages for testing to see if -ComputerName is a domain controller # Worked around Get-ADDomainController issue when run from a child domain # Set-StrictMode -Version 2 #force on $PSDefaultParameterValues = @{"*:Verbose"=$True} $SaveEAPreference = $ErrorActionPreference $ErrorActionPreference = 'SilentlyContinue' If($Null -eq $MSWord) { If($Text -or $HTML -or $PDF) { $MSWord = $False } Else { $MSWord = $True } } If($MSWord -eq $False -and $PDF -eq $False -and $Text -eq $False -and $HTML -eq $False) { $MSWord = $True } Write-Verbose "$(Get-Date): Testing output parameters" If($MSWord) { Write-Verbose "$(Get-Date): MSWord is set" } ElseIf($PDF) { Write-Verbose "$(Get-Date): PDF is set" } ElseIf($Text) { Write-Verbose "$(Get-Date): Text is set" } ElseIf($HTML) { Write-Verbose "$(Get-Date): HTML is set" } Else { $ErrorActionPreference = $SaveEAPreference Write-Verbose "$(Get-Date): Unable to determine output parameter" If($Null -eq $MSWord) { Write-Verbose "$(Get-Date): MSWord is Null" } ElseIf($Null -eq $PDF) { Write-Verbose "$(Get-Date): PDF is Null" } ElseIf($Null -eq $Text) { Write-Verbose "$(Get-Date): Text is Null" } ElseIf($Null -eq $HTML) { Write-Verbose "$(Get-Date): HTML is Null" } Else { Write-Verbose "$(Get-Date): MSWord is $($MSWord)" Write-Verbose "$(Get-Date): PDF is $($PDF)" Write-Verbose "$(Get-Date): Text is $($Text)" Write-Verbose "$(Get-Date): HTML is $($HTML)" } Write-Error " `n`n `t`t Unable to determine output parameter. `n`n `t`t Script cannot continue. `n`n " Exit } If($ADForest -ne "" -and $ADDomain -ne "") { #2.16 #Make ADForest equal to ADDomain so no code has to change in the script $ADForest = $ADDomain } #If the MaxDetails parameter is used, set a bunch of stuff true If($MaxDetails) { $DCDNSInfo = $True $GPOInheritance = $True $HardWare = $True $IncludeUserInfo = $True $Services = $True $Section = "All" } $ValidSection = $False Switch ($Section) { "Forest" {$ValidSection = $True} "Sites" {$ValidSection = $True} "Domains" {$ValidSection = $True} "OUs" {$ValidSection = $True} "Groups" {$ValidSection = $True} "GPOs" {$ValidSection = $True} "Misc" {$ValidSection = $True} "All" {$ValidSection = $True} } If($ValidSection -eq $False) { $ErrorActionPreference = $SaveEAPreference Write-Error -Message " `n`n `t`t The Section parameter specified, $($Section), is an invalid Section option. `n`n `t`t Valid options are: `t`tForest `t`tSites `t`tDomains `t`tOUs `t`tGroups `t`tGPOs `t`tMisc `t`tAll `t`t Script cannot continue. `n`n " Exit } If($Folder -ne "") { Write-Verbose "$(Get-Date): Testing folder path" #does it exist If(Test-Path $Folder -EA 0) { #it exists, now check to see if it is a folder and not a file If(Test-Path $Folder -pathType Container -EA 0) { #it exists and it is a folder Write-Verbose "$(Get-Date): Folder path $Folder exists and is a folder" } Else { #it exists but it is a file not a folder Write-Error " `n`n `t`t Folder $Folder is a file, not a folder. `n`n `t`t Script cannot continue. `n`n " Exit } } Else { #does not exist Write-Error " `n`n `t`t Folder $Folder does not exist. `n`n `t`t Script cannot continue. `n`n " Exit } } If($Folder -eq "") { $Script:pwdpath = $pwd.Path } Else { $Script:pwdpath = $Folder } If($Script:pwdpath.EndsWith("\")) { #remove the trailing \ $Script:pwdpath = $Script:pwdpath.SubString(0, ($Script:pwdpath.Length - 1)) } #V2.18 added If($Log) { #start transcript logging $Script:LogPath = "$($Script:pwdpath)\ADDSDocScriptTranscript_$(Get-Date -f yyyy-MM-dd_HHmm).txt" try { Start-Transcript -Path $Script:LogPath -Force -Verbose:$false | Out-Null Write-Verbose "$(Get-Date): Transcript/log started at $Script:LogPath" $Script:StartLog = $true } catch { Write-Verbose "$(Get-Date): Transcript/log failed at $Script:LogPath" $Script:StartLog = $false } } If($Dev) { $Error.Clear() $Script:DevErrorFile = "$($Script:pwdpath)\ADInventoryScriptErrors_$(Get-Date -f yyyy-MM-dd_HHmm).txt" } If(![String]::IsNullOrEmpty($SmtpServer) -and [String]::IsNullOrEmpty($From) -and [String]::IsNullOrEmpty($To)) { Write-Error " `n`n `t`t You specified an SmtpServer but did not include a From or To email address. `n`n `t`t Script cannot continue. `n`n" Exit } If(![String]::IsNullOrEmpty($SmtpServer) -and [String]::IsNullOrEmpty($From) -and ![String]::IsNullOrEmpty($To)) { Write-Error " `n`n `t`t You specified an SmtpServer and a To email address but did not include a From email address. `n`n `t`t Script cannot continue. `n`n" Exit } If(![String]::IsNullOrEmpty($SmtpServer) -and [String]::IsNullOrEmpty($To) -and ![String]::IsNullOrEmpty($From)) { Write-Error " `n`n `t`t You specified an SmtpServer and a From email address but did not include a To email address. `n`n `t`t Script cannot continue. `n`n" Exit } If(![String]::IsNullOrEmpty($From) -and ![String]::IsNullOrEmpty($To) -and [String]::IsNullOrEmpty($SmtpServer)) { Write-Error " `n`n `t`t You specified From and To email addresses but did not include the SmtpServer. `n`n `t`t Script cannot continue. `n`n" Exit } If(![String]::IsNullOrEmpty($From) -and [String]::IsNullOrEmpty($SmtpServer)) { Write-Error " `n`n `t`t You specified a From email address but did not include the SmtpServer. `n`n `t`t Script cannot continue. `n`n" Exit } If(![String]::IsNullOrEmpty($To) -and [String]::IsNullOrEmpty($SmtpServer)) { Write-Error " `n`n `t`t You specified a To email address but did not include the SmtpServer. `n`n `t`t Script cannot continue. `n`n" Exit } #region initialize variables for word html and text [string]$Script:RunningOS = (Get-WmiObject -class Win32_OperatingSystem -EA 0).Caption If($MSWord -or $PDF) { #try and fix the issue with the $CompanyName variable $Script:CoName = $CompanyName Write-Verbose "$(Get-Date): CoName is $($Script:CoName)" #the following values were attained from #http://msdn.microsoft.com/en-us/library/office/aa211923(v=office.11).aspx [int]$wdAlignPageNumberRight = 2 [int]$wdColorGray15 = 14277081 [int]$wdColorGray05 = 15987699 [int]$wdMove = 0 [int]$wdSeekMainDocument = 0 [int]$wdSeekPrimaryFooter = 4 [int]$wdStory = 6 [long]$wdColorRed = 255 [int]$wdColorBlack = 0 [long]$wdColorYellow = 65535 #added in ADDS script V2.22 [int]$wdWord2007 = 12 [int]$wdWord2010 = 14 [int]$wdWord2013 = 15 [int]$wdWord2016 = 16 [int]$wdFormatDocumentDefault = 16 [int]$wdFormatPDF = 17 #http://blogs.technet.com/b/heyscriptingguy/archive/2006/03/01/how-can-i-right-align-a-single-column-in-a-word-table.aspx #http://msdn.microsoft.com/en-us/library/office/ff835817%28v=office.15%29.aspx [int]$wdAlignParagraphLeft = 0 [int]$wdAlignParagraphCenter = 1 [int]$wdAlignParagraphRight = 2 #http://msdn.microsoft.com/en-us/library/office/ff193345%28v=office.15%29.aspx [int]$wdCellAlignVerticalTop = 0 [int]$wdCellAlignVerticalCenter = 1 [int]$wdCellAlignVerticalBottom = 2 #http://msdn.microsoft.com/en-us/library/office/ff844856%28v=office.15%29.aspx [int]$wdAutoFitFixed = 0 [int]$wdAutoFitContent = 1 [int]$wdAutoFitWindow = 2 #http://msdn.microsoft.com/en-us/library/office/ff821928%28v=office.15%29.aspx [int]$wdAdjustNone = 0 [int]$wdAdjustProportional = 1 [int]$wdAdjustFirstColumn = 2 [int]$wdAdjustSameWidth = 3 [int]$PointsPerTabStop = 36 [int]$Indent0TabStops = 0 * $PointsPerTabStop [int]$Indent1TabStops = 1 * $PointsPerTabStop [int]$Indent2TabStops = 2 * $PointsPerTabStop [int]$Indent3TabStops = 3 * $PointsPerTabStop [int]$Indent4TabStops = 4 * $PointsPerTabStop # http://www.thedoctools.com/index.php?show=wt_style_names_english_danish_german_french [int]$wdStyleHeading1 = -2 [int]$wdStyleHeading2 = -3 [int]$wdStyleHeading3 = -4 [int]$wdStyleHeading4 = -5 [int]$wdStyleNoSpacing = -158 [int]$wdTableGrid = -155 #http://groovy.codehaus.org/modules/scriptom/1.6.0/scriptom-office-2K3-tlb/apidocs/org/codehaus/groovy/scriptom/tlb/office/word/WdLineStyle.html [int]$wdLineStyleNone = 0 [int]$wdLineStyleSingle = 1 [int]$wdHeadingFormatTrue = -1 [int]$wdHeadingFormatFalse = 0 } If($HTML) { Set-Variable htmlredmask -Option AllScope -Value "#FF0000" 4>$Null Set-Variable htmlcyanmask -Option AllScope -Value "#00FFFF" 4>$Null Set-Variable htmlbluemask -Option AllScope -Value "#0000FF" 4>$Null Set-Variable htmldarkbluemask -Option AllScope -Value "#0000A0" 4>$Null Set-Variable htmllightbluemask -Option AllScope -Value "#ADD8E6" 4>$Null Set-Variable htmlpurplemask -Option AllScope -Value "#800080" 4>$Null Set-Variable htmlyellowmask -Option AllScope -Value "#FFFF00" 4>$Null Set-Variable htmllimemask -Option AllScope -Value "#00FF00" 4>$Null Set-Variable htmlmagentamask -Option AllScope -Value "#FF00FF" 4>$Null Set-Variable htmlwhitemask -Option AllScope -Value "#FFFFFF" 4>$Null Set-Variable htmlsilvermask -Option AllScope -Value "#C0C0C0" 4>$Null Set-Variable htmlgraymask -Option AllScope -Value "#808080" 4>$Null Set-Variable htmlblackmask -Option AllScope -Value "#000000" 4>$Null Set-Variable htmlorangemask -Option AllScope -Value "#FFA500" 4>$Null Set-Variable htmlmaroonmask -Option AllScope -Value "#800000" 4>$Null Set-Variable htmlgreenmask -Option AllScope -Value "#008000" 4>$Null Set-Variable htmlolivemask -Option AllScope -Value "#808000" 4>$Null Set-Variable htmlbold -Option AllScope -Value 1 4>$Null Set-Variable htmlitalics -Option AllScope -Value 2 4>$Null Set-Variable htmlred -Option AllScope -Value 4 4>$Null Set-Variable htmlcyan -Option AllScope -Value 8 4>$Null Set-Variable htmlblue -Option AllScope -Value 16 4>$Null Set-Variable htmldarkblue -Option AllScope -Value 32 4>$Null Set-Variable htmllightblue -Option AllScope -Value 64 4>$Null Set-Variable htmlpurple -Option AllScope -Value 128 4>$Null Set-Variable htmlyellow -Option AllScope -Value 256 4>$Null Set-Variable htmllime -Option AllScope -Value 512 4>$Null Set-Variable htmlmagenta -Option AllScope -Value 1024 4>$Null Set-Variable htmlwhite -Option AllScope -Value 2048 4>$Null Set-Variable htmlsilver -Option AllScope -Value 4096 4>$Null Set-Variable htmlgray -Option AllScope -Value 8192 4>$Null Set-Variable htmlolive -Option AllScope -Value 16384 4>$Null Set-Variable htmlorange -Option AllScope -Value 32768 4>$Null Set-Variable htmlmaroon -Option AllScope -Value 65536 4>$Null Set-Variable htmlgreen -Option AllScope -Value 131072 4>$Null Set-Variable htmlblack -Option AllScope -Value 262144 4>$Null } If($TEXT) { [System.Text.StringBuilder] $global:Output = New-Object System.Text.StringBuilder( 16384 ) } #endregion #region email function Function SendEmail { Param([string]$Attachments) Write-Verbose "$(Get-Date): Prepare to email" $emailAttachment = $Attachments $emailSubject = $Script:Title $emailBody = @" Hello,

$Script:Title is attached. "@ If($Dev) { Out-File -FilePath $Script:DevErrorFile -InputObject $error 4>$Null } $error.Clear() If($From -Like "anonymous@*") { #https://serverfault.com/questions/543052/sending-unauthenticated-mail-through-ms-exchange-with-powershell-windows-server $anonUsername = "anonymous" $anonPassword = ConvertTo-SecureString -String "anonymous" -AsPlainText -Force $anonCredentials = New-Object System.Management.Automation.PSCredential($anonUsername,$anonPassword) If($UseSSL) { Send-MailMessage -Attachments $emailAttachment -Body $emailBody -BodyAsHtml -From $From ` -Port $SmtpPort -SmtpServer $SmtpServer -Subject $emailSubject -To $To ` -UseSSL -credential $anonCredentials *>$Null } Else { Send-MailMessage -Attachments $emailAttachment -Body $emailBody -BodyAsHtml -From $From ` -Port $SmtpPort -SmtpServer $SmtpServer -Subject $emailSubject -To $To ` -credential $anonCredentials *>$Null } If($?) { Write-Verbose "$(Get-Date): Email successfully sent using anonymous credentials" } ElseIf(!$?) { $e = $error[0] Write-Verbose "$(Get-Date): Email was not sent:" Write-Warning "$(Get-Date): Exception: $e.Exception" } } Else { If($UseSSL) { Write-Verbose "$(Get-Date): Trying to send email using current user's credentials with SSL" Send-MailMessage -Attachments $emailAttachment -Body $emailBody -BodyAsHtml -From $From ` -Port $SmtpPort -SmtpServer $SmtpServer -Subject $emailSubject -To $To ` -UseSSL *>$Null } Else { Write-Verbose "$(Get-Date): Trying to send email using current user's credentials without SSL" Send-MailMessage -Attachments $emailAttachment -Body $emailBody -BodyAsHtml -From $From ` -Port $SmtpPort -SmtpServer $SmtpServer -Subject $emailSubject -To $To *>$Null } If(!$?) { $e = $error[0] #error 5.7.57 is O365 and error 5.7.0 is gmail If($null -ne $e.Exception -and $e.Exception.ToString().Contains("5.7")) { #The server response was: 5.7.xx SMTP; Client was not authenticated to send anonymous mail during MAIL FROM Write-Verbose "$(Get-Date): Current user's credentials failed. Ask for usable credentials." If($Dev) { Out-File -FilePath $Script:DevErrorFile -InputObject $error -Append 4>$Null } $error.Clear() $emailCredentials = Get-Credential -UserName $From -Message "Enter the password to send email" If($UseSSL) { Send-MailMessage -Attachments $emailAttachment -Body $emailBody -BodyAsHtml -From $From ` -Port $SmtpPort -SmtpServer $SmtpServer -Subject $emailSubject -To $To ` -UseSSL -credential $emailCredentials *>$Null } Else { Send-MailMessage -Attachments $emailAttachment -Body $emailBody -BodyAsHtml -From $From ` -Port $SmtpPort -SmtpServer $SmtpServer -Subject $emailSubject -To $To ` -credential $emailCredentials *>$Null } If($?) { Write-Verbose "$(Get-Date): Email successfully sent using new credentials" } ElseIf(!$?) { $e = $error[0] Write-Verbose "$(Get-Date): Email was not sent:" Write-Warning "$(Get-Date): Exception: $e.Exception" } } Else { Write-Verbose "$(Get-Date): Email was not sent:" Write-Warning "$(Get-Date): Exception: $e.Exception" } } } } #endregion #region code for -hardware switch Function GetComputerWMIInfo { Param([string]$RemoteComputerName) # original work by Kees Baggerman, # Senior Technical Consultant @ Inter Access # k.baggerman@myvirtualvision.com # @kbaggerman on Twitter # http://blog.myvirtualvision.com # modified 1-May-2014 to work in trusted AD Forests and using different domain admin credentials # modified 17-Aug-2016 to fix a few issues with Text and HTML output # modified 29-Apr-2018 to change from Arrays to New-Object System.Collections.ArrayList #Get Computer info Write-Verbose "$(Get-Date): `t`tProcessing WMI Computer information" Write-Verbose "$(Get-Date): `t`t`tHardware information" If($MSWord -or $PDF) { WriteWordLine 3 0 "Computer Information: $($RemoteComputerName)" WriteWordLine 4 0 "General Computer" } ElseIf($Text) { Line 0 "Computer Information: $($RemoteComputerName)" Line 1 "General Computer" } ElseIf($HTML) { WriteHTMLLine 3 0 "Computer Information: $($RemoteComputerName)" WriteHTMLLine 4 0 "General Computer" } Try { $Results = Get-WmiObject -computername $RemoteComputerName win32_computersystem } Catch { $Results = $Null } If($? -and $Null -ne $Results) { $ComputerItems = $Results | Select-Object Manufacturer, Model, Domain, ` @{N="TotalPhysicalRam"; E={[math]::round(($_.TotalPhysicalMemory / 1GB),0)}}, ` NumberOfProcessors, NumberOfLogicalProcessors $Results = $Null [string]$ComputerOS = (Get-WmiObject -class Win32_OperatingSystem -computername $RemoteComputerName -EA 0).Caption ForEach($Item in $ComputerItems) { OutputComputerItem $Item $ComputerOS } } ElseIf(!$?) { Write-Verbose "$(Get-Date): Get-WmiObject win32_computersystem failed for $($RemoteComputerName)" Write-Warning "Get-WmiObject win32_computersystem failed for $($RemoteComputerName)" If($MSWORD -or $PDF) { WriteWordLine 0 2 "Get-WmiObject win32_computersystem failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteWordLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteWordLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteWordLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } ElseIf($Text) { Line 2 "Get-WmiObject win32_computersystem failed for $($RemoteComputerName)" Line 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" Line 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" Line 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." Line 2 "" } ElseIf($HTML) { WriteHTMLLine 0 2 "Get-WmiObject win32_computersystem failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteHTMLLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteHTMLLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteHTMLLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } } Else { Write-Verbose "$(Get-Date): No results Returned for Computer information" If($MSWORD -or $PDF) { WriteWordLine 0 2 "No results Returned for Computer information" "" $Null 0 $False $True } ElseIf($Text) { Line 2 "No results Returned for Computer information" } ElseIf($HTML) { WriteHTMLLine 0 2 "No results Returned for Computer information" "" $Null 0 $False $True } } #Get Disk info Write-Verbose "$(Get-Date): `t`t`tDrive information" If($MSWord -or $PDF) { WriteWordLine 4 0 "Drive(s)" } ElseIf($Text) { Line 1 "Drive(s)" } ElseIf($HTML) { WriteHTMLLine 4 0 "Drive(s)" } Try { $Results = Get-WmiObject -computername $RemoteComputerName Win32_LogicalDisk } Catch { $Results = $Null } If($? -and $Null -ne $Results) { $drives = $Results | Select-Object caption, @{N="drivesize"; E={[math]::round(($_.size / 1GB),0)}}, filesystem, @{N="drivefreespace"; E={[math]::round(($_.freespace / 1GB),0)}}, volumename, drivetype, volumedirty, volumeserialnumber $Results = $Null ForEach($drive in $drives) { If($drive.caption -ne "A:" -and $drive.caption -ne "B:") { OutputDriveItem $drive } } } ElseIf(!$?) { Write-Verbose "$(Get-Date): Get-WmiObject Win32_LogicalDisk failed for $($RemoteComputerName)" Write-Warning "Get-WmiObject Win32_LogicalDisk failed for $($RemoteComputerName)" If($MSWORD -or $PDF) { WriteWordLine 0 2 "Get-WmiObject Win32_LogicalDisk failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteWordLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteWordLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteWordLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } ElseIf($Text) { Line 2 "Get-WmiObject Win32_LogicalDisk failed for $($RemoteComputerName)" Line 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" Line 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" Line 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." } ElseIf($HTML) { WriteHTMLLine 0 2 "Get-WmiObject Win32_LogicalDisk failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteHTMLLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteHTMLLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteHTMLLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } } Else { Write-Verbose "$(Get-Date): No results Returned for Drive information" If($MSWORD -or $PDF) { WriteWordLine 0 2 "No results Returned for Drive information" "" $Null 0 $False $True } ElseIf($Text) { Line 2 "No results Returned for Drive information" } ElseIf($HTML) { WriteHTMLLine 0 2 "No results Returned for Drive information" "" $Null 0 $False $True } } #Get CPU's and stepping Write-Verbose "$(Get-Date): `t`t`tProcessor information" If($MSWord -or $PDF) { WriteWordLine 4 0 "Processor(s)" } ElseIf($Text) { Line 1 "Processor(s)" } ElseIf($HTML) { WriteHTMLLine 4 0 "Processor(s)" } Try { $Results = Get-WmiObject -computername $RemoteComputerName win32_Processor } Catch { $Results = $Null } If($? -and $Null -ne $Results) { $Processors = $Results | Select-Object availability, name, description, maxclockspeed, l2cachesize, l3cachesize, numberofcores, numberoflogicalprocessors $Results = $Null ForEach($processor in $processors) { OutputProcessorItem $processor } } ElseIf(!$?) { Write-Verbose "$(Get-Date): Get-WmiObject win32_Processor failed for $($RemoteComputerName)" Write-Warning "Get-WmiObject win32_Processor failed for $($RemoteComputerName)" If($MSWORD -or $PDF) { WriteWordLine 0 2 "Get-WmiObject win32_Processor failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteWordLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteWordLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteWordLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } ElseIf($Text) { Line 2 "Get-WmiObject win32_Processor failed for $($RemoteComputerName)" Line 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" Line 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" Line 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." } ElseIf($HTML) { WriteHTMLLine 0 2 "Get-WmiObject win32_Processor failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteHTMLLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteHTMLLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteHTMLLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } } Else { Write-Verbose "$(Get-Date): No results Returned for Processor information" If($MSWORD -or $PDF) { WriteWordLine 0 2 "No results Returned for Processor information" "" $Null 0 $False $True } ElseIf($Text) { Line 2 "No results Returned for Processor information" } ElseIf($HTML) { WriteHTMLLine 0 2 "No results Returned for Processor information" "" $Null 0 $False $True } } #Get Nics Write-Verbose "$(Get-Date): `t`t`tNIC information" If($MSWord -or $PDF) { WriteWordLine 4 0 "Network Interface(s)" } ElseIf($Text) { Line 1 "Network Interface(s)" } ElseIf($HTML) { WriteHTMLLine 4 0 "Network Interface(s)" } [bool]$GotNics = $True Try { $Results = Get-WmiObject -computername $RemoteComputerName win32_networkadapterconfiguration } Catch { $Results = $Null } If($? -and $Null -ne $Results) { $Nics = $Results | Where-Object {$Null -ne $_.ipaddress} $Results = $Null If($Null -eq $Nics) { $GotNics = $False } Else { $GotNics = !($Nics.__PROPERTY_COUNT -eq 0) } If($GotNics) { ForEach($nic in $nics) { Try { $ThisNic = Get-WmiObject -computername $RemoteComputerName win32_networkadapter | Where-Object {$_.index -eq $nic.index} } Catch { $ThisNic = $Null } If($? -and $Null -ne $ThisNic) { OutputNicItem $Nic $ThisNic $RemoteComputerName } ElseIf(!$?) { Write-Warning "$(Get-Date): Error retrieving NIC information" Write-Verbose "$(Get-Date): Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" Write-Warning "Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" If($MSWORD -or $PDF) { WriteWordLine 0 2 "Error retrieving NIC information" "" $Null 0 $False $True WriteWordLine 0 2 "Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteWordLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteWordLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteWordLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } ElseIf($Text) { Line 2 "Error retrieving NIC information" Line 2 "Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" Line 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" Line 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" Line 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." } ElseIf($HTML) { WriteHTMLLine 0 2 "Error retrieving NIC information" "" $Null 0 $False $True WriteHTMLLine 0 2 "Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteHTMLLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteHTMLLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteHTMLLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } } Else { Write-Verbose "$(Get-Date): No results Returned for NIC information" If($MSWORD -or $PDF) { WriteWordLine 0 2 "No results Returned for NIC information" "" $Null 0 $False $True } ElseIf($Text) { Line 2 "No results Returned for NIC information" } ElseIf($HTML) { WriteHTMLLine 0 2 "No results Returned for NIC information" "" $Null 0 $False $True } } } } } ElseIf(!$?) { Write-Warning "$(Get-Date): Error retrieving NIC configuration information" Write-Verbose "$(Get-Date): Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" Write-Warning "Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" If($MSWORD -or $PDF) { WriteWordLine 0 2 "Error retrieving NIC configuration information" "" $Null 0 $False $True WriteWordLine 0 2 "Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteWordLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteWordLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteWordLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } ElseIf($Text) { Line 2 "Error retrieving NIC configuration information" Line 2 "Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" Line 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" Line 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" Line 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." } ElseIf($HTML) { WriteHTMLLine 0 2 "Error retrieving NIC configuration information" "" $Null 0 $False $True WriteHTMLLine 0 2 "Get-WmiObject win32_networkadapterconfiguration failed for $($RemoteComputerName)" "" $Null 0 $False $True WriteHTMLLine 0 2 "On $($RemoteComputerName) you may need to run winmgmt /verifyrepository" "" $Null 0 $False $True WriteHTMLLine 0 2 "and winmgmt /salvagerepository. If this is a trusted Forest, you may" "" $Null 0 $False $True WriteHTMLLine 0 2 "need to rerun the script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } } Else { Write-Verbose "$(Get-Date): No results Returned for NIC configuration information" If($MSWORD -or $PDF) { WriteWordLine 0 2 "No results Returned for NIC configuration information" "" $Null 0 $False $True } ElseIf($Text) { Line 2 "No results Returned for NIC configuration information" } ElseIf($HTML) { WriteHTMLLine 0 2 "No results Returned for NIC configuration information" "" $Null 0 $False $True } } If($MSWORD -or $PDF) { WriteWordLine 0 0 "" } ElseIf($Text) { Line 0 "" } ElseIf($HTML) { WriteHTMLLine 0 0 "" } } Function OutputComputerItem { Param([object]$Item, [string]$OS) If($MSWord -or $PDF) { $ItemInformation = New-Object System.Collections.ArrayList $ItemInformation.Add(@{ Data = "Manufacturer"; Value = $Item.manufacturer; }) > $Null $ItemInformation.Add(@{ Data = "Model"; Value = $Item.model; }) > $Null $ItemInformation.Add(@{ Data = "Domain"; Value = $Item.domain; }) > $Null $ItemInformation.Add(@{ Data = "Operating System"; Value = $OS; }) > $Null $ItemInformation.Add(@{ Data = "Total Ram"; Value = "$($Item.totalphysicalram) GB"; }) > $Null $ItemInformation.Add(@{ Data = "Physical Processors (sockets)"; Value = $Item.NumberOfProcessors; }) > $Null $ItemInformation.Add(@{ Data = "Logical Processors (cores w/HT)"; Value = $Item.NumberOfLogicalProcessors; }) > $Null $Table = AddWordTable -Hashtable $ItemInformation ` -Columns Data,Value ` -List ` -AutoFit $wdAutoFitFixed; ## Set first column format SetWordCellFormat -Collection $Table.Columns.Item(1).Cells -Bold -BackgroundColor $wdColorGray15; ## IB - set column widths without recursion $Table.Columns.Item(1).Width = 150; $Table.Columns.Item(2).Width = 200; $Table.Rows.SetLeftIndent($Indent0TabStops,$wdAdjustNone) FindWordDocumentEnd $Table = $Null WriteWordLine 0 0 "" } ElseIf($Text) { Line 2 "Manufacturer`t`t`t: " $Item.manufacturer Line 2 "Model`t`t`t`t: " $Item.model Line 2 "Domain`t`t`t`t: " $Item.domain Line 2 "Operating System`t`t: " $OS Line 2 "Total Ram`t`t`t: $($Item.totalphysicalram) GB" Line 2 "Physical Processors (sockets)`t: " $Item.NumberOfProcessors Line 2 "Logical Processors (cores w/HT)`t: " $Item.NumberOfLogicalProcessors Line 2 "" } ElseIf($HTML) { $rowdata = @() $columnHeaders = @("Manufacturer",($htmlsilver -bor $htmlbold),$Item.manufacturer,$htmlwhite) $rowdata += @(,('Model',($htmlsilver -bor $htmlbold),$Item.model,$htmlwhite)) $rowdata += @(,('Domain',($htmlsilver -bor $htmlbold),$Item.domain,$htmlwhite)) $rowdata += @(,('Total Ram',($htmlsilver -bor $htmlbold),"$($Item.totalphysicalram) GB",$htmlwhite)) $rowdata += @(,('Physical Processors (sockets)',($htmlsilver -bor $htmlbold),$Item.NumberOfProcessors,$htmlwhite)) $rowdata += @(,('Logical Processors (cores w/HT)',($htmlsilver -bor $htmlbold),$Item.NumberOfLogicalProcessors,$htmlwhite)) $msg = "" $columnWidths = @("150px","200px") FormatHTMLTable $msg -rowarray $rowdata -columnArray $columnheaders -fixedWidth $columnWidths -tablewidth "350" WriteHTMLLine 0 0 " " } } Function OutputDriveItem { Param([object]$Drive) $xDriveType = "" Switch ($drive.drivetype) { 0 {$xDriveType = "Unknown"; Break} 1 {$xDriveType = "No Root Directory"; Break} 2 {$xDriveType = "Removable Disk"; Break} 3 {$xDriveType = "Local Disk"; Break} 4 {$xDriveType = "Network Drive"; Break} 5 {$xDriveType = "Compact Disc"; Break} 6 {$xDriveType = "RAM Disk"; Break} Default {$xDriveType = "Unknown"; Break} } $xVolumeDirty = "" If(![String]::IsNullOrEmpty($drive.volumedirty)) { If($drive.volumedirty) { $xVolumeDirty = "Yes" } Else { $xVolumeDirty = "No" } } If($MSWORD -or $PDF) { $DriveInformation = New-Object System.Collections.ArrayList $DriveInformation.Add(@{ Data = "Caption"; Value = $Drive.caption; }) > $Null $DriveInformation.Add(@{ Data = "Size"; Value = "$($drive.drivesize) GB"; }) > $Null If(![String]::IsNullOrEmpty($drive.filesystem)) { $DriveInformation.Add(@{ Data = "File System"; Value = $Drive.filesystem; }) > $Null } $DriveInformation.Add(@{ Data = "Free Space"; Value = "$($drive.drivefreespace) GB"; }) > $Null If(![String]::IsNullOrEmpty($drive.volumename)) { $DriveInformation.Add(@{ Data = "Volume Name"; Value = $Drive.volumename; }) > $Null } If(![String]::IsNullOrEmpty($drive.volumedirty)) { $DriveInformation.Add(@{ Data = "Volume is Dirty"; Value = $xVolumeDirty; }) > $Null } If(![String]::IsNullOrEmpty($drive.volumeserialnumber)) { $DriveInformation.Add(@{ Data = "Volume Serial Number"; Value = $Drive.volumeserialnumber; }) > $Null } $DriveInformation.Add(@{ Data = "Drive Type"; Value = $xDriveType; }) > $Null $Table = AddWordTable -Hashtable $DriveInformation ` -Columns Data,Value ` -List ` -AutoFit $wdAutoFitFixed; ## Set first column format SetWordCellFormat -Collection $Table.Columns.Item(1).Cells ` -Bold ` -BackgroundColor $wdColorGray15; ## IB - set column widths without recursion $Table.Columns.Item(1).Width = 150; $Table.Columns.Item(2).Width = 200; $Table.Rows.SetLeftIndent($Indent0TabStops,$wdAdjustProportional) FindWordDocumentEnd $Table = $Null WriteWordLine 0 2 "" } ElseIf($Text) { Line 2 "Caption`t`t: " $drive.caption Line 2 "Size`t`t: $($drive.drivesize) GB" If(![String]::IsNullOrEmpty($drive.filesystem)) { Line 2 "File System`t: " $drive.filesystem } Line 2 "Free Space`t: $($drive.drivefreespace) GB" If(![String]::IsNullOrEmpty($drive.volumename)) { Line 2 "Volume Name`t: " $drive.volumename } If(![String]::IsNullOrEmpty($drive.volumedirty)) { Line 2 "Volume is Dirty`t: " $xVolumeDirty } If(![String]::IsNullOrEmpty($drive.volumeserialnumber)) { Line 2 "Volume Serial #`t: " $drive.volumeserialnumber } Line 2 "Drive Type`t: " $xDriveType Line 2 "" } ElseIf($HTML) { $rowdata = @() $columnHeaders = @("Caption",($htmlsilver -bor $htmlbold),$Drive.caption,$htmlwhite) $rowdata += @(,('Size',($htmlsilver -bor $htmlbold),"$($drive.drivesize) GB",$htmlwhite)) If(![String]::IsNullOrEmpty($drive.filesystem)) { $rowdata += @(,('File System',($htmlsilver -bor $htmlbold),$Drive.filesystem,$htmlwhite)) } $rowdata += @(,('Free Space',($htmlsilver -bor $htmlbold),"$($drive.drivefreespace) GB",$htmlwhite)) If(![String]::IsNullOrEmpty($drive.volumename)) { $rowdata += @(,('Volume Name',($htmlsilver -bor $htmlbold),$Drive.volumename,$htmlwhite)) } If(![String]::IsNullOrEmpty($drive.volumedirty)) { $rowdata += @(,('Volume is Dirty',($htmlsilver -bor $htmlbold),$xVolumeDirty,$htmlwhite)) } If(![String]::IsNullOrEmpty($drive.volumeserialnumber)) { $rowdata += @(,('Volume Serial Number',($htmlsilver -bor $htmlbold),$Drive.volumeserialnumber,$htmlwhite)) } $rowdata += @(,('Drive Type',($htmlsilver -bor $htmlbold),$xDriveType,$htmlwhite)) $msg = "" $columnWidths = @("150px","200px") FormatHTMLTable $msg -rowarray $rowdata -columnArray $columnheaders -fixedWidth $columnWidths -tablewidth "350" WriteHTMLLine 0 0 " " } } Function OutputProcessorItem { Param([object]$Processor) $xAvailability = "" Switch ($processor.availability) { 1 {$xAvailability = "Other"; Break} 2 {$xAvailability = "Unknown"; Break} 3 {$xAvailability = "Running or Full Power"; Break} 4 {$xAvailability = "Warning"; Break} 5 {$xAvailability = "In Test"; Break} 6 {$xAvailability = "Not Applicable"; Break} 7 {$xAvailability = "Power Off"; Break} 8 {$xAvailability = "Off Line"; Break} 9 {$xAvailability = "Off Duty"; Break} 10 {$xAvailability = "Degraded"; Break} 11 {$xAvailability = "Not Installed"; Break} 12 {$xAvailability = "Install Error"; Break} 13 {$xAvailability = "Power Save - Unknown"; Break} 14 {$xAvailability = "Power Save - Low Power Mode"; Break} 15 {$xAvailability = "Power Save - Standby"; Break} 16 {$xAvailability = "Power Cycle"; Break} 17 {$xAvailability = "Power Save - Warning"; Break} Default {$xAvailability = "Unknown"; Break} } If($MSWORD -or $PDF) { $ProcessorInformation = New-Object System.Collections.ArrayList $ProcessorInformation.Add(@{ Data = "Name"; Value = $Processor.name; }) > $Null $ProcessorInformation.Add(@{ Data = "Description"; Value = $Processor.description; }) > $Null $ProcessorInformation.Add(@{ Data = "Max Clock Speed"; Value = "$($processor.maxclockspeed) MHz"; }) > $Null If($processor.l2cachesize -gt 0) { $ProcessorInformation.Add(@{ Data = "L2 Cache Size"; Value = "$($processor.l2cachesize) KB"; }) > $Null } If($processor.l3cachesize -gt 0) { $ProcessorInformation.Add(@{ Data = "L3 Cache Size"; Value = "$($processor.l3cachesize) KB"; }) > $Null } If($processor.numberofcores -gt 0) { $ProcessorInformation.Add(@{ Data = "Number of Cores"; Value = $Processor.numberofcores; }) > $Null } If($processor.numberoflogicalprocessors -gt 0) { $ProcessorInformation.Add(@{ Data = "Number of Logical Processors (cores w/HT)"; Value = $Processor.numberoflogicalprocessors; }) > $Null } $ProcessorInformation.Add(@{ Data = "Availability"; Value = $xAvailability; }) > $Null $Table = AddWordTable -Hashtable $ProcessorInformation ` -Columns Data,Value ` -List ` -AutoFit $wdAutoFitFixed; ## Set first column format SetWordCellFormat -Collection $Table.Columns.Item(1).Cells -Bold -BackgroundColor $wdColorGray15; ## IB - set column widths without recursion $Table.Columns.Item(1).Width = 150; $Table.Columns.Item(2).Width = 200; $Table.Rows.SetLeftIndent($Indent0TabStops,$wdAdjustProportional) FindWordDocumentEnd $Table = $Null WriteWordLine 0 0 "" } ElseIf($Text) { Line 2 "Name`t`t`t`t: " $processor.name Line 2 "Description`t`t`t: " $processor.description Line 2 "Max Clock Speed`t`t`t: $($processor.maxclockspeed) MHz" If($processor.l2cachesize -gt 0) { Line 2 "L2 Cache Size`t`t`t: $($processor.l2cachesize) KB" } If($processor.l3cachesize -gt 0) { Line 2 "L3 Cache Size`t`t`t: $($processor.l3cachesize) KB" } If($processor.numberofcores -gt 0) { Line 2 "# of Cores`t`t`t: " $processor.numberofcores } If($processor.numberoflogicalprocessors -gt 0) { Line 2 "# of Logical Procs (cores w/HT)`t: " $processor.numberoflogicalprocessors } Line 2 "Availability`t`t`t: " $xAvailability Line 2 "" } ElseIf($HTML) { $rowdata = @() $columnHeaders = @("Name",($htmlsilver -bor $htmlbold),$Processor.name,$htmlwhite) $rowdata += @(,('Description',($htmlsilver -bor $htmlbold),$Processor.description,$htmlwhite)) $rowdata += @(,('Max Clock Speed',($htmlsilver -bor $htmlbold),"$($processor.maxclockspeed) MHz",$htmlwhite)) If($processor.l2cachesize -gt 0) { $rowdata += @(,('L2 Cache Size',($htmlsilver -bor $htmlbold),"$($processor.l2cachesize) KB",$htmlwhite)) } If($processor.l3cachesize -gt 0) { $rowdata += @(,('L3 Cache Size',($htmlsilver -bor $htmlbold),"$($processor.l3cachesize) KB",$htmlwhite)) } If($processor.numberofcores -gt 0) { $rowdata += @(,('Number of Cores',($htmlsilver -bor $htmlbold),$Processor.numberofcores,$htmlwhite)) } If($processor.numberoflogicalprocessors -gt 0) { $rowdata += @(,('Number of Logical Processors (cores w/HT)',($htmlsilver -bor $htmlbold),$Processor.numberoflogicalprocessors,$htmlwhite)) } $rowdata += @(,('Availability',($htmlsilver -bor $htmlbold),$xAvailability,$htmlwhite)) $msg = "" $columnWidths = @("150px","200px") FormatHTMLTable $msg -rowarray $rowdata -columnArray $columnheaders -fixedWidth $columnWidths -tablewidth "350" WriteHTMLLine 0 0 " " } } Function OutputNicItem { Param([object]$Nic, [object]$ThisNic, [string]$RemoteComputerName) $powerMgmt = Get-WmiObject -computername $RemoteComputerName MSPower_DeviceEnable -Namespace root\wmi | Where-Object{$_.InstanceName -match [regex]::Escape($ThisNic.PNPDeviceID)} If($? -and $Null -ne $powerMgmt) { If($powerMgmt.Enable -eq $True) { $PowerSaving = "Enabled" } Else { $PowerSaving = "Disabled" } } Else { $PowerSaving = "N/A" } $xAvailability = "" Switch ($ThisNic.availability) { 1 {$xAvailability = "Other"; Break} 2 {$xAvailability = "Unknown"; Break} 3 {$xAvailability = "Running or Full Power"; Break} 4 {$xAvailability = "Warning"; Break} 5 {$xAvailability = "In Test"; Break} 6 {$xAvailability = "Not Applicable"; Break} 7 {$xAvailability = "Power Off"; Break} 8 {$xAvailability = "Off Line"; Break} 9 {$xAvailability = "Off Duty"; Break} 10 {$xAvailability = "Degraded"; Break} 11 {$xAvailability = "Not Installed"; Break} 12 {$xAvailability = "Install Error"; Break} 13 {$xAvailability = "Power Save - Unknown"; Break} 14 {$xAvailability = "Power Save - Low Power Mode"; Break} 15 {$xAvailability = "Power Save - Standby"; Break} 16 {$xAvailability = "Power Cycle"; Break} 17 {$xAvailability = "Power Save - Warning"; Break} Default {$xAvailability = "Unknown"; Break} } #attempt to get Receive Side Scaling setting $RSSEnabled = "N/A" Try { #https://ios.developreference.com/article/10085450/How+do+I+enable+VRSS+(Virtual+Receive+Side+Scaling)+for+a+Windows+VM+without+relying+on+Enable-NetAdapterRSS%3F $RSSEnabled = (Get-WmiObject -ComputerName $RemoteComputerName MSFT_NetAdapterRssSettingData -Namespace "root\StandardCimV2" -ea 0).Enabled If($RSSEnabled) { $RSSEnabled = "Enabled" } ELse { $RSSEnabled = "Disabled" } } Catch { $RSSEnabled = "Not available on $Script:RunningOS" } $xIPAddress = New-Object System.Collections.ArrayList ForEach($IPAddress in $Nic.ipaddress) { $xIPAddress.Add("$($IPAddress)") > $Null } $xIPSubnet = New-Object System.Collections.ArrayList ForEach($IPSubnet in $Nic.ipsubnet) { $xIPSubnet.Add("$($IPSubnet)") > $Null } If($Null -ne $nic.dnsdomainsuffixsearchorder -and $nic.dnsdomainsuffixsearchorder.length -gt 0) { $nicdnsdomainsuffixsearchorder = $nic.dnsdomainsuffixsearchorder $xnicdnsdomainsuffixsearchorder = New-Object System.Collections.ArrayList ForEach($DNSDomain in $nicdnsdomainsuffixsearchorder) { $xnicdnsdomainsuffixsearchorder.Add("$($DNSDomain)") > $Null } } If($Null -ne $nic.dnsserversearchorder -and $nic.dnsserversearchorder.length -gt 0) { $nicdnsserversearchorder = $nic.dnsserversearchorder $xnicdnsserversearchorder = New-Object System.Collections.ArrayList ForEach($DNSServer in $nicdnsserversearchorder) { $xnicdnsserversearchorder.Add("$($DNSServer)") > $Null } } $xdnsenabledforwinsresolution = "" If($nic.dnsenabledforwinsresolution) { $xdnsenabledforwinsresolution = "Yes" } Else { $xdnsenabledforwinsresolution = "No" } $xTcpipNetbiosOptions = "" Switch ($nic.TcpipNetbiosOptions) { 0 {$xTcpipNetbiosOptions = "Use NetBIOS setting from DHCP Server"; Break} 1 {$xTcpipNetbiosOptions = "Enable NetBIOS"; Break} 2 {$xTcpipNetbiosOptions = "Disable NetBIOS"; Break} Default {$xTcpipNetbiosOptions = "Unknown"; Break} } $xwinsenablelmhostslookup = "" If($nic.winsenablelmhostslookup) { $xwinsenablelmhostslookup = "Yes" } Else { $xwinsenablelmhostslookup = "No" } If($MSWORD -or $PDF) { $NicInformation = New-Object System.Collections.ArrayList $NicInformation.Add(@{ Data = "Name"; Value = $ThisNic.Name; }) > $Null If($ThisNic.Name -ne $nic.description) { $NicInformation.Add(@{ Data = "Description"; Value = $Nic.description; }) > $Null } $NicInformation.Add(@{ Data = "Connection ID"; Value = $ThisNic.NetConnectionID; }) > $Null If(validObject $Nic Manufacturer) { $NicInformation.Add(@{ Data = "Manufacturer"; Value = $Nic.manufacturer; }) > $Null } $NicInformation.Add(@{ Data = "Availability"; Value = $xAvailability; }) > $Null $NicInformation.Add(@{ Data = "Allow the computer to turn off this device to save power"; Value = $PowerSaving; }) > $Null $NicInformation.Add(@{ Data = "Receive Side Scaling"; Value = $RSSEnabled; }) > $Null $NicInformation.Add(@{ Data = "Physical Address"; Value = $Nic.macaddress; }) > $Null If($xIPAddress.Count -gt 1) { $NicInformation.Add(@{ Data = "IP Address"; Value = $xIPAddress[0]; }) > $Null $NicInformation.Add(@{ Data = "Default Gateway"; Value = $Nic.Defaultipgateway; }) > $Null $NicInformation.Add(@{ Data = "Subnet Mask"; Value = $xIPSubnet[0]; }) > $Null $cnt = -1 ForEach($tmp in $xIPAddress) { $cnt++ If($cnt -gt 0) { $NicInformation.Add(@{ Data = "IP Address"; Value = $tmp; }) > $Null $NicInformation.Add(@{ Data = "Subnet Mask"; Value = $xIPSubnet[$cnt]; }) > $Null } } } Else { $NicInformation.Add(@{ Data = "IP Address"; Value = $xIPAddress; }) > $Null $NicInformation.Add(@{ Data = "Default Gateway"; Value = $Nic.Defaultipgateway; }) > $Null $NicInformation.Add(@{ Data = "Subnet Mask"; Value = $xIPSubnet; }) > $Null } If($nic.dhcpenabled) { $DHCPLeaseObtainedDate = $nic.ConvertToDateTime($nic.dhcpleaseobtained) $DHCPLeaseExpiresDate = $nic.ConvertToDateTime($nic.dhcpleaseexpires) $NicInformation.Add(@{ Data = "DHCP Enabled"; Value = $Nic.dhcpenabled; }) > $Null $NicInformation.Add(@{ Data = "DHCP Lease Obtained"; Value = $dhcpleaseobtaineddate; }) > $Null $NicInformation.Add(@{ Data = "DHCP Lease Expires"; Value = $dhcpleaseexpiresdate; }) > $Null $NicInformation.Add(@{ Data = "DHCP Server"; Value = $Nic.dhcpserver; }) > $Null } If(![String]::IsNullOrEmpty($nic.dnsdomain)) { $NicInformation.Add(@{ Data = "DNS Domain"; Value = $Nic.dnsdomain; }) > $Null } If($Null -ne $nic.dnsdomainsuffixsearchorder -and $nic.dnsdomainsuffixsearchorder.length -gt 0) { $NicInformation.Add(@{ Data = "DNS Search Suffixes"; Value = $xnicdnsdomainsuffixsearchorder[0]; }) > $Null $cnt = -1 ForEach($tmp in $xnicdnsdomainsuffixsearchorder) { $cnt++ If($cnt -gt 0) { $NicInformation.Add(@{ Data = ""; Value = $tmp; }) > $Null } } } $NicInformation.Add(@{ Data = "DNS WINS Enabled"; Value = $xdnsenabledforwinsresolution; }) > $Null If($Null -ne $nic.dnsserversearchorder -and $nic.dnsserversearchorder.length -gt 0) { $NicInformation.Add(@{ Data = "DNS Servers"; Value = $xnicdnsserversearchorder[0]; }) > $Null $cnt = -1 ForEach($tmp in $xnicdnsserversearchorder) { $cnt++ If($cnt -gt 0) { $NicInformation.Add(@{ Data = ""; Value = $tmp; }) > $Null } } } $NicInformation.Add(@{ Data = "NetBIOS Setting"; Value = $xTcpipNetbiosOptions; }) > $Null $NicInformation.Add(@{ Data = "WINS: Enabled LMHosts"; Value = $xwinsenablelmhostslookup; }) > $Null If(![String]::IsNullOrEmpty($nic.winshostlookupfile)) { $NicInformation.Add(@{ Data = "Host Lookup File"; Value = $Nic.winshostlookupfile; }) > $Null } If(![String]::IsNullOrEmpty($nic.winsprimaryserver)) { $NicInformation.Add(@{ Data = "Primary Server"; Value = $Nic.winsprimaryserver; }) > $Null } If(![String]::IsNullOrEmpty($nic.winssecondaryserver)) { $NicInformation.Add(@{ Data = "Secondary Server"; Value = $Nic.winssecondaryserver; }) > $Null } If(![String]::IsNullOrEmpty($nic.winsscopeid)) { $NicInformation.Add(@{ Data = "Scope ID"; Value = $Nic.winsscopeid; }) > $Null } $Table = AddWordTable -Hashtable $NicInformation -Columns Data,Value -List -AutoFit $wdAutoFitFixed; ## Set first column format SetWordCellFormat -Collection $Table.Columns.Item(1).Cells -Bold -BackgroundColor $wdColorGray15; ## IB - set column widths without recursion $Table.Columns.Item(1).Width = 150; $Table.Columns.Item(2).Width = 200; $Table.Rows.SetLeftIndent($Indent0TabStops,$wdAdjustProportional) FindWordDocumentEnd $Table = $Null WriteWordLine 0 0 "" } ElseIf($Text) { Line 2 "Name`t`t`t: " $ThisNic.Name If($ThisNic.Name -ne $nic.description) { Line 2 "Description`t`t: " $nic.description } Line 2 "Connection ID`t`t: " $ThisNic.NetConnectionID If(validObject $Nic Manufacturer) { Line 2 "Manufacturer`t`t: " $Nic.manufacturer } Line 2 "Availability`t`t: " $xAvailability Line 2 "Allow computer to turn " Line 2 "off device to save power: " $PowerSaving Line 2 "Receive Side Scaling`t: " $RSSEnabled Line 2 "Physical Address`t: " $nic.macaddress Line 2 "IP Address`t`t: " $xIPAddress[0] $cnt = -1 ForEach($tmp in $xIPAddress) { $cnt++ If($cnt -gt 0) { Line 5 " " $tmp } } Line 2 "Default Gateway`t`t: " $Nic.Defaultipgateway Line 2 "Subnet Mask`t`t: " $xIPSubnet[0] $cnt = -1 ForEach($tmp in $xIPSubnet) { $cnt++ If($cnt -gt 0) { Line 5 " " $tmp } } If($nic.dhcpenabled) { $DHCPLeaseObtainedDate = $nic.ConvertToDateTime($nic.dhcpleaseobtained) $DHCPLeaseExpiresDate = $nic.ConvertToDateTime($nic.dhcpleaseexpires) Line 2 "DHCP Enabled`t`t: " $nic.dhcpenabled Line 2 "DHCP Lease Obtained`t: " $dhcpleaseobtaineddate Line 2 "DHCP Lease Expires`t: " $dhcpleaseexpiresdate Line 2 "DHCP Server`t`t:" $nic.dhcpserver } If(![String]::IsNullOrEmpty($nic.dnsdomain)) { Line 2 "DNS Domain`t`t: " $nic.dnsdomain } If($Null -ne $nic.dnsdomainsuffixsearchorder -and $nic.dnsdomainsuffixsearchorder.length -gt 0) { [int]$x = 1 Line 2 "DNS Search Suffixes`t: " $xnicdnsdomainsuffixsearchorder[0] $cnt = -1 ForEach($tmp in $xnicdnsdomainsuffixsearchorder) { $cnt++ If($cnt -gt 0) { Line 5 " " $tmp } } } Line 2 "DNS WINS Enabled`t: " $xdnsenabledforwinsresolution If($Null -ne $nic.dnsserversearchorder -and $nic.dnsserversearchorder.length -gt 0) { [int]$x = 1 Line 2 "DNS Servers`t`t: " $xnicdnsserversearchorder[0] $cnt = -1 ForEach($tmp in $xnicdnsserversearchorder) { $cnt++ If($cnt -gt 0) { Line 5 " " $tmp } } } Line 2 "NetBIOS Setting`t`t: " $xTcpipNetbiosOptions Line 2 "WINS:" Line 3 "Enabled LMHosts`t: " $xwinsenablelmhostslookup If(![String]::IsNullOrEmpty($nic.winshostlookupfile)) { Line 3 "Host Lookup File`t: " $nic.winshostlookupfile } If(![String]::IsNullOrEmpty($nic.winsprimaryserver)) { Line 3 "Primary Server`t: " $nic.winsprimaryserver } If(![String]::IsNullOrEmpty($nic.winssecondaryserver)) { Line 3 "Secondary Server`t: " $nic.winssecondaryserver } If(![String]::IsNullOrEmpty($nic.winsscopeid)) { Line 3 "Scope ID`t`t: " $nic.winsscopeid } Line 0 "" } ElseIf($HTML) { $rowdata = @() $columnHeaders = @("Name",($htmlsilver -bor $htmlbold),$ThisNic.Name,$htmlwhite) If($ThisNic.Name -ne $nic.description) { $rowdata += @(,('Description',($htmlsilver -bor $htmlbold),$Nic.description,$htmlwhite)) } $rowdata += @(,('Connection ID',($htmlsilver -bor $htmlbold),$ThisNic.NetConnectionID,$htmlwhite)) If(validObject $Nic Manufacturer) { $rowdata += @(,('Manufacturer',($htmlsilver -bor $htmlbold),$Nic.manufacturer,$htmlwhite)) } $rowdata += @(,('Availability',($htmlsilver -bor $htmlbold),$xAvailability,$htmlwhite)) $rowdata += @(,('Allow the computer to turn off this device to save power',($htmlsilver -bor $htmlbold),$PowerSaving,$htmlwhite)) $rowdata += @(,('Physical Address',($htmlsilver -bor $htmlbold),$Nic.macaddress,$htmlwhite)) $rowdata += @(,('Receive Side Scaling',($htmlsilver -bor $htmlbold),$RSSEnabled,$htmlwhite)) $rowdata += @(,('IP Address',($htmlsilver -bor $htmlbold),$xIPAddress[0],$htmlwhite)) $cnt = -1 ForEach($tmp in $xIPAddress) { $cnt++ If($cnt -gt 0) { $rowdata += @(,('IP Address',($htmlsilver -bor $htmlbold),$tmp,$htmlwhite)) } } $rowdata += @(,('Default Gateway',($htmlsilver -bor $htmlbold),$Nic.Defaultipgateway[0],$htmlwhite)) $rowdata += @(,('Subnet Mask',($htmlsilver -bor $htmlbold),$xIPSubnet[0],$htmlwhite)) $cnt = -1 ForEach($tmp in $xIPSubnet) { $cnt++ If($cnt -gt 0) { $rowdata += @(,('Subnet Mask',($htmlsilver -bor $htmlbold),$tmp,$htmlwhite)) } } If($nic.dhcpenabled) { $DHCPLeaseObtainedDate = $nic.ConvertToDateTime($nic.dhcpleaseobtained) $DHCPLeaseExpiresDate = $nic.ConvertToDateTime($nic.dhcpleaseexpires) $rowdata += @(,('DHCP Enabled',($htmlsilver -bor $htmlbold),$Nic.dhcpenabled,$htmlwhite)) $rowdata += @(,('DHCP Lease Obtained',($htmlsilver -bor $htmlbold),$dhcpleaseobtaineddate,$htmlwhite)) $rowdata += @(,('DHCP Lease Expires',($htmlsilver -bor $htmlbold),$dhcpleaseexpiresdate,$htmlwhite)) $rowdata += @(,('DHCP Server',($htmlsilver -bor $htmlbold),$Nic.dhcpserver,$htmlwhite)) } If(![String]::IsNullOrEmpty($nic.dnsdomain)) { $rowdata += @(,('DNS Domain',($htmlsilver -bor $htmlbold),$Nic.dnsdomain,$htmlwhite)) } If($Null -ne $nic.dnsdomainsuffixsearchorder -and $nic.dnsdomainsuffixsearchorder.length -gt 0) { $rowdata += @(,('DNS Search Suffixes',($htmlsilver -bor $htmlbold),$xnicdnsdomainsuffixsearchorder[0],$htmlwhite)) $cnt = -1 ForEach($tmp in $xnicdnsdomainsuffixsearchorder) { $cnt++ If($cnt -gt 0) { $rowdata += @(,('',($htmlsilver -bor $htmlbold),$tmp,$htmlwhite)) } } } $rowdata += @(,('DNS WINS Enabled',($htmlsilver -bor $htmlbold),$xdnsenabledforwinsresolution,$htmlwhite)) If($Null -ne $nic.dnsserversearchorder -and $nic.dnsserversearchorder.length -gt 0) { $rowdata += @(,('DNS Servers',($htmlsilver -bor $htmlbold),$xnicdnsserversearchorder[0],$htmlwhite)) $cnt = -1 ForEach($tmp in $xnicdnsserversearchorder) { $cnt++ If($cnt -gt 0) { $rowdata += @(,('',($htmlsilver -bor $htmlbold),$tmp,$htmlwhite)) } } } $rowdata += @(,('NetBIOS Setting',($htmlsilver -bor $htmlbold),$xTcpipNetbiosOptions,$htmlwhite)) $rowdata += @(,('WINS: Enabled LMHosts',($htmlsilver -bor $htmlbold),$xwinsenablelmhostslookup,$htmlwhite)) If(![String]::IsNullOrEmpty($nic.winshostlookupfile)) { $rowdata += @(,('Host Lookup File',($htmlsilver -bor $htmlbold),$Nic.winshostlookupfile,$htmlwhite)) } If(![String]::IsNullOrEmpty($nic.winsprimaryserver)) { $rowdata += @(,('Primary Server',($htmlsilver -bor $htmlbold),$Nic.winsprimaryserver,$htmlwhite)) } If(![String]::IsNullOrEmpty($nic.winssecondaryserver)) { $rowdata += @(,('Secondary Server',($htmlsilver -bor $htmlbold),$Nic.winssecondaryserver,$htmlwhite)) } If(![String]::IsNullOrEmpty($nic.winsscopeid)) { $rowdata += @(,('Scope ID',($htmlsilver -bor $htmlbold),$Nic.winsscopeid,$htmlwhite)) } $msg = "" $columnWidths = @("150px","200px") FormatHTMLTable $msg -rowarray $rowdata -columnArray $columnheaders -fixedWidth $columnWidths -tablewidth "350" WriteHTMLLine 0 0 " " } } #endregion #region GetComputerServices Function GetComputerServices { Param([string]$RemoteComputerName) # modified 29-Apr-2018 to change from Arrays to New-Object System.Collections.ArrayList #Get Computer services info Write-Verbose "$(Get-Date): `t`tProcessing Computer services information" If($MSWORD -or $PDF) { WriteWordLine 3 0 "Services" } ElseIf($Text) { Line 0 "Services" } ElseIf($HTML) { WriteHTMLLine 3 0 "Services" } Try { #Iain Brighton optimization 5-Jun-2014 #Replaced with a single call to retrieve services via WMI. The repeated ## "Get-WMIObject Win32_Service -Filter" calls were the major delays in the script. ## If we need to retrieve the StartUp type might as well just use WMI. #V2.20 changed to @() $Services = @(Get-WMIObject Win32_Service -ComputerName $RemoteComputerName | Sort-Object DisplayName) } Catch { $Services = $Null } If($? -and $Null -ne $Services) { [int]$NumServices = $Services.count Write-Verbose "$(Get-Date): `t`t$($NumServices) Services found" If($MSWord -or $PDF) { WriteWordLine 0 1 "Services ($NumServices Services found)" $ServicesWordTable = New-Object System.Collections.ArrayList ## Create an array of hashtables to store references of cells that we wish to highlight after the table has been added $HighlightedCells = New-Object System.Collections.ArrayList ## Seed the $Services row index from the second row [int] $CurrentServiceIndex = 2; } ElseIf($Text) { Line 0 "Services ($NumServices Services found)" Line 0 "" #V2.16 addition [int]$MaxDisplayNameLength = ($Services.DisplayName | Measure-Object -Maximum -Property Length).Maximum If($MaxDisplayNameLength -gt 12) #12 is length of "Display Name" { #10 is length of "Display Name" minus 2 to allow for spacing between columns Line 1 ("Display Name" + (' ' * ($MaxDisplayNameLength - 10))) -NoNewLine } Else { Line 1 "Display Name " -NoNewLine } Line 1 "Status " -NoNewLine Line 1 "Startup Type" } ElseIf($HTML) { WriteHTMLLine 0 1 "Services ($NumServices Services found)" $rowdata = @() } ForEach($Service in $Services) { #Write-Verbose "$(Get-Date): `t`t`t Processing service $($Service.DisplayName)"; If($MSWord -or $PDF) { ## Add the required key/values to the hashtable $WordTableRowHash = @{ DisplayName = $Service.DisplayName; Status = $Service.State; StartMode = $Service.StartMode } ## Add the hash to the array $ServicesWordTable.Add($WordTableRowHash) > $Null ## Store "to highlight" cell references If($Service.State -like "Stopped" -and $Service.StartMode -like "Auto") { $HighlightedCells.Add(@{ Row = $CurrentServiceIndex; Column = 2; }) > $Null } $CurrentServiceIndex++; } ElseIf($Text) { #V2.16 change If(($Service.DisplayName).Length -lt ($MaxDisplayNameLength)) { [int]$NumOfSpaces = (($MaxDisplayNameLength) - ($Service.DisplayName.Length)) + 2 #+2 to allow for column spacing $tmp1 = ($($Service.DisplayName) + (' ' * $NumOfSPaces)) Line 1 $tmp1 -NoNewLine } Else { Line 1 "$($Service.DisplayName) " -NoNewLine } Line 1 "$($Service.State) " -NoNewLine Line 1 $Service.StartMode } ElseIf($HTML) { If($Service.State -like "Stopped" -and $Service.StartMode -like "Auto") { $HighlightedCells = $htmlred } Else { $HighlightedCells = $htmlwhite } $rowdata += @(,($Service.DisplayName,$htmlwhite, $Service.State,$HighlightedCells, $Service.StartMode,$htmlwhite)) } } If($MSWord -or $PDF) { ## Add the table to the document, using the hashtable (-Alt is short for -AlternateBackgroundColor!) $Table = AddWordTable -Hashtable $ServicesWordTable ` -Columns DisplayName, Status, StartMode ` -Headers "Display Name", "Status", "Startup Type" ` -AutoFit $wdAutoFitContent; ## IB - Set the header row format after the SetWordTableAlternateRowColor function as it will paint the header row! SetWordCellFormat -Collection $Table.Rows.Item(1).Cells -Bold -BackgroundColor $wdColorGray15; ## IB - Set the required highlighted cells SetWordCellFormat -Coordinates $HighlightedCells -Table $Table -Bold -BackgroundColor $wdColorRed -Solid; #indent the entire table 1 tab stop $Table.Rows.SetLeftIndent($Indent1TabStops,$wdAdjustProportional) FindWordDocumentEnd $Table = $Null WriteWordLine 0 0 "" } ElseIf($Text) { #V2.16 change Line 0 "" } ElseIf($HTML) { $columnHeaders = @('Display Name',($htmlsilver -bor $htmlbold),'Status',($htmlsilver -bor $htmlbold),'Startup Type',($htmlsilver -bor $htmlbold)) $msg = "" FormatHTMLTable $msg "auto" -rowArray $rowdata -columnArray $columnHeaders WriteHTMLLine 0 0 " " } } ElseIf(!$?) { Write-Warning "No services were retrieved." If($MSWORD -or $PDF) { WriteWordLine 0 0 "Warning: No Services were retrieved" "" $Null 0 $False $True WriteWordLine 0 1 "If this is a trusted Forest, you may need to rerun the" "" $Null 0 $False $True WriteWordLine 0 1 "script with Domain Admin credentials from the trusted Forest." "" $Null 0 $False $True } ElseIf($Text) { Line 0 "Warning: No Services were retrieved" Line 1 "If this is a trusted Forest, you may need to rerun the" Line 1 "script with Domain Admin credentials from the trusted Forest." } ElseIf($HTML) { WriteHTMLLine 0 0 "Warning: No Services were retrieved" "" $Null 0 $htmlbold WriteHTMLLine 0 1 "If this is a trusted Forest, you may need to rerun the" "" $Null 0 $htmlbold WriteHTMLLine 0 1 "script with Domain Admin credentials from the trusted Forest." "" $Null 0 $htmlbold } } Else { Write-Warning "Services retrieval was successful but no services were returned." If($MSWORD -or $PDF) { WriteWordLine 0 0 "Services retrieval was successful but no services were returned." "" $Null 0 $False $True } ElseIf($Text) { Line 0 "Services retrieval was successful but no services were returned." } ElseIf($HTML) { WriteHTMLLine 0 0 "Services retrieval was successful but no services were returned." "" $Null 0 $htmlbold } } } #endregion #region BuildDCDNSIPConfigTable Function BuildDCDNSIPConfigTable { Param([string]$RemoteComputerName, [string]$Site) [bool]$GotNics = $True Try { $Results = Get-WmiObject -computername $RemoteComputerName win32_networkadapterconfiguration } Catch { $Results = $Null } If($? -and $Null -ne $Results) { $Nics = $Results | Where-Object {$Null -ne $_.ipaddress} $Results = $Null If($Null -eq $Nics) { $GotNics = $False } Else { $GotNics = !($Nics.__PROPERTY_COUNT -eq 0) } If($GotNics) { ForEach($nic in $nics) { Try { $ThisNic = Get-WmiObject -computername $RemoteComputerName win32_networkadapter | Where-Object {$_.index -eq $nic.index} } Catch { $ThisNic = $Null } If($? -and $Null -ne $ThisNic) { Write-Verbose "$(Get-Date): `t`t`tGather DC DNS IP Config info" $xIPAddress = @() ForEach($IPAddress in $Nic.ipaddress) { $xIPAddress += "$($IPAddress)" } If($Null -ne $nic.dnsserversearchorder -and $nic.dnsserversearchorder.length -gt 0) { $nicdnsserversearchorder = $nic.dnsserversearchorder $xnicdnsserversearchorder = @() ForEach($DNSServer in $nicdnsserversearchorder) { $xnicdnsserversearchorder += "$($DNSServer)" } } $obj = New-Object -TypeName PSObject $obj | Add-Member -MemberType NoteProperty -Name DCName -Value $RemoteComputerName $obj | Add-Member -MemberType NoteProperty -Name DCSite -Value $Site If($xIPAddress.Count -gt 1) { $obj | Add-Member -MemberType NoteProperty -Name DCIpAddress1 -Value $xIPAddress[0] $obj | Add-Member -MemberType NoteProperty -Name DCIpAddress2 -Value $xIPAddress[1] } Else { $obj | Add-Member -MemberType NoteProperty -Name DCIpAddress1 -Value $xIPAddress[0] $obj | Add-Member -MemberType NoteProperty -Name DCIpAddress2 -Value "" } If($Null -ne $nic.dnsserversearchorder -and $nic.dnsserversearchorder.length -gt 0) { $obj | Add-Member -MemberType NoteProperty -Name DCDNS1 -Value $xnicdnsserversearchorder[0] If($Null -ne $xnicdnsserversearchorder[1]) { $obj | Add-Member -MemberType NoteProperty -Name DCDNS2 -Value $xnicdnsserversearchorder[1] } Else { $obj | Add-Member -MemberType NoteProperty -Name DCDNS2 -Value " " } If($Null -ne $xnicdnsserversearchorder[2]) { $obj | Add-Member -MemberType NoteProperty -Name DCDNS3 -Value $xnicdnsserversearchorder[2] } Else { $obj | Add-Member -MemberType NoteProperty -Name DCDNS3 -Value " " } If($Null -ne $xnicdnsserversearchorder[3]) { $obj | Add-Member -MemberType NoteProperty -Name DCDNS4 -Value $xnicdnsserversearchorder[3] } Else { $obj | Add-Member -MemberType NoteProperty -Name DCDNS4 -Value " " } } [void]$Script:DCDNSIPInfo.Add($obj) } } } } Else { Write-Verbose "$(Get-Date): No results Returned for NIC configuration information" If($MSWORD -or $PDF) { WriteWordLine 0 2 "No results Returned for NIC configuration information" "" $Null 0 $False $True } ElseIf($Text) { Line 2 "No results Returned for NIC configuration information" } ElseIf($HTML) { WriteHTMLLine 0 2 "No results Returned for NIC configuration information" "" $Null 0 $False $True } } } #endregion #region word specific functions Function SetWordHashTable { Param([string]$CultureCode) #optimized by Michael B. SMith # DE and FR translations for Word 2010 by Vladimir Radojevic # Vladimir.Radojevic@Commerzreal.com # DA translations for Word 2010 by Thomas Daugaard # Citrix Infrastructure Specialist at edgemo A/S # CA translations by Javier Sanchez # CEO & Founder 101 Consulting #ca - Catalan #da - Danish #de - German #en - English #es - Spanish #fi - Finnish #fr - French #nb - Norwegian #nl - Dutch #pt - Portuguese #sv - Swedish #zh - Chinese [string]$toc = $( Switch ($CultureCode) { 'ca-' { 'Taula automática 2'; Break } 'da-' { 'Automatisk tabel 2'; Break } 'de-' { 'Automatische Tabelle 2'; Break } 'en-' { 'Automatic Table 2'; Break } 'es-' { 'Tabla automática 2'; Break } 'fi-' { 'Automaattinen taulukko 2'; Break } 'fr-' { 'Table automatique 2'; Break } #changed 13-feb-2017 david roquier and samuel legrand 'nb-' { 'Automatisk tabell 2'; Break } 'nl-' { 'Automatische inhoudsopgave 2'; Break } 'pt-' { 'Sumário Automático 2'; Break } # fix in 2.23 thanks to Johan Kallio 'sv-' { 'Automatisk innehållsförteckning2'; Break } 'sv-' { 'Automatisk innehållsförteckn2'; Break } 'zh-' { '自动目录 2'; Break } } ) $Script:myHash = @{} $Script:myHash.Word_TableOfContents = $toc $Script:myHash.Word_NoSpacing = $wdStyleNoSpacing $Script:myHash.Word_Heading1 = $wdStyleheading1 $Script:myHash.Word_Heading2 = $wdStyleheading2 $Script:myHash.Word_Heading3 = $wdStyleheading3 $Script:myHash.Word_Heading4 = $wdStyleheading4 $Script:myHash.Word_TableGrid = $wdTableGrid } Function GetCulture { Param([int]$WordValue) #codes obtained from http://support.microsoft.com/kb/221435 #http://msdn.microsoft.com/en-us/library/bb213877(v=office.12).aspx $CatalanArray = 1027 $ChineseArray = 2052,3076,5124,4100 $DanishArray = 1030 $DutchArray = 2067, 1043 $EnglishArray = 3081, 10249, 4105, 9225, 6153, 8201, 5129, 13321, 7177, 11273, 2057, 1033, 12297 $FinnishArray = 1035 $FrenchArray = 2060, 1036, 11276, 3084, 12300, 5132, 13324, 6156, 8204, 10252, 7180, 9228, 4108 $GermanArray = 1031, 3079, 5127, 4103, 2055 $NorwegianArray = 1044, 2068 $PortugueseArray = 1046, 2070 $SpanishArray = 1034, 11274, 16394, 13322, 9226, 5130, 7178, 12298, 17418, 4106, 18442, 19466, 6154, 15370, 10250, 20490, 3082, 14346, 8202 $SwedishArray = 1053, 2077 #ca - Catalan #da - Danish #de - German #en - English #es - Spanish #fi - Finnish #fr - French #nb - Norwegian #nl - Dutch #pt - Portuguese #sv - Swedish #zh - Chinese Switch ($WordValue) { {$CatalanArray -contains $_} {$CultureCode = "ca-"} {$ChineseArray -contains $_} {$CultureCode = "zh-"} {$DanishArray -contains $_} {$CultureCode = "da-"} {$DutchArray -contains $_} {$CultureCode = "nl-"} {$EnglishArray -contains $_} {$CultureCode = "en-"} {$FinnishArray -contains $_} {$CultureCode = "fi-"} {$FrenchArray -contains $_} {$CultureCode = "fr-"} {$GermanArray -contains $_} {$CultureCode = "de-"} {$NorwegianArray -contains $_} {$CultureCode = "nb-"} {$PortugueseArray -contains $_} {$CultureCode = "pt-"} {$SpanishArray -contains $_} {$CultureCode = "es-"} {$SwedishArray -contains $_} {$CultureCode = "sv-"} Default {$CultureCode = "en-"} } Return $CultureCode } Function ValidateCoverPage { Param([int]$xWordVersion, [string]$xCP, [string]$CultureCode) $xArray = "" Switch ($CultureCode) { 'ca-' { If($xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "En bandes", "Faceta", "Filigrana", "Integral", "Ió (clar)", "Ió (fosc)", "Línia lateral", "Moviment", "Quadrícula", "Retrospectiu", "Sector (clar)", "Sector (fosc)", "Semàfor", "Visualització principal", "Whisp") } ElseIf($xWordVersion -eq $wdWord2013) { $xArray = ("Austin", "En bandes", "Faceta", "Filigrana", "Integral", "Ió (clar)", "Ió (fosc)", "Línia lateral", "Moviment", "Quadrícula", "Retrospectiu", "Sector (clar)", "Sector (fosc)", "Semàfor", "Visualització", "Whisp") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alfabet", "Anual", "Austin", "Conservador", "Contrast", "Cubicles", "Diplomàtic", "Exposició", "Línia lateral", "Mod", "Mosiac", "Moviment", "Paper de diari", "Perspectiva", "Piles", "Quadrícula", "Sobri", "Transcendir", "Trencaclosques") } } 'da-' { If($xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "BevægElse", "Brusen", "Facet", "Filigran", "Gitter", "Integral", "Ion (lys)", "Ion (mørk)", "Retro", "Semafor", "Sidelinje", "Stribet", "Udsnit (lys)", "Udsnit (mørk)", "Visningsmaster") } ElseIf($xWordVersion -eq $wdWord2013) { $xArray = ("BevægElse", "Brusen", "Ion (lys)", "Filigran", "Retro", "Semafor", "Visningsmaster", "Integral", "Facet", "Gitter", "Stribet", "Sidelinje", "Udsnit (lys)", "Udsnit (mørk)", "Ion (mørk)", "Austin") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("BevægElse", "Moderat", "Perspektiv", "Firkanter", "Overskrid", "Alfabet", "Kontrast", "Stakke", "Fliser", "Gåde", "Gitter", "Austin", "Eksponering", "Sidelinje", "Enkel", "Nålestribet", "Årlig", "Avispapir", "Tradionel") } } 'de-' { If($xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "Bewegung", "Facette", "Filigran", "Gebändert", "Integral", "Ion (dunkel)", "Ion (hell)", "Pfiff", "Randlinie", "Raster", "Rückblick", "Segment (dunkel)", "Segment (hell)", "Semaphor", "ViewMaster") } ElseIf($xWordVersion -eq $wdWord2013) { $xArray = ("Semaphor", "Segment (hell)", "Ion (hell)", "Raster", "Ion (dunkel)", "Filigran", "Rückblick", "Pfiff", "ViewMaster", "Segment (dunkel)", "Verbunden", "Bewegung", "Randlinie", "Austin", "Integral", "Facette") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alphabet", "Austin", "Bewegung", "Durchscheinend", "Herausgestellt", "Jährlich", "Kacheln", "Kontrast", "Kubistisch", "Modern", "Nadelstreifen", "Perspektive", "Puzzle", "Randlinie", "Raster", "Schlicht", "Stapel", "Traditionell", "Zeitungspapier") } } 'en-' { If($xWordVersion -eq $wdWord2013 -or $xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "Banded", "Facet", "Filigree", "Grid", "Integral", "Ion (Dark)", "Ion (Light)", "Motion", "Retrospect", "Semaphore", "Sideline", "Slice (Dark)", "Slice (Light)", "ViewMaster", "Whisp") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alphabet", "Annual", "Austere", "Austin", "Conservative", "Contrast", "Cubicles", "Exposure", "Grid", "Mod", "Motion", "Newsprint", "Perspective", "Pinstripes", "Puzzle", "Sideline", "Stacks", "Tiles", "Transcend") } } 'es-' { If($xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "Con bandas", "Cortar (oscuro)", "Cuadrícula", "Whisp", "Faceta", "Filigrana", "Integral", "Ion (claro)", "Ion (oscuro)", "Línea lateral", "Movimiento", "Retrospectiva", "Semáforo", "Slice (luz)", "Vista principal", "Whisp") } ElseIf($xWordVersion -eq $wdWord2013) { $xArray = ("Whisp", "Vista principal", "Filigrana", "Austin", "Slice (luz)", "Faceta", "Semáforo", "Retrospectiva", "Cuadrícula", "Movimiento", "Cortar (oscuro)", "Línea lateral", "Ion (oscuro)", "Ion (claro)", "Integral", "Con bandas") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alfabeto", "Anual", "Austero", "Austin", "Conservador", "Contraste", "Cuadrícula", "Cubículos", "Exposición", "Línea lateral", "Moderno", "Mosaicos", "Movimiento", "Papel periódico", "Perspectiva", "Pilas", "Puzzle", "Rayas", "Sobrepasar") } } 'fi-' { If($xWordVersion -eq $wdWord2016) { $xArray = ("Filigraani", "Integraali", "Ioni (tumma)", "Ioni (vaalea)", "Opastin", "Pinta", "Retro", "Sektori (tumma)", "Sektori (vaalea)", "Vaihtuvavärinen", "ViewMaster", "Austin", "Kuiskaus", "Liike", "Ruudukko", "Sivussa") } ElseIf($xWordVersion -eq $wdWord2013) { $xArray = ("Filigraani", "Integraali", "Ioni (tumma)", "Ioni (vaalea)", "Opastin", "Pinta", "Retro", "Sektori (tumma)", "Sektori (vaalea)", "Vaihtuvavärinen", "ViewMaster", "Austin", "Kiehkura", "Liike", "Ruudukko", "Sivussa") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Aakkoset", "Askeettinen", "Austin", "Kontrasti", "Laatikot", "Liike", "Liituraita", "Mod", "Osittain peitossa", "Palapeli", "Perinteinen", "Perspektiivi", "Pinot", "Ruudukko", "Ruudut", "Sanomalehtipaperi", "Sivussa", "Vuotuinen", "Ylitys") } } 'fr-' { If($xWordVersion -eq $wdWord2013 -or $xWordVersion -eq $wdWord2016) { $xArray = ("À bandes", "Austin", "Facette", "Filigrane", "Guide", "Intégrale", "Ion (clair)", "Ion (foncé)", "Lignes latérales", "Quadrillage", "Rétrospective", "Secteur (clair)", "Secteur (foncé)", "Sémaphore", "ViewMaster", "Whisp") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alphabet", "Annuel", "Austère", "Austin", "Blocs empilés", "Classique", "Contraste", "Emplacements de bureau", "Exposition", "Guide", "Ligne latérale", "Moderne", "Mosaïques", "Mots croisés", "Papier journal", "Perspective", "Quadrillage", "Rayures fines", "Transcendant") } } 'nb-' { If($xWordVersion -eq $wdWord2013 -or $xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "BevegElse", "Dempet", "Fasett", "Filigran", "Integral", "Ion (lys)", "Ion (mørk)", "Retrospekt", "Rutenett", "Sektor (lys)", "Sektor (mørk)", "Semafor", "Sidelinje", "Stripet", "ViewMaster") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alfabet", "Årlig", "Avistrykk", "Austin", "Avlukker", "BevegElse", "Engasjement", "Enkel", "Fliser", "Konservativ", "Kontrast", "Mod", "Perspektiv", "Puslespill", "Rutenett", "Sidelinje", "Smale striper", "Stabler", "Transcenderende") } } 'nl-' { If($xWordVersion -eq $wdWord2013 -or $xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "Beweging", "Facet", "Filigraan", "Gestreept", "Integraal", "Ion (donker)", "Ion (licht)", "Raster", "Segment (Light)", "Semafoor", "Slice (donker)", "Spriet", "Terugblik", "Terzijde", "ViewMaster") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Aantrekkelijk", "Alfabet", "Austin", "Bescheiden", "Beweging", "Blikvanger", "Contrast", "Eenvoudig", "Jaarlijks", "Krantenpapier", "Krijtstreep", "Kubussen", "Mod", "Perspectief", "Puzzel", "Raster", "Stapels", "Tegels", "Terzijde") } } 'pt-' { If($xWordVersion -eq $wdWord2013 -or $xWordVersion -eq $wdWord2016) { $xArray = ("Animação", "Austin", "Em Tiras", "Exibição Mestra", "Faceta", "Fatia (Clara)", "Fatia (Escura)", "Filete", "Filigrana", "Grade", "Integral", "Íon (Claro)", "Íon (Escuro)", "Linha Lateral", "Retrospectiva", "Semáforo") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alfabeto", "Animação", "Anual", "Austero", "Austin", "Baias", "Conservador", "Contraste", "Exposição", "Grade", "Ladrilhos", "Linha Lateral", "Listras", "Mod", "Papel Jornal", "Perspectiva", "Pilhas", "Quebra-cabeça", "Transcend") } } 'sv-' { If($xWordVersion -eq $wdWord2013 -or $xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "Band", "Fasett", "Filigran", "Integrerad", "Jon (ljust)", "Jon (mörkt)", "Knippe", "Rutnät", "RörElse", "Sektor (ljus)", "Sektor (mörk)", "Semafor", "Sidlinje", "VisaHuvudsida", "Återblick") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alfabetmönster", "Austin", "Enkelt", "Exponering", "Konservativt", "Kontrast", "Kritstreck", "Kuber", "Perspektiv", "Plattor", "Pussel", "Rutnät", "RörElse", "Sidlinje", "Sobert", "Staplat", "Tidningspapper", "Årligt", "Övergående") } } 'zh-' { If($xWordVersion -eq $wdWord2010 -or $xWordVersion -eq $wdWord2013 -or $xWordVersion -eq $wdWord2016) { $xArray = ('奥斯汀', '边线型', '花丝', '怀旧', '积分', '离子(浅色)', '离子(深色)', '母版型', '平面', '切片(浅色)', '切片(深色)', '丝状', '网格', '镶边', '信号灯', '运动型') } } Default { If($xWordVersion -eq $wdWord2013 -or $xWordVersion -eq $wdWord2016) { $xArray = ("Austin", "Banded", "Facet", "Filigree", "Grid", "Integral", "Ion (Dark)", "Ion (Light)", "Motion", "Retrospect", "Semaphore", "Sideline", "Slice (Dark)", "Slice (Light)", "ViewMaster", "Whisp") } ElseIf($xWordVersion -eq $wdWord2010) { $xArray = ("Alphabet", "Annual", "Austere", "Austin", "Conservative", "Contrast", "Cubicles", "Exposure", "Grid", "Mod", "Motion", "Newsprint", "Perspective", "Pinstripes", "Puzzle", "Sideline", "Stacks", "Tiles", "Transcend") } } } If($xArray -contains $xCP) { $xArray = $Null Return $True } Else { $xArray = $Null Return $False } } Function CheckWordPrereq { If((Test-Path REGISTRY::HKEY_CLASSES_ROOT\Word.Application) -eq $False) { $ErrorActionPreference = $SaveEAPreference Write-Host "`n`n`t`tThis script directly outputs to Microsoft Word, please install Microsoft Word`n`n" Exit } #find out our session (usually "1" except on TS/RDC or Citrix) $SessionID = (Get-Process -PID $PID).SessionId #Find out if winword is running in our session #[bool]$wordrunning = ((Get-Process 'WinWord' -ea 0)|Where-Object {$_.SessionId -eq $SessionID}) -ne $Null [bool]$wordrunning = $null –ne ((Get-Process 'WinWord' -ea 0) | Where-Object {$_.SessionId -eq $SessionID}) If($wordrunning) { $ErrorActionPreference = $SaveEAPreference Write-Host "`n`n`tPlease close all instances of Microsoft Word before running this report.`n`n" Exit } } Function ValidateCompanyName { [bool]$xResult = Test-RegistryValue "HKCU:\Software\Microsoft\Office\Common\UserInfo" "CompanyName" If($xResult) { Return Get-LocalRegistryValue "HKCU:\Software\Microsoft\Office\Common\UserInfo" "CompanyName" } Else { $xResult = Test-RegistryValue "HKCU:\Software\Microsoft\Office\Common\UserInfo" "Company" If($xResult) { Return Get-LocalRegistryValue "HKCU:\Software\Microsoft\Office\Common\UserInfo" "Company" } Else { Return "" } } } Function Set-DocumentProperty { <# .SYNOPSIS Function to set the Title Page document properties in MS Word .DESCRIPTION Long description .PARAMETER Document Current Document Object .PARAMETER DocProperty Parameter description .PARAMETER Value Parameter description .EXAMPLE Set-DocumentProperty -Document $Script:Doc -DocProperty Title -Value 'MyTitle' .EXAMPLE Set-DocumentProperty -Document $Script:Doc -DocProperty Company -Value 'MyCompany' .EXAMPLE Set-DocumentProperty -Document $Script:Doc -DocProperty Author -Value 'Jim Moyle' .EXAMPLE Set-DocumentProperty -Document $Script:Doc -DocProperty Subject -Value 'MySubjectTitle' .NOTES Function Created by Jim Moyle June 2017 Twitter : @JimMoyle #> param ( [object]$Document, [String]$DocProperty, [string]$Value ) try { $binding = "System.Reflection.BindingFlags" -as [type] $builtInProperties = $Document.BuiltInDocumentProperties $property = [System.__ComObject].invokemember("item", $binding::GetProperty, $null, $BuiltinProperties, $DocProperty) [System.__ComObject].invokemember("value", $binding::SetProperty, $null, $property, $Value) } catch { Write-Warning "Failed to set $DocProperty to $Value" } } Function FindWordDocumentEnd { #return focus to main document $Script:Doc.ActiveWindow.ActivePane.view.SeekView = $wdSeekMainDocument #move to the end of the current document $Script:Selection.EndKey($wdStory,$wdMove) | Out-Null } Function SetupWord { Write-Verbose "$(Get-Date): Setting up Word" # Setup word for output Write-Verbose "$(Get-Date): Create Word comObject." $Script:Word = New-Object -comobject "Word.Application" -EA 0 4>$Null If(!$? -or $Null -eq $Script:Word) { Write-Warning "The Word object could not be created. You may need to repair your Word installation." $ErrorActionPreference = $SaveEAPreference Write-Error " `n`n `t`t The Word object could not be created. `n`n `t`t You may need to repair your Word installation. `n`n `t`t Script cannot continue. `n`n " Exit } Write-Verbose "$(Get-Date): Determine Word language value" If( ( validStateProp $Script:Word Language Value__ ) ) { [int]$Script:WordLanguageValue = [int]$Script:Word.Language.Value__ } Else { [int]$Script:WordLanguageValue = [int]$Script:Word.Language } If(!($Script:WordLanguageValue -gt -1)) { $ErrorActionPreference = $SaveEAPreference Write-Error " `n`n `t`t Unable to determine the Word language value. `n`n `t`t Script cannot continue. `n`n " AbortScript } Write-Verbose "$(Get-Date): Word language value is $($Script:WordLanguageValue)" $Script:WordCultureCode = GetCulture $Script:WordLanguageValue SetWordHashTable $Script:WordCultureCode [int]$Script:WordVersion = [int]$Script:Word.Version If($Script:WordVersion -eq $wdWord2016) { $Script:WordProduct = "Word 2016" } ElseIf($Script:WordVersion -eq $wdWord2013) { $Script:WordProduct = "Word 2013" } ElseIf($Script:WordVersion -eq $wdWord2010) { $Script:WordProduct = "Word 2010" } ElseIf($Script:WordVersion -eq $wdWord2007) { $ErrorActionPreference = $SaveEAPreference Write-Error " `n`n `t`t Microsoft Word 2007 is no longer supported. `n`n `t`t Script will end. `n`n " AbortScript } ElseIf($Script:WordVersion -eq 0) { Write-Error " `n`n `t`t The Word Version is 0. You should run a full online repair of your Office installation. `n`n `t`t Script cannot continue. `n`n " Exit } Else { $ErrorActionPreference = $SaveEAPreference Write-Error " `n`n `t`t You are running an untested or unsupported version of Microsoft Word. `n`n `t`t Script will end. `n`n `t`t Please send info on your version of Word to webster@carlwebster.com `n`n " AbortScript } #only validate CompanyName if the field is blank If([String]::IsNullOrEmpty($Script:CoName)) { Write-Verbose "$(Get-Date): Company name is blank. Retrieve company name from registry." $TmpName = ValidateCompanyName If([String]::IsNullOrEmpty($TmpName)) { Write-Warning "`n`n`t`tCompany Name is blank so Cover Page will not show a Company Name." Write-Warning "`n`t`tCheck HKCU:\Software\Microsoft\Office\Common\UserInfo for Company or CompanyName value." Write-Warning "`n`t`tYou may want to use the -CompanyName parameter if you need a Company Name on the cover page.`n`n" } Else { $Script:CoName = $TmpName Write-Verbose "$(Get-Date): Updated company name to $($Script:CoName)" } } If($Script:WordCultureCode -ne "en-") { Write-Verbose "$(Get-Date): Check Default Cover Page for $($WordCultureCode)" [bool]$CPChanged = $False Switch ($Script:WordCultureCode) { 'ca-' { If($CoverPage -eq "Sideline") { $CoverPage = "Línia lateral" $CPChanged = $True } } 'da-' { If($CoverPage -eq "Sideline") { $CoverPage = "Sidelinje" $CPChanged = $True } } 'de-' { If($CoverPage -eq "Sideline") { $CoverPage = "Randlinie" $CPChanged = $True } } 'es-' { If($CoverPage -eq "Sideline") { $CoverPage = "Línea lateral" $CPChanged = $True } } 'fi-' { If($CoverPage -eq "Sideline") { $CoverPage = "Sivussa" $CPChanged = $True } } 'fr-' { If($CoverPage -eq "Sideline") { If($Script:WordVersion -eq $wdWord2013 -or $Script:WordVersion -eq $wdWord2016) { $CoverPage = "Lignes latérales" $CPChanged = $True } Else { $CoverPage = "Ligne latérale" $CPChanged = $True } } } 'nb-' { If($CoverPage -eq "Sideline") { $CoverPage = "Sidelinje" $CPChanged = $True } } 'nl-' { If($CoverPage -eq "Sideline") { $CoverPage = "Terzijde" $CPChanged = $True } } 'pt-' { If($CoverPage -eq "Sideline") { $CoverPage = "Linha Lateral" $CPChanged = $True } } 'sv-' { If($CoverPage -eq "Sideline") { $CoverPage = "Sidlinje" $CPChanged = $True } } 'zh-' { If($CoverPage -eq "Sideline") { $CoverPage = "边线型" $CPChanged = $True } } } If($CPChanged) { Write-Verbose "$(Get-Date): Changed Default Cover Page from Sideline to $($CoverPage)" } } Write-Verbose "$(Get-Date): Validate cover page $($CoverPage) for culture code $($Script:WordCultureCode)" [bool]$ValidCP = $False $ValidCP = ValidateCoverPage $Script:WordVersion $CoverPage $Script:WordCultureCode If(!$ValidCP) { $ErrorActionPreference = $SaveEAPreference Write-Verbose "$(Get-Date): Word language value $($Script:WordLanguageValue)" Write-Verbose "$(Get-Date): Culture code $($Script:WordCultureCode)" Write-Error " `n`n `t`t For $($Script:WordProduct), $($CoverPage) is not a valid Cover Page option. `n`n `t`t Script cannot continue. `n`n " AbortScript } ShowScriptOptions $Script:Word.Visible = $False #http://jdhitsolutions.com/blog/2012/05/san-diego-2012-powershell-deep-dive-slides-and-demos/ #using Jeff's Demo-WordReport.ps1 file for examples Write-Verbose "$(Get-Date): Load Word Templates" [bool]$Script:CoverPagesExist = $False [bool]$BuildingBlocksExist = $False $Script:Word.Templates.LoadBuildingBlocks() #word 2010/2013/2016 $BuildingBlocksCollection = $Script:Word.Templates | Where-Object {$_.name -eq "Built-In Building Blocks.dotx"} Write-Verbose "$(Get-Date): Attempt to load cover page $($CoverPage)" $part = $Null $BuildingBlocksCollection | ForEach-Object{ If ($_.BuildingBlockEntries.Item($CoverPage).Name -eq $CoverPage) { $BuildingBlocks = $_ } } If($Null -ne $BuildingBlocks) { $BuildingBlocksExist = $True Try { $part = $BuildingBlocks.BuildingBlockEntries.Item($CoverPage) } Catch { $part = $Null } If($Null -ne $part) { $Script:CoverPagesExist = $True } } If(!$Script:CoverPagesExist) { Write-Verbose "$(Get-Date): Cover Pages are not installed or the Cover Page $($CoverPage) does not exist." Write-Warning "Cover Pages are not installed or the Cover Page $($CoverPage) does not exist." Write-Warning "This report will not have a Cover Page." } Write-Verbose "$(Get-Date): Create empty word doc" $Script:Doc = $Script:Word.Documents.Add() If($Null -eq $Script:Doc) { Write-Verbose "$(Get-Date): " $ErrorActionPreference = $SaveEAPreference Write-Error " `n`n `t`t An empty Word document could not be created. `n`n `t`t Script cannot continue. `n`n " AbortScript } $Script:Selection = $Script:Word.Selection If($Null -eq $Script:Selection) { Write-Verbose "$(Get-Date): " $ErrorActionPreference = $SaveEAPreference Write-Error " `n`n `t`t An unknown error happened selecting the entire Word document for default formatting options. `n`n `t`t Script cannot continue. `n`n " AbortScript } #set Default tab stops to 1/2 inch (this line is not from Jeff Hicks) #36 = .50" $Script:Word.ActiveDocument.DefaultTabStop = 36 #Disable Spell and Grammar Check to resolve issue and improve performance (from Pat Coughlin) Write-Verbose "$(Get-Date): Disable grammar and spell checking" #bug reported 1-Apr-2014 by Tim Mangan #save current options first before turning them off $Script:CurrentGrammarOption = $Script:Word.Options.CheckGrammarAsYouType $Script:CurrentSpellingOption = $Script:Word.Options.CheckSpellingAsYouType $Script:Word.Options.CheckGrammarAsYouType = $False $Script:Word.Options.CheckSpellingAsYouType = $False If($BuildingBlocksExist) { #insert new page, getting ready for table of contents Write-Verbose "$(Get-Date): Insert new page, getting ready for table of contents" $part.Insert($Script:Selection.Range,$True) | Out-Null $Script:Selection.InsertNewPage() #table of contents Write-Verbose "$(Get-Date): Table of Contents - $($Script:MyHash.Word_TableOfContents)" $toc = $BuildingBlocks.BuildingBlockEntries.Item($Script:MyHash.Word_TableOfContents) If($Null -eq $toc) { Write-Verbose "$(Get-Date): " Write-Verbose "$(Get-Date): Table of Content - $($Script:MyHash.Word_TableOfContents) could not be retrieved." Write-Warning "This report will not have a Table of Contents." } Else { $toc.insert($Script:Selection.Range,$True) | Out-Null } } Else { Write-Verbose "$(Get-Date): Table of Contents are not installed." Write-Warning "Table of Contents are not installed so this report will not have a Table of Contents." } #set the footer Write-Verbose "$(Get-Date): Set the footer" [string]$footertext = "Report created by $username" #get the footer Write-Verbose "$(Get-Date): Get the footer and format font" $Script:Doc.ActiveWindow.ActivePane.view.SeekView = $wdSeekPrimaryFooter #get the footer and format font $footers = $Script:Doc.Sections.Last.Footers ForEach ($footer in $footers) { If($footer.exists) { $footer.range.Font.name = "Calibri" $footer.range.Font.size = 8 $footer.range.Font.Italic = $True $footer.range.Font.Bold = $True } } #end ForEach Write-Verbose "$(Get-Date): Footer text" $Script:Selection.HeaderFooter.Range.Text = $footerText #add page numbering Write-Verbose "$(Get-Date): Add page numbering" $Script:Selection.HeaderFooter.PageNumbers.Add($wdAlignPageNumberRight) | Out-Null FindWordDocumentEnd Write-Verbose "$(Get-Date):" #end of Jeff Hicks } Function UpdateDocumentProperties { Param([string]$AbstractTitle, [string]$SubjectTitle) #updated 8-Jun-2017 with additional cover page fields #Update document properties If($MSWORD -or $PDF) { If($Script:CoverPagesExist) { Write-Verbose "$(Get-Date): Set Cover Page Properties" #8-Jun-2017 put these 4 items in alpha order Set-DocumentProperty -Document $Script:Doc -DocProperty Author -Value $UserName Set-DocumentProperty -Document $Script:Doc -DocProperty Company -Value $Script:CoName Set-DocumentProperty -Document $Script:Doc -DocProperty Subject -Value $SubjectTitle Set-DocumentProperty -Document $Script:Doc -DocProperty Title -Value $Script:title #Get the Coverpage XML part $cp = $Script:Doc.CustomXMLParts | Where-Object {$_.NamespaceURI -match "coverPageProps$"} #get the abstract XML part $ab = $cp.documentelement.ChildNodes | Where-Object {$_.basename -eq "Abstract"} #set the text If([String]::IsNullOrEmpty($Script:CoName)) { [string]$abstract = $AbstractTitle } Else { [string]$abstract = "$($AbstractTitle) for $($Script:CoName)" } $ab.Text = $abstract #added 8-Jun-2017 $ab = $cp.documentelement.ChildNodes | Where-Object {$_.basename -eq "CompanyAddress"} #set the text [string]$abstract = $CompanyAddress $ab.Text = $abstract #added 8-Jun-2017 $ab = $cp.documentelement.ChildNodes | Where-Object {$_.basename -eq "CompanyEmail"} #set the text [string]$abstract = $CompanyEmail $ab.Text = $abstract #added 8-Jun-2017 $ab = $cp.documentelement.ChildNodes | Where-Object {$_.basename -eq "CompanyFax"} #set the text [string]$abstract = $CompanyFax $ab.Text = $abstract #added 8-Jun-2017 $ab = $cp.documentelement.ChildNodes | Where-Object {$_.basename -eq "CompanyPhone"} #set the text [string]$abstract = $CompanyPhone $ab.Text = $abstract $ab = $cp.documentelement.ChildNodes | Where-Object {$_.basename -eq "PublishDate"} #set the text [string]$abstract = (Get-Date -Format d).ToString() $ab.Text = $abstract Write-Verbose "$(Get-Date): Update the Table of Contents" #update the Table of Contents $Script:Doc.TablesOfContents.item(1).Update() $cp = $Null $ab = $Null $abstract = $Null } } } #endregion #region registry functions #http://stackoverflow.com/questions/5648931/test-if-registry-value-exists # This Function just gets $True or $False Function Test-RegistryValue($path, $name) { $key = Get-Item -LiteralPath $path -EA 0 $key -and $Null -ne $key.GetValue($name, $Null) } # Gets the specified local registry value or $Null if it is missing Function Get-LocalRegistryValue($path, $name) { $key = Get-Item -LiteralPath $path -EA 0 If($key) { $key.GetValue($name, $Null) } Else { $Null } } Function Get-RegistryValue { # Gets the specified registry value or $Null if it is missing [CmdletBinding()] Param([string]$path, [string]$name, [string]$ComputerName) If($ComputerName -eq $env:computername -or $ComputerName -eq "LocalHost") { $key = Get-Item -LiteralPath $path -EA 0 If($key) { Return $key.GetValue($name, $Null) } Else { Return $Null } } Else { #path needed here is different for remote registry access $path1 = $path.SubString(6) $path2 = $path1.Replace('\','\\') $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $ComputerName) $RegKey= $Reg.OpenSubKey($path2) $Results = $RegKey.GetValue($name) If($Null -ne $Results) { Return $Results } Else { Return $Null } } } #endregion #region word, text and html line output functions Function line #function created by Michael B. Smith, Exchange MVP #@essentialexch on Twitter #https://essential.exchange/blog #for creating the formatted text report #created March 2011 #updated March 2014 # updated March 2019 to use StringBuilder (about 100 times more efficient than simple strings) { Param ( [Int] $tabs = 0, [String] $name = '', [String] $value = '', [String] $newline = [System.Environment]::NewLine, [Switch] $nonewline ) while( $tabs -gt 0 ) { $null = $global:Output.Append( "`t" ) $tabs-- } If( $nonewline ) { $null = $global:Output.Append( $name + $value ) } Else { $null = $global:Output.AppendLine( $name + $value ) } } Function WriteWordLine #Function created by Ryan Revord #@rsrevord on Twitter #Function created to make output to Word easy in this script #updated 27-Mar-2014 to include font name, font size, italics and bold options { Param([int]$style=0, [int]$tabs = 0, [string]$name = '', [string]$value = '', [string]$fontName=$Null, [int]$fontSize=0, [bool]$italics=$False, [bool]$boldface=$False, [Switch]$nonewline) #Build output style [string]$output = "" Switch ($style) { 0 {$Script:Selection.Style = $Script:MyHash.Word_NoSpacing; Break} 1 {$Script:Selection.Style = $Script:MyHash.Word_Heading1; Break} 2 {$Script:Selection.Style = $Script:MyHash.Word_Heading2; Break} 3 {$Script:Selection.Style = $Script:MyHash.Word_Heading3; Break} 4 {$Script:Selection.Style = $Script:MyHash.Word_Heading4; Break} Default {$Script:Selection.Style = $Script:MyHash.Word_NoSpacing; Break} } #build # of tabs While($tabs -gt 0) { $output += "`t"; $tabs--; } If(![String]::IsNullOrEmpty($fontName)) { $Script:Selection.Font.name = $fontName } If($fontSize -ne 0) { $Script:Selection.Font.size = $fontSize } If($italics -eq $True) { $Script:Selection.Font.Italic = $True } If($boldface -eq $True) { $Script:Selection.Font.Bold = $True } #output the rest of the parameters. $output += $name + $value $Script:Selection.TypeText($output) #test for new WriteWordLine 0. If($nonewline) { # Do nothing. } Else { $Script:Selection.TypeParagraph() } } #*********************************************************************************************************** # WriteHTMLLine #*********************************************************************************************************** <# .Synopsis Writes a line of output for HTML output .DESCRIPTION This function formats an HTML line .USAGE WriteHTMLLine