I have a list of employees with their Employee ID, Name, Manager Name and Manager ID. I’m trying to run a Powershell script that will link the employee to their manager, and that manager, to their manager, etc, but my code isn’t giving me the results I’m hoping for. Here’s an example of my CSV:<\/p>\n

ID,FirstName,LastName,ManagerID\n5,Smith,John,8\n8,Jones,James,332\n332,Schmidt,Johan,15\n10,Simmons,Richard,3032\n15,MakeIt,Willie,3032\n3032,Wont,Betty,4507\n4507,Bunns,Seymore,9575\n9575,TooFar,Eileen,8988\n8988,Beatem,Dewey,0\n<\/code><\/pre>\n

Advertisement

In this example, John Smith, reports to James Jones, who reports to Johan Scmidt, who reports to Willie MakeIt, who reports to Betty Wont, who reports to Seymore Bunns, who reports to Eileen TooFar, who reports to Dewey Beatem. Since Richard Simmons also reports to Willie MakeIt, it should reflect that in the output.<\/p>\n

Advertisement

This is an example of my script.<\/p>\n

$Employees = Import-CSV -Path \"C:\\Scripts\\OrgChart\\ActiveEmployees.csv\"\n$Employees | Get-Member\nFunction Add-ManagerLevel([Object[]]$Employees) {\n\n    Function Get-Level($ManagerID, [INT]$Level = 0) {# 0 is the top of heirarchy\n        $Manager - $Employees | Where-Object {_.Id -eq $ManagerID}\n        IF (!$Manager) {$Level} Else {Get-level $Manager.ManagerID ($Level + 1)}\n    }\n\n    $Employees | ForEach-Object {\n        $_ | Add-member \"Level\" (Get-level $_.ManagerID) -PassThru\n    }\n}\n$Employees | Export-Csv -Path \"C:\\Scripts\\OrgChart\\OrgChart.csv\" -NoTypeInformation -Encoding UTF8\n<\/code><\/pre>\n

I get this output from the script:<\/p>\n

PS C:\\Scripts\\OrgChart> .\\Get-OrgChart.ps1\n\n  TypeName: System.Management.Automation.PSCustomObject\n\nName       Member        Type   Definition                  \n----       ---------- ----------                  \nEquals      Method       bool   Equals(System.Object obj)\nGetHashCode Method       int    GetHashCode()          \nGetType     Method       type   GetType()              \nToString    Method       string ToString()          \nFirstName   NoteProperty string FirstName=Alexander  \nID          NoteProperty string ID=5                \nLastName    NoteProperty string LastName=Davis      \nManagerID   NoteProperty string ManagerID=8\n<\/code><\/pre>\n

What am I doing wrong? Please help if you can. We can make this work in SQL, but we’re trying to do it in PowerShell.<\/p>","upvoteCount":3,"answerCount":15,"datePublished":"2021-12-02T15:47:26.000Z","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"},"acceptedAnswer":{"@type":"Answer","text":"

Just build the directed graph from the data and traverse it a couple of times to make a lookup hash table and assign the levels. Afterwards you can use the same traversal technique from the top level to generate the report in any way you want.<\/p>\n

$testData = @'\nID,FirstName,LastName,ManagerID\n5,Smith,John,8\n8,Jones,James,332\n332,Schmidt,Johan,15\n10,Simmons,Richard,3032\n15,MakeIt,Willie,3032\n3032,Wont,Betty,4507\n4507,Bunns,Seymore,9575\n9575,TooFar,Eileen,8988\n8988,Beatem,Dewey,0\n'@ | ConvertFrom-Csv |\nForEach-Object {\n    [PSCustomObject][ordered]@{\n        ID            = $_.ID\n        FirstName      = $_.FirstName\n        LastName      = $_.LastName\n        ManagerID     = $_.ManagerID\n        DirectReports = @()\n        Level         = 0\n    }\n}\n\n$lookUp = @{}\nforeach ($employee in $testData) {\n    $lookUp.Add($employee.ID, $employee)\n}\n\n$rootCandidate = $null\nforeach ($employee in $testData) {\n    if ($lookUp.ContainsKey($employee.ManagerID)) {\n        $lookUp[$employee.ManagerID].DirectReports += $employee\n    }\n    else {\n        $rootCandidate = $employee\n    }\n}\n\nfunction Set-Level( $employee, $level) {\n    $employee.Level = $level\n    foreach ($report in $employee.DirectReports) {\n        Set-Level $report ($level+1)\n    }    \n}\n\nSet-Level $rootCandidate 1\n$lookUp.Values\n<\/code><\/pre>","upvoteCount":2,"datePublished":"2021-12-02T21:37:00.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/8","author":{"@type":"Person","name":"tulioarends","url":"https://community.spiceworks.com/u/tulioarends"}},"suggestedAnswer":[{"@type":"Answer","text":"

