Managing Network Inventory

I am looking for some best practice on how you manage your PC Estate Inventory; right from new PC’s being dispatched to old PC’s being disposed of. I work for a large organisation and we have upwards of 250 sites, all of which house employees who work on the Authorities PC’s, a PC estate of over 20’000 workstations,  As you can imagine old PC’s need scrapping, new PC’s need purchasing, so the Inventory is ever changing. Our IT Support is outsourced, and the Service Provider charge us $$x per PC, per annual support. Therefore if we have PC’s that are of no use and no longer in use, but haven’t been disposed of they remain on the Inventory and our organisation incurs an annual charge for kit that isn’t being used. Tracking down old PC’s to see if they are still in use over 250 sites is a nightmare. Our Auditors are after documentation at all levels which is fair game, currently we use these 2 major documents:

• New PC arrives, the recipient signs for the new PC, signed document goes in central repository.
• Old PC gets wiped on goes to be recycled, the recycling company signs for this, signed document goes in central repository.  

It’s a fill time job managing this monster. I need some best practice and to be honest, advice and tips on how to manage the whole inventory to ensure old redundant kit does not stay on the Inventory, i.e. locked in someone’s cabinet as they were to lazy to wipe it and contact the recycling vendor.  

Tools, documentation, procedures, and tips based on experience etc. What do you do to satisfy your auditors to ensure you organisation does not incur unnecessary support charges as your inventory figures aren’t accurate. What records to you keep etc etc.
LVL 3
pma111Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Rich RumbleSecurity SamuraiCommented:
We use homegrown scripts, logon scripts mostly, that write flat files to a file share that get parsed by a scheduled tasks and put into a DB. Were in the midst of revamping and installing an agent based method, very similar to OpenAudIT's. Below is some simple code we use to return basic details about systems and OS's like hard drive info, bios (serial numbers aka dell tag or ibm tags for instance) memory data, network card(s) data like IP mac, dns, wins... antivirus data and services.
OpenAudIT has a very similar script but is it's agent, the script below can be used on local machines (cscript /nologo inventory.vbs) or it can make encrypted connections to machines via IP or FQDN.
We also have a custom application that monitors network devices like routers and switches, keeping track of where mac address's are, a list of IP's in the ARP tables, and we monitor bandwidth usage (clearsite.sourceforge.net) Our next effort will focus on more OS's than M$'s.
-rich
'Usage:
'cscript /nologo inventory.vbs /s:ip.ip.ip.ip  /u:user_name /p:password /c:hd,pc,bios,vid,mem,nic,cpu,hwerr,os,srvc,av,fw
' ip's can be comma seperated... ip's could also be dns-name(s)
' if no parametes are given local host and all parameters are run...
Const WbemAuthenticationLevelPktPrivacy = 6

Function ConvertSize(Size)
Do While InStr(Size,",") 'Remove commas from size
    CommaLocate = InStr(Size,",")
    Size = Mid(Size,1,CommaLocate - 1) & _
        Mid(Size,CommaLocate + 1,Len(Size) - CommaLocate)
Loop

Suffix = " Bytes"
If Size >= 1024 Then suffix = " KB"
If Size >= 1048576 Then suffix = " MB"
If Size >= 1073741824 Then suffix = " GB"
If Size >= 1099511627776 Then suffix = " TB"

Select Case Suffix
    Case " KB" Size = Round(Size / 1024, 0)
    Case " MB" Size = Round(Size / 1048576, 0)
    Case " GB" Size = Round(Size / 1073741824, 0)
    Case " TB" Size = Round(Size / 1099511627776, 0)
End Select

ConvertSize = Size & Suffix
End Function

Function WMIDateStringToDate(dtmDate)
On Error Resume Next
    WScript.Echo dtm:
    WMIDateStringToDate = CDate(Mid(dtmDate, 5, 2) & "/" & _
    Mid(dtmDate, 7, 2) & "/" & Left(dtmDate, 4) _
    & " " & Mid (dtmDate, 9, 2) & ":" & Mid(dtmDate, 11, 2) & ":" & Mid(dtmDate,13, 2))
End Function

If Wscript.Arguments.Named("u") <> "" And Wscript.Arguments.Named("p") <> "" Then
    boolAlternate = True
    strUser = WScript.Arguments.Named("u")
    strPassword = WScript.Arguments.Named("p")
'    WScript.Echo "Using alternate credentials..."
Else
    boolAlternate = False
'    WScript.Echo "Using current credentials..."
End If

If WScript.Arguments.Named("s") = "" Then
    arrComputers = Array(".")
Else
    arrComputers = Split(WScript.Arguments.Named("s"), ",")
End If

For Each strComputer In arrComputers

    If boolAlternate = True Then
        strNamespace = "root\cimv2"
        Set objWbemLocator = CreateObject("WbemScripting.SWbemLocator")
        Set objWMIService = objwbemLocator.ConnectServer(strComputer, strNamespace, strUser, strPassword)
        objWMIService.Security_.authenticationLevel = WbemAuthenticationLevelPktPrivacy
    Else
        Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    End If

    If Wscript.Arguments.Named("c") <> "" Then
        ' This splits the "/c:" argument by a comma, and goes through each
        arrSections = Split(Wscript.Arguments.Named("c"), ",")
        For Each strSection In arrSections
            Select Case Trim(LCase(strSection))
                Case "hd"
                    HD_Info
                Case "pc"
                    PC_Info
                Case "bios"
                    Bios_Info
                Case "vid"
                    Video_Info
                Case "mem"
                    Memory_Info
                Case "nic"
                    NIC_Info
                Case "cpu"
                    CPU_Info
                Case "hwerr"
                    HW_Err_Info
                Case "os"
                    OS_Info
                Case "srvc"
		    SRVC_Info
                Case "av"
                    AV_Info
                Case "fw"
                    FW_Info
		Case "acct"
                    Acct_Info
            End Select
        Next
    Else
'        This is where all tests are run
'        WScript.Echo "Running all sections..."
        HD_Info
        PC_Info
        Bios_Info
        Video_Info
        Memory_Info
        NIC_Info
        CPU_Info
        HW_Err_Info
        OS_Info
        SRVC_Info
        AV_Info
        FW_Info
	Acct_Info
    End If 
Next
Sub HD_Info
On Error Resume Next
'    Get Mapped Drive(s) Info
				WScript.Echo  "------Drives------"
    Set colItems = objWMIService.ExecQuery("Select * from Win32_LogicalDisk Where Description = 'Network Connection'")
    For Each objItem in colItems
        WScript.Echo  "----Mapped----"
        WScript.Echo  "VolumeName  : " & objItem.VolumeName
        WScript.Echo  "Description : " & objItem.Description
        WScript.Echo  "Name        : " & objItem.Name
        WScript.Echo  "DeviceID    : " & objItem.DeviceID
        WScript.Echo  "Size        : " & ConvertSize(objItem.Size)
        Wscript.Echo  "FreeSpace   : " & ConvertSize(objItem.FreeSpace)
        Wscript.Echo  "FileSystem  : " & objItem.FileSystem
        WScript.Echo  "ProviderName: " & objItem.ProviderName
        Wscript.Echo  "SerialNumber: " & objItem.VolumeSerialNumber
    Next
'    Get Harddrive(s) Info
    Set colItems = objWMIService.ExecQuery("Select * from Win32_LogicalDisk Where Description = 'Local Fixed Disk'")
    For Each objItem in colItems
        WScript.Echo  "----HD----"
        WScript.Echo  "VolumeName  : " & objItem.VolumeName
        WScript.Echo  "Description : " & objItem.Description
        WScript.Echo  "Name        : " & objItem.Name
        WScript.Echo  "DeviceID    : " & objItem.DeviceID
        WScript.Echo  "Size        : " & ConvertSize(objItem.Size)
        Wscript.Echo  "FreeSpace   : " & ConvertSize(objItem.FreeSpace)
        Wscript.Echo  "FileSystem  : " & objItem.FileSystem
        Wscript.Echo  "SerialNumber: " & objItem.VolumeSerialNumber
    Next