I have a list of employees with their Employee ID, Name, Manager Name and Manager ID. I’m trying to run a Powershell script that will link the employee to their manager, and that manager, to their manager, etc, but my code isn’t giving me the results I’m hoping for. Here’s an example of my CSV:<\/p>\n

ID,FirstName,LastName,ManagerID\n5,Smith,John,8\n8,Jones,James,332\n332,Schmidt,Johan,15\n10,Simmons,Richard,3032\n15,MakeIt,Willie,3032\n3032,Wont,Betty,4507\n4507,Bunns,Seymore,9575\n9575,TooFar,Eileen,8988\n8988,Beatem,Dewey,0\n<\/code><\/pre>\n

In this example, John Smith, reports to James Jones, who reports to Johan Scmidt, who reports to Willie MakeIt, who reports to Betty Wont, who reports to Seymore Bunns, who reports to Eileen TooFar, who reports to Dewey Beatem. Since Richard Simmons also reports to Willie MakeIt, it should reflect that in the output.<\/p>\n

This is an example of my script.<\/p>\n

$Employees = Import-CSV -Path \"C:\\Scripts\\OrgChart\\ActiveEmployees.csv\"\n$Employees | Get-Member\nFunction Add-ManagerLevel([Object[]]$Employees) {\n\n    Function Get-Level($ManagerID, [INT]$Level = 0) {# 0 is the top of heirarchy\n        $Manager - $Employees | Where-Object {_.Id -eq $ManagerID}\n        IF (!$Manager) {$Level} Else {Get-level $Manager.ManagerID ($Level + 1)}\n    }\n\n    $Employees | ForEach-Object {\n        $_ | Add-member \"Level\" (Get-level $_.ManagerID) -PassThru\n    }\n}\n$Employees | Export-Csv -Path \"C:\\Scripts\\OrgChart\\OrgChart.csv\" -NoTypeInformation -Encoding UTF8\n<\/code><\/pre>\n

I get this output from the script:<\/p>\n

PS C:\\Scripts\\OrgChart> .\\Get-OrgChart.ps1\n\n  TypeName: System.Management.Automation.PSCustomObject\n\nName       Member        Type   Definition                  \n----       ---------- ----------                  \nEquals      Method       bool   Equals(System.Object obj)\nGetHashCode Method       int    GetHashCode()          \nGetType     Method       type   GetType()              \nToString    Method       string ToString()          \nFirstName   NoteProperty string FirstName=Alexander  \nID          NoteProperty string ID=5                \nLastName    NoteProperty string LastName=Davis      \nManagerID   NoteProperty string ManagerID=8\n<\/code><\/pre>\n

What am I doing wrong? Please help if you can. We can make this work in SQL, but we’re trying to do it in PowerShell.<\/p>","upvoteCount":3,"datePublished":"2021-12-02T15:47:26.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/1","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"}},{"@type":"Answer","text":"

Welcome<\/p>\n

If you post code, please use the ‘Insert Code’ button. Please and thank you!<\/p>\n

\n
\n
<\/div>\n \"\"\n PLEASE READ BEFORE POSTING! Read if you're new to the PowerShell forum!<\/a> Programming & Development<\/span><\/span><\/a>\n <\/div>\n
\n Hi, and welcome to the PowerShell forum! \n\n\nDon’t apologize for being a “noob” or “newbie” or “n00b.” There’s just no need – nobody will think you’re stupid, and the forums are all about asking questions. Just ask!\nUse a descriptive subject. Don't say \"Need help\" or \"PowerShell Help\", actually summarize what the problem is. It helps the rest of us keep track of which problem is which.\nDon’t post massive scripts. We’re all volunteers and we don’t have time to read all that, nor will we copy, past…\n <\/blockquote>\n<\/aside>\n\n