End Sub
'    Get Local Login Information
Sub PC_Info
        WScript.Echo  "------Login------"
On Error Resume Next
    Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)
    For Each objItem in colItems
        Wscript.Echo  "Caption     : " & objItem.Caption
        Wscript.Echo  "TimeZone    : " & objItem.CurrentTimeZone
        Wscript.Echo  "Description : " & objItem.Description
        Wscript.Echo  "Domain Role : " & objItem.DomainRole
        Wscript.Echo  "Manufacturer: " & objItem.Manufacturer
        Wscript.Echo  "Model       : " & objItem.Model
        Wscript.Echo  "Name        : " & objItem.Name
        Wscript.Echo  "Domain      : " & objItem.Domain
        Wscript.Echo  "UserName    : " & objItem.UserName
    Next
End Sub

'    Get Bios info, includng Asset Tag, Bios Revision and Manufacturer
Sub Bios_Info
       WScript.Echo  "------Bios------"
On Error Resume Next
    Set colItems = objWMIService.ExecQuery("Select * from Win32_BIOS",,48)
    For Each objItem in colItems
        Wscript.Echo  "BuildNumber : " & objItem.BuildNumber
        Wscript.Echo  "ReleaseDate : " & WMIDateStringToDate(objItem.ReleaseDate)
        Wscript.Echo  "Description : " & objItem.Description
        Wscript.Echo  "Manufacturer: " & objItem.Manufacturer
        Wscript.Echo  "Name        : " & objItem.Name
        Wscript.Echo  "SerialNumber: " & objItem.SerialNumber
        Wscript.Echo  "Version     : " & objItem.Version
    Next
End Sub

'    Get Screen Resolution, Refreash and Video Card info
Sub Video_Info
       WScript.Echo  "------Vid------"
On Error Resume Next
    Set colItems = objWMIService.ExecQuery("Select * from Win32_DisplayControllerConfiguration",,48)
    For Each objItem in colItems
        Wscript.Echo  "Description: " & objItem.Description
        Wscript.Echo  "Name       : " & objItem.Name
        Wscript.Echo  "RefreshRate: " & objItem.RefreshRate
        Wscript.Echo  "VideoMode  : " & objItem.VideoMode
    Next
End Sub

'    Get Memory Information
Sub Memory_Info
       WScript.Echo  "------Mem------"
On Error Resume Next
    Set colItems = objWMIService.ExecQuery("Select * from Win32_LogicalMemoryConfiguration",,48)
    For Each objItem in colItems
        Wscript.Echo  "FreeVirtMem: " & ConvertSize(objItem.AvailableVirtualMemory * 1024)
        Wscript.Echo  "TotPgFileSz: " & ConvertSize(objItem.TotalPageFileSpace * 1024)
        Wscript.Echo  "TotPhyMem  : " & ConvertSize(objItem.TotalPhysicalMemory * 1024)
        Wscript.Echo  "TotVirtMem : " & ConvertSize(objItem.TotalVirtualMemory * 1024)
    Next
End Sub

'    Get NIC information
Sub NIC_Info
On Error Resume Next
       WScript.Echo  "------Net------"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_NetworkAdapterConfiguration " & "Where IPEnabled = True")
        For Each objItem in colItems
         WScript.Echo  "----Nic----"
        ' Beginning of Adapter specific information
        Wscript.Echo  "Caption    : " & objItem.Caption
        If Not IsNull(objItem.DNSDomainSuffixSearchOrder) Then
          Dim strDefaultIPGateway : strDefaultIPGateway = Join(objItem.DefaultIPGateway, ",")
          Wscript.Echo "DfltGtwy   : " & strDefaultIPGateway
        End If
        Wscript.Echo "Description: " & objItem.Description
        If Not IsNull(objItem.DNSDomainSuffixSearchOrder) Then
          Dim strDNSDomainSuffixSearchOrder : strDNSDomainSuffixSearchOrder = Join(objItem.DNSDomainSuffixSearchOrder, ",")
        Wscript.Echo "DNSSrchOrdr: " & strDNSDomainSuffixSearchOrder
        End If
        Wscript.Echo "DHCPEnabled: " & objItem.DHCPEnabled
        Wscript.Echo "MACAddress : " & objItem.MACAddress
        Wscript.Echo "WINSPriSrvr: " & objItem.WINSPrimaryServer
        Wscript.Echo "WINSSecSrvr: " & objItem.WINSSecondaryServer
        ' Beginning IP Address Listing
        Dim i
        For i = 0 To UBound (objItem.IPAddress)
         Wscript.Echo "IPAddress  : " & objItem.IPAddress(i)
         Wscript.Echo "Subnet     : " & objItem.IPSubnet(i)
        Next
        Set objWMIService2 = GetObject("winmgmts:\\" & strComputer & "\root\WMI")
      	Set colItems2 = objWMIService.ExecQuery("SELECT * FROM MSNdis_LinkSpeed Where InstanceName = '" & Desc & "'",,48)
        For Each objItem2 In colItems2
        WScript.Echo "<LinkSpeed>" & objItem.NdisLinkSpeed & "</LinkSpeed>" 
        Next
        Next
End Sub

'    Get CPU Information
Sub CPU_Info
       WScript.Echo  "------Processor------"
On Error Resume Next
    Set colItems = objWMIService.ExecQuery("Select * from Win32_Processor",,48)
    For Each objItem in colItems
        Wscript.Echo "----CPU----"
        Wscript.Echo  "DeviceID   : " & objItem.DeviceID
        Wscript.Echo  "Caption    : " & objItem.Caption
        Wscript.Echo  "ClockSpeed : " & objItem.CurrentClockSpeed
        Wscript.Echo  "Description: " & objItem.Description
        Wscript.Echo  "Family     : " & objItem.Family
        Wscript.Echo  "Load%      : " & objItem.LoadPercentage
        Wscript.Echo  "Name       : " & objItem.Name
    Next
End Sub

'    Show non-functioning Devices (yellow exclamation point, or red circle)
Sub HW_Err_Info
On Error Resume Next
    Set colItems = objWMIService.ExecQuery("Select * from Win32_PNPEntity Where ConfigManagerErrorCode <> 0")
    
        WScript.Echo  "------Errors------"
    For Each objItem in colItems
        Wscript.Echo "----HW-ERR----"
        Wscript.Echo  "Name       : " & objItem.Name
        Wscript.Echo  "Description: " & objItem.Description
        Wscript.Echo  "DeviceID   : " & objItem.DeviceID
        Wscript.Echo  "Maker      : " & objItem.Manufacturer
    Next
End Sub

Sub OS_Info
On Error Resume Next
       WScript.Echo  "------PC Info------"
    Set colItems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem",,48)
        For Each objItem in colItems
      WScript.Echo "CountryCode: " & objItem.CountryCode
      WScript.Echo "CSDVersion : " & objItem.CSDVersion
      WScript.Echo "CSName     : " & objItem.CSName
      WScript.Echo "TimeZone   : " & objItem.CurrentTimeZone
      WScript.Echo "FreePhysMem: " & ConvertSize(objItem.FreePhysicalMemory * 1024)
      WScript.Echo "FreePgFlSpc: " & ConvertSize(objItem.FreeSpaceInPagingFiles * 1024)
      WScript.Echo "FreeVirtMem: " & ConvertSize(objItem.FreeVirtualMemory * 1024)
      WScript.Echo "InstallDate: " & WMIDateStringToDate(objItem.InstallDate)
      WScript.Echo "LstBootTime: " & WMIDateStringToDate(objItem.LastBootUpTime)
      WScript.Echo "LocalTime  : " & WMIDateStringToDate(objItem.LocalDateTime)
      WScript.Echo "Locale     : " & objItem.Locale
      WScript.Echo "NumProcess : " & objItem.NumberOfProcesses
      WScript.Echo "NumOfUsers : " & objItem.NumberOfUsers
      WScript.Echo "Org        : " & objItem.Organization
      WScript.Echo "OSLanguage : " & objItem.OSLanguage
      WScript.Echo "ProductSuite: " & objItem.OSProductSuite
      WScript.Echo "OSType     : " & objItem.OSType
      WScript.Echo "ProductType: " & objItem.ProductType
      WScript.Echo "RegisteredUsr: " & objItem.RegisteredUser
      WScript.Echo "SerialNum  : " & objItem.SerialNumber
      WScript.Echo "SPMajorVer : " & objItem.ServicePackMajorVersion
      WScript.Echo "SPMinorVer : " & objItem.ServicePackMinorVersion
      WScript.Echo "TotVirtMem : " & ConvertSize(objItem.TotalVirtualMemorySize * 1024)
      WScript.Echo "TotVisMem  : " & ConvertSize(objItem.TotalVisibleMemorySize * 1024)
      WScript.Echo "Version    : " & objItem.Version