\"192033ab-bb8f-4032-88a5-8e2313af0344-codebutton_small.png\"<\/p>\n

    \n
  • Neally Bot<\/li>\n<\/ul>","upvoteCount":0,"datePublished":"2021-12-02T15:58:18.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/2","author":{"@type":"Person","name":"Neally","url":"https://community.spiceworks.com/u/Neally"}},{"@type":"Answer","text":"

    Done. Better?<\/p>","upvoteCount":1,"datePublished":"2021-12-02T16:45:01.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/3","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"}},{"@type":"Answer","text":"

    \n
    \n
    <\/div>\n\"\" Twyrch:<\/div>\n
    \n

    Done. Better?<\/p>\n<\/blockquote>\n<\/aside>\n

    Yes, thank you.<\/p>\n

    the output you see comes from this line<\/p>\n

    $Employees | Get-Member\n<\/code><\/pre>\n

    Your script is rather incompelte.<\/p>\n

    You define functions, but you are not calling them?<\/p>\n

    ‘add-managerlevel’ is not called. and there are syntax errors<\/p>\n

    Where-Object {_.Id -eq $ManagerID}\n#############{$_.Id\n\n<\/code><\/pre>","upvoteCount":0,"datePublished":"2021-12-02T17:49:36.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/4","author":{"@type":"Person","name":"Neally","url":"https://community.spiceworks.com/u/Neally"}},{"@type":"Answer","text":"

    Thank you. I’ll correct these issues and try again.<\/p>","upvoteCount":0,"datePublished":"2021-12-02T18:02:42.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/5","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"}},{"@type":"Answer","text":"

    \n
    \n
    <\/div>\n\"\" Neally:<\/div>\n
    \n
    \n
    \n
    <\/div>\n\"\" Twyrch:<\/div>\n
    \n

    Done. Better?<\/p>\n<\/blockquote>\n<\/aside>\n

    Yes, thank you.<\/p>\n

    the output you see comes from this line<\/p>\n

    $Employees | Get-Member\n<\/code><\/pre>\n

    Your script is rather incompelte.<\/p>\n

    You define functions, but you are not calling them?<\/p>\n

    ‘add-managerlevel’ is not called. and there are syntax errors<\/p>\n

    Where-Object {_.Id -eq $ManagerID}\n#############{$_.Id\n\n<\/code><\/pre>\n<\/blockquote>\n<\/aside>\n

    I corrected the Function and the syntax and now it’s at least producing the list of names, but they’re all at level 0. I also get this error prior to the script producing the names with the levels.<\/p>\n

    Method invocation failed because [System.Object[]] does not contain a method named 'op_Subtraction'.\nAt C:\\Scripts\\OrgChart\\Get-OrgChart.ps1:6 char:9\n+         $Manager - $Employees | Where-Object {$_.Id -eq $ManagerID}\n+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    + CategoryInfo          : InvalidOperation: (op_Subtraction:String) [], RuntimeException\n    + FullyQualifiedErrorId : MethodNotFound\n<\/code><\/pre>\n

    This is my updated code.<\/p>\n

    $Employees = Import-CSV -Path \"C:\\Scripts\\OrgChart\\ActiveEmployees.csv\"\n$Employees | Get-Member\nFunction Add-ManagerLevel([Object[]]$Employees) {\n\n    Function Get-Level($ManagerID, [INT]$Level = 0) {# 0 is the top of heirarchy\n        $Manager - $Employees | Where-Object {$_.Id -eq $ManagerID}\n        IF (!$Manager) {$Level} Else {Get-level $Manager.ManagerID ($Level + 1)}\n    }\n\n    $Employees | ForEach-Object {\n        $_ | Add-member \"Level\" (Get-level $_.ManagerID) -PassThru\n    }    \n}\nAdd-ManagerLevel $Employees | Sort-Object Level | Format-Table\n$Employees | Export-Csv -Path \"C:\\Scripts\\OrgChart\\OrgChart.csv\" -NoTypeInformation -Encoding UTF8\n<\/code><\/pre>\n

    I’m afraid I’m in over my head here.<\/p>","upvoteCount":0,"datePublished":"2021-12-02T20:53:08.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/6","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"}},{"@type":"Answer","text":"

    can you show an example of what you want the result to look like? I’m not following.<\/p>","upvoteCount":0,"datePublished":"2021-12-02T20:54:47.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/7","author":{"@type":"Person","name":"Neally","url":"https://community.spiceworks.com/u/Neally"}},{"@type":"Answer","text":"

    I would have never guessed that’s what he wanted from what he wrote.<\/p>\n

    clear-host \n\n$testData = @'\nID,FirstName,LastName,ManagerID\n5,Smith,John,8\n8,Jones,James,332\n332,Schmidt,Johan,15\n10,Simmons,Richard,3032\n15,MakeIt,Willie,3032\n3032,Wont,Betty,4507\n4507,Bunns,Seymore,9575\n9575,TooFar,Eileen,8988\n8988,Beatem,Dewey,0\n'@ | ConvertFrom-Csv |\nForEach-Object {\n    [PSCustomObject][ordered]@{\n        ID            = $_.ID\n        FirstName     = $_.FirstName\n        LastName      = $_.LastName\n        ManagerID     = $_.ManagerID\n        DirectReports = @()\n        Level         = 0\n    }\n}\n\n$lookUp = @{}\nforeach ($employee in $testData) {\n    $lookUp.Add($employee.ID, $employee)\n}\n\n$rootCandidate = $null\n\nforeach ($employee in $testData) {\n    if ($lookUp.ContainsKey($employee.ManagerID)) {\n        $lookUp[$employee.ManagerID].DirectReports += $employee\n    }\n    else {\n        $rootCandidate = $employee\n    }\n}\n\nfunction Set-Level( $employee, $level) {\n    $employee.Level = $level\n    foreach ($report in $employee.DirectReports) {\n        Set-Level $report ($level+1)\n    }    \n}\n\nSet-Level $rootCandidate 1\n\n$data = \n$lookUp.Values |\nselect id, firstname,lastname,managerid,level, @{n='DirectReportsCount';e={($_.directreports |measure).count}} | sort level\n\n$data | format-table -autosize -wrap\n\n$data | export-csv \"C:\\Scripts\\OrgChart\\OrgChart.csv\" -NoTypeInformation -Encoding UTF8\n<\/code><\/pre>\n

    \"ebe4fd3e-40a3-4542-9654-5be6524b7580-2021-12-02_15-47-05.png\"<\/p>","upvoteCount":2,"datePublished":"2021-12-02T21:47:29.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/9","author":{"@type":"Person","name":"Neally","url":"https://community.spiceworks.com/u/Neally"}},{"@type":"Answer","text":"

    @alexw<\/a> ​ Sorry if I wasn’t clear.<\/p>\n

    @tulioarends<\/a> ​ Thanks, I’ll give that a try. I have over 4000 lines in my CSV. Do I need to put all 4000 lines into the PowerShell script?<\/p>\n

    $testData = @'\nID,FirstName,LastName,ManagerID\n5,Smith,John,8\n8,Jones,James,332\n332,Schmidt,Johan,15\n10,Simmons,Richard,3032\n15,MakeIt,Willie,3032\n3032,Wont,Betty,4507\n4507,Bunns,Seymore,9575\n9575,TooFar,Eileen,8988\n8988,Beatem,Dewey,0\n'@ | ConvertFrom-Csv |\n<\/code><\/pre>","upvoteCount":0,"datePublished":"2021-12-06T12:23:15.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/10","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"}},{"@type":"Answer","text":"
    \n
    \n
    <\/div>\n\"\" Neally:<\/div>\n
    \n

    I would have never guessed that’s what he wanted from what he wrote.<\/p>\n

    clear-host \n\n$testData = @'\nID,FirstName,LastName,ManagerID\n5,Smith,John,8\n8,Jones,James,332\n332,Schmidt,Johan,15\n10,Simmons,Richard,3032\n15,MakeIt,Willie,3032\n3032,Wont,Betty,4507\n4507,Bunns,Seymore,9575\n9575,TooFar,Eileen,8988\n8988,Beatem,Dewey,0\n'@ | ConvertFrom-Csv |\nForEach-Object {\n    [PSCustomObject][ordered]@{\n        ID            = $_.ID\n        FirstName     = $_.FirstName\n        LastName      = $_.LastName\n        ManagerID     = $_.ManagerID\n        DirectReports = @()\n        Level         = 0\n    }\n}\n\n$lookUp = @{}\nforeach ($employee in $testData) {\n    $lookUp.Add($employee.ID, $employee)\n}\n\n$rootCandidate = $null\n\nforeach ($employee in $testData) {\n    if ($lookUp.ContainsKey($employee.ManagerID)) {\n        $lookUp[$employee.ManagerID].DirectReports += $employee\n    }\n    else {\n        $rootCandidate = $employee\n    }\n}\n\nfunction Set-Level( $employee, $level) {\n    $employee.Level = $level\n    foreach ($report in $employee.DirectReports) {\n        Set-Level $report ($level+1)\n    }    \n}\n\nSet-Level $rootCandidate 1\n\n$data = \n$lookUp.Values |\nselect id, firstname,lastname,managerid,level, @{n='DirectReportsCount';e={($_.directreports |measure).count}} | sort level\n\n$data | format-table -autosize -wrap\n\n$data | export-csv \"C:\\Scripts\\OrgChart\\OrgChart.csv\" -NoTypeInformation -Encoding UTF8\n<\/code><\/pre>\n<\/blockquote>\n<\/aside>\n

    I ran the script exactly as you listed it and it did give me output but when I put in the actual data, it did not list the employees in the correct levels. Do the names have to be in a specific order? HR provides them in the order of their employee ID.<\/p>\n

    Here’s an example of the output I’m receiving.<\/p>\n

    931  Brandon          Brooks              391           0                  0\n867  Brian            Jones               8             0                  0\n8718 Meghan           Stackhouse          9473          0                  1\n479  Melanie          Edwards             500           0                  3\n7854 Gordon           Davis               7118          0                 28\n3162 Patrick          Ingram              7086          0                  0\n8742 Evan             Goble               3241          0                  0\n5432 Grant            Spanier             31            0                  0\n7302 Charles          Wright              3009          0                  0\n8163 Donna            Thedford            6836          0                  1\n4539 Regina           Ellison             4541          0                  0\n7652 John             Fisher              7916          0                  0\n<\/code><\/pre>","upvoteCount":0,"datePublished":"2021-12-06T12:37:46.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/11","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"}},{"@type":"Answer","text":"
    \n
    \n
    <\/div>\n\"\" Twyrch:<\/div>\n
    \n

    @alexw<\/a> ​ Sorry if I wasn’t clear.<\/p>\n

    @tulioarends<\/a> ​ Thanks, I’ll give that a try. I have over 4000 lines in my CSV. Do I need to put all 4000 lines into the PowerShell script?<\/p>\n

    $testData = @'\nID,FirstName,LastName,ManagerID\n5,Smith,John,8\n8,Jones,James,332\n332,Schmidt,Johan,15\n10,Simmons,Richard,3032\n15,MakeIt,Willie,3032\n3032,Wont,Betty,4507\n4507,Bunns,Seymore,9575\n9575,TooFar,Eileen,8988\n8988,Beatem,Dewey,0\n'@ | ConvertFrom-Csv |\n<\/code><\/pre>\n<\/blockquote>\n<\/aside>\n

    No, I just used ConvertFrom-CSV for testing with the data you provided. It does the same thing as Import-CSV but without needing to read a file.<\/p>","upvoteCount":0,"datePublished":"2021-12-06T17:57:47.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/12","author":{"@type":"Person","name":"tulioarends","url":"https://community.spiceworks.com/u/tulioarends"}},{"@type":"Answer","text":"

    One thing to note is that my script onle takes into consideration one top level exec. I assumed that this is a tree graph (only one root node).
    \nIf that is not the case the code needs to be modified slightly.<\/p>","upvoteCount":1,"datePublished":"2021-12-06T18:02:04.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/13","author":{"@type":"Person","name":"tulioarends","url":"https://community.spiceworks.com/u/tulioarends"}},{"@type":"Answer","text":"

    \n
    \n
    <\/div>\n\"\" tulioarends:<\/div>\n
    \n

    One thing to note is that my script onle takes into consideration one top level exec. I assumed that this is a tree graph (only one root node).
    \nIf that is not the case the code needs to be modified slightly.<\/p>\n<\/blockquote>\n<\/aside>\n

    @tulioarends<\/a> ​ No, I only have one top level exec. He has a 0 after his name, as in the example data. I replaced the example data with real data, though. Does that matter?<\/p>","upvoteCount":0,"datePublished":"2021-12-08T13:50:21.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/14","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"}},{"@type":"Answer","text":"

    \n
    \n
    <\/div>\n\"\" tulioarends:<\/div>\n
    \n

    One thing to note is that my script onle takes into consideration one top level exec. I assumed that this is a tree graph (only one root node).
    \nIf that is not the case the code needs to be modified slightly.<\/p>\n<\/blockquote>\n<\/aside>\n

    I found the problem. I had to have my top level executive at the bottom, so I sorted my list on the ManagerID column from largest to smallest and it worked.<\/p>","upvoteCount":0,"datePublished":"2021-12-08T14:07:36.000Z","url":"https://community.spiceworks.com/t/building-an-orgchart-in-powershell/818574/15","author":{"@type":"Person","name":"twyrch","url":"https://community.spiceworks.com/u/twyrch"}}]}}