Next
End Sub

Sub SRVC_Info
On Error Resume Next
       WScript.Echo  "------Service Info------"
     Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Service",,48)
		   For Each objItem In colItems
		  WScript.Echo "----Service----"
      WScript.Echo "AcceptPause : " & objItem.AcceptPause
      WScript.Echo "AcceptStop  : " & objItem.AcceptStop
	  Wscript.Echo "Caption     : " & objItem.Caption
      WScript.Echo "DesktopInteract: " & objItem.DesktopInteract
      WScript.Echo "DisplayName : " & objItem.DisplayName
      WScript.Echo "ErrorControl: " & objItem.ErrorControl
      WScript.Echo "Name        : " & objItem.Name
      WScript.Echo "PathName    : " & objItem.PathName
      WScript.Echo "ProcessId   : " & objItem.ProcessId
      WScript.Echo "Started     : " & objItem.Started
      WScript.Echo "StartMode   : " & objItem.StartMode
      WScript.Echo "StartName   : " & objItem.StartName
      WScript.Echo "State       : " & objItem.State
	Next
End Sub


Sub AV_Info
On Error Resume Next
       WScript.Echo  "------AV------"
Set oWMIAV = GetObject ("winmgmts:\\" & strComputer & "\root\SecurityCenter")
Set colItems = oWMIAV.ExecQuery("Select * from AntiVirusProduct",,48)

If Err = 0 Then
   For Each objAVProduct In colItems
     Wscript.Echo  "----AV----"
     WScript.Echo "companyName: " & objAVProduct.companyName
     WScript.Echo "displayName: " & objAVProduct.displayName
     WScript.Echo "instanceGuid: " & objAVProduct.instanceGuid
     WScript.Echo "onAccessScanningEnabled: " & objAVProduct.onAccessScanningEnabled
     WScript.Echo "pathToEnableOnAccessUI : " & objAVProduct.pathToEnableOnAccessUI
     WScript.Echo "pathToUpdateUI : " & objAVProduct.pathToUpdateUI
     WScript.Echo "productUptoDate: " & objAVProduct.productUptoDate
     WScript.Echo "updateUIMd5Hash: " & objAVProduct.updateUIMd5Hash
     WScript.Echo "updateUIParameters: " & objAVProduct.updateUIParameters
     WScript.Echo "versionNumber: " & objAVProduct.versionNumber
   Next
    Else
      Err.Clear
      WScript.Echo "Unable to connect to SecurityCenter class on " & strComputer
      WScript.Echo "Number     : " & Err.Number
      WScript.Echo "Source     : " & Err.Source
      WScript.Echo "Description: " & Err.Description
    End If
End Sub

Sub FW_Info
       WScript.Echo  "------FW------"
On Error Resume Next
Set oWMIFW = GetObject ("winmgmts:\\" & strComputer & "\root\SecurityCenter")
Set colItems = oWMIFW.ExecQuery("Select * from FirewallProduct",,48)
If Err = 0 Then
   For Each objFWProduct In colItems
     WScript.Echo "companyName: " & objFWProduct.companyName
     WScript.Echo "displayName: " & objFWProduct.displayName
     WScript.Echo "enableUIMd5Hash: " & objFWProduct.enableUIMd5Hash
     WScript.Echo "enableUIParameters: " & objFWProduct.enableUIParameters
     WScript.Echo "instanceGuid: " & objFWProduct.instanceGuid
     WScript.Echo "pathToEnableOnUI: " & objFWProduct.pathToEnableOnUI
     WScript.Echo "versionNumber: " & objFWProduct.versionNumber
   Next
    Else
      Err.Clear
      WScript.Echo "Unable to connect to SecurityCenter class on " & strComputer
      WScript.Echo "Number     : " & Err.Number
      WScript.Echo "Source     : " & Err.Source
      WScript.Echo "Description: " & Err.Description
    End If
End Sub

Sub Acct_Info
       WScript.Echo  "------Local Accounts------"
On Error Resume Next
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_UserAccount Where LocalAccount = True",,48)
   For Each objItem In colItems
	  WScript.Echo "----Acct----"
      WScript.Echo "AccountType: " & objItem.AccountType
      WScript.Echo "Caption    : " & objItem.Caption
      WScript.Echo "Description: " & objItem.Description
      WScript.Echo "Disabled   : " & objItem.Disabled
      WScript.Echo "Domain     : " & objItem.Domain
      WScript.Echo "FullName   : " & objItem.FullName
      WScript.Echo "Lockedout  : " & objItem.Lockout
      WScript.Echo "Name       : " & objItem.Name
      WScript.Echo "Pwd Changeable: " & objItem.PasswordChangeable
      WScript.Echo "Pwd Expires   : " & objItem.PasswordExpires
      WScript.Echo "Pwd Required  : " & objItem.PasswordRequired
      WScript.Echo "SID        : " & objItem.SID
      WScript.Echo "Status     : " & objItem.Status
   Next
End Sub

Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Share WHERE Type=0",,48)
	For Each objItem in colItems
		WScript.Echo "Listing Permissions for " & objItem.Path
		ReadDescriptor objItem.Path
	Next
	Set objWMIService = Nothing
	On Error Goto 0
Next

Open in new window

0
Rich RumbleSecurity SamuraiCommented:
remove the last "next" on line 414... my bad.
-rich
0
pma111Author Commented:
thanks rich, issues we have are that some machines are used compeltely "offline", so to speak. Which creates major issues with windows and AV updates and such like. Also what types of records do you maintain in terms of asset acquisition (new PC), and disposal (i.e. when you wipe the drive and send them to be recycled etc), does this keep your auditors off your back?
0
Rich RumbleSecurity SamuraiCommented:
We wrote everything ourselves... it scrapes our purchasing applications database. While we do keep records of when we donate or recycle, your question actually made me send several emails last night about how we lack this final step in inventory! As far as I know the records are kept in a filing cabinet :( so I want to add procedure to scan in the documents (going forward) and attach them to the assets in our DB. We have "pool" assets that aren't deployed yet that get inventoried when they arrive by the receiving dept, they pop in a cd with a script on it and it grabs some of the basic data (hd serial, size.. memory installed, serial) then it's put back on the shelf until deployed. Once it's seen on the network it's status is flipped to online instead of pool. We also have users with laptops that are on the road and seldom in the office. We have a https url that they connect to after a scheduled task runs every hour. While we are subject to a number of audits (PCI/SOX/201 CMR 17.0  and more!) inventory control seems to be very low on the list, even though I think we have a pretty good system. We wrote our own because there was a major lack of good systems out there. You may want to look a OpenAudit or SpiceWorks. There are companies in the US too I know do a good job of this as well, webspeedway.com is one.
-rich
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Roachy1979Commented:
Hi pma111 - we use a fantastic bit of software called OCS-NG http://www.ocsinventory-ng.org/ 

It's open source and free, and can be partly rolled out via login script to machines - but is easy to use with other devices such as printers/wireless access points, etc...can also integrate nicely with GLPI, a ticketing system if you are so inclined.

In terms of features, it handles individual hardware, installed software (handy for licensing) and service pack versions, as well as MAC address information and loads of other bits :)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Network Management

From novice to tech pro — start learning today.