Help figuring out filtering Get-ADComputer with variables

Welcome Forums General PowerShell Q&A Help figuring out filtering Get-ADComputer with variables

Viewing 9 reply threads
  • Author
    Posts
    • #189490
      Participant
      Topics: 1
      Replies: 4
      Points: 42
      Rank: Member

      I'm trying to build a simple script that asks for a unique part of the name of a computer in our AD structure and searches for it.  Our naming schema works like SITEROOM-Q1234 where the 4 digit asset tag is unique.  Eventually I want to do things with the results, most likely delete the objects with Remove-ADComputer, but for now, I just need to get the beginning bit working.

      Also – I'm absolutely, completely, new to Powershell.  I've been watching the video series on Powershell V3 on Channel9 and it's helping me make sense of it, and also doing some tinkering myself and lots and lots of googling.  I'm taking advice that I've read online and attempting to make some tools to automate repetitive tasks as a way of learning how Powershell works.

      The first two lines of my script look like this:

      $Qnumber=read-host "What is the Q Number you are searching for?"
      Get-ADComputer -Filter {Name -like "*$Qnumber"}

      When I run those lines separately, I don't get any results, nor any error messages.

      If I just run this I get an expected result:

      Get-ADComputer -Filter {Name -like "*8116"}

      Where 8116 is the number of a known computer.  If I just type the variable into the shell, I get the output I entered with read-host, as expected.

      I'm scratching my head.  I've found different suggestions online for using "" instead of {} and single quotes around the variable and the wildcard, but that doesn't turn up any results either.

      Any kind gurus out there that want to send me in the right direction?

    • #189520
      Participant
      Topics: 1
      Replies: 1639
      Points: 3,104
      Helping Hand
      Rank: Community Hero

      I just tested it and it worked just as expected with this code:

      $Number = Read-Host -Prompt 'Enter the number'
      Get-ADComputer -Filter "Name -like '*$Number'"
    • #189553
      Participant
      Topics: 4
      Replies: 99
      Points: 210
      Helping Hand
      Rank: Participant

      combining stuff inside ad cmdlet -filter {} just does not work. I think there was some bad explanation somewhere which I came a cross years back. Ofc I can't find it anymore. It works like Olaf says or you can do it like below.

      $Qnumber='*'+$(read-host "What is the Q Number you are searching for?")
      Get-ADComputer -Filter {Name -like $Qnumber}
      

      It has something to do with the fact that {} is script block and "" is string

       

    • #189673
      js
      Participant
      Topics: 27
      Replies: 717
      Points: 1,886
      Helping Hand
      Rank: Community Hero

      -filter is type string. The docs are wrong. That whole Backus-Naur form under -Filter should be taken out.

    • #189724
      Participant
      Topics: 1
      Replies: 4
      Points: 42
      Rank: Member

      Thanks for the replies guys.  While the post was awaiting moderation one of my coworkers and I continued to troubleshoot it and now we have it working.  It looks like this:

       

      $Qnumber = read-host "What is the Q Number you are searching for?"
      $LocalADServer = Get-ADDomainController | Select-Object -ExpandProperty hostname
      $FullComputerName = Get-Adcomputer -Filter "name -like '*$Qnumber'" | Select-Object -ExpandProperty Samaccountname
      Get-Adcomputer -Filter "samaccountname -eq '$FullComputerName'" | Remove-ADComputer -confirm
      Get-AdComputer -Filter "samaccountname -eq '$FullComputerName'"
      write-host "The computer $FullComputerName has been deleted from Active Directory on $LocalADServer."

      Of course, although the original problem is solved (in the way you all suggested), it's now super ugly for several reasons.

      1, no matter what happens the write-host line executes so I have to decide on whether the code did anything by whether the get-adcomputer line above it outputs anything.

      2, I'd like to use the user input from -confirm to make the script behaviour change and display a different error or success message – I guess it's time for me to start looking at something like decision trees (I think they're called in programming) and have the action depend on user input.

      3, I feel like using Get-User so often when I've already populated variables is just doing it wrong. (do you even code bro?)

      Much, much more to learn.

      The crazy thing is, this is all not super useful anyway, all it does it replace something I do sometimes that is a one liner in a cmd prompt:

      dsquery computer -name *Q1234 | dsrm -noprompt

      However, my co-worker and I are thinking that if I continue to refine it I can possibly use some WDS modules to approve the imaging request after the computer has been removed from AD and is being freshly imaged.  So maybe it (or at least a later iteration of it) can have some usefulness one day.

      Again, thanks for all the helpful replies!!

       

    • #189751
      Participant
      Topics: 10
      Replies: 1284
      Points: 1,084
      Helping Hand
      Rank: Community Hero

      Highly recommend that you do NOT use -like and a wildcard. If you enter 1 character, your code would delete every computer in Active Directory with that criteria. You enter 1 then every computername ending in 1 one is removed, which I can only imagine would be a really bad day. Use -eq and enter an exact name.

      Next, you are creating a varaiable for the DC, but you have to pass it to the command to use that DC. Also note the -WhatIf on the Remove-Computer, this allows you to test without making changes. You should use that switch a lot as you are learning because scripting works really well when you use a wrong operator (talking from experience here)

      $Qnumber = read-host "What is the Q Number you are searching for?"
      
      $LocalADServer = Get-ADDomainController | Select-Object -ExpandProperty hostname
      
      $computer = Get-Adcomputer -Filter "name -eq 'Qnumber'" -Server $LocalADServer
      
      if ($computer) {
          'Found computer {0} on domain controller {1}' -f $computer.Name
          try {
              $Computer | Remove-ADComputer -Confirm:$False -ErrorAction Stop -WhatIf
              "The computer $($computer.Name) has been deleted from Active Directory on $LocalADServer."   
          }
          catch {
              'Unable to remove computer {0}. {1}' -f $computer.Name, $_
          }
      
      }
      else {
          'Unable to find computer {0} on domain controller' -f $Qnumber, $LocalADServer
      }
      
    • #189766
      Participant
      Topics: 1
      Replies: 4
      Points: 42
      Rank: Member

      Rob, you're awesome!  Lol.  I can only imagine accidentally typing a single digit instead of 4 and then having to figure out which of between 10s and possibly hundreds of computers I deleted.  (Probably only 10s in our directory structure, but still...)

      That said, I originally had it with a -whatif which I have been using for testing.  I got rid of the -whatif for now when I was selectively testing it as I figured it "worked" (which it did) but I wanted to see the -confirm work.  As it turns out, if you use -whatif then the -confirm doesn't ever take effect, at least in my testing.

      Also, thanks for throwing that try-catch in there – that's the direction I am heading with a try-catch (google has been my friend this AM) and I'm just reading about it.  I have more bits to add to this script as I flesh it out, but these were some really great points!

       

      edit: I also should note that I realized I wasn't using the variable for the DC for anything other than the write-host line at the bottom – that was an in progress bit, and kind of me just playing around to make sure I could figure out how to do that in case I need to later.  I didn't need too much to have it passed to remove-adcomputer (again, I guess I'm assuming remove-adcomputer is going to do it on the local DC) but I can see why it's better that way.

    • #189772
      Participant
      Topics: 1
      Replies: 4
      Points: 42
      Rank: Member

      I think I'm going to have to sanity check it another way, maybe this will make sense.

      Using "-eq '*$qnumber' " doesn't seem to work, which is why I went with -like instead of -eq, although I see why it's not ideal.  However, because the names are all prepended with various amounts of characters I still need a wildcard in the filter regardless.  As far as I can tell. (@Rob, your snippet missed the $ on the Qnumber variable in the filter bit, so I just added it while I played around.)

      If I run the snippet as provided it doesn't ever match any computer when I enter the 4 digit unique identifier.  I think that's because -eq doesn't accept wildcards?  If I ignore your good advice and change -eq to -like everything then works.  The problem is that in what I'm attempting to make a tool for I don't know the whole name of the PC, but I can read the unique 4 digit code from the side of the case where it's been laser-etched etc.

      Perhaps I can check a method or property of the result of get-adcomputer|gm that says how many objects it matched.  So if it's 0, it didn't match any and I can fail out.  If it's >1 I made a mistake with my entry and it should also fail out.  If it is =1 then I know I only matched one object and I can then use remove-adcomputer on it. (I could still have mistyped the number in some way and delete the wrong one, but that's on me....)

      Just to be clear, this isn't a request for any revision or anything else, just more thought process about how I'm looking at it.  I should, in fact, drop this pet project for a little while as I continue to work on my backup system woes, but this is a nice little distraction when I'm waiting for 10s of TBs of data to shuffle at not very fast speeds.

       

    • #189784
      Participant
      Topics: 10
      Replies: 1284
      Points: 1,084
      Helping Hand
      Rank: Community Hero

      So, this is the quandary of many of scripters. You want to ask for input and hope that everyone types what you expect, but this is not the world we live in. This is how SQL injection attacks happen, when you just pass a something with out validating it people can type in whatever they want and additional information or even send malicious commands. Anywho, this always adds a ton of work to the script to make sure that someone isn't entering 1 or something else you are not expecting. There are a lot of tutorials on menus, but you basically have to validate what was entered to use the wildcard. This would validate that the number is 4 characters:

      Do {
          $Qnumber = read-host "What is the Q Number you are searching for?"
      
          if ( $Qnumber -notmatch '^[0-9]{4}' ) {
              Write-Host 'The QNumber has to be a 4 numbers' -ForegroundColor Yellow
          }
      }
      Until ( $Qnumber -match '^[0-9]{4}' )
      

      Output:

      What is the Q Number you are searching for?: abcd
      The QNumber has to be a 4 numbers
      What is the Q Number you are searching for?: 123e
      The QNumber has to be a 4 numbers
      What is the Q Number you are searching for?: 123
      The QNumber has to be a 4 numbers
      What is the Q Number you are searching for?: 1
      The QNumber has to be a 4 numbers
      What is the Q Number you are searching for?: 1252
      

      Even in addition to this, if you had separate OU's for Servers or even better these computers, I would use that OU path in the SearchBase. Reduce the scope as much as possible to ensure there isn't a RGE (Resume Generating Event)

    • #189808
      Participant
      Topics: 1
      Replies: 4
      Points: 42
      Rank: Member

      Thanks for the tips and points.  I'm going to take a look at what you shared about making sure something is 4 numbers, that sounds awesome.  The bonus right now is that the only person who is going to run this (or can, currently) is me.  That said, eventually I might want to share it with others in my department and be a hero for having automated something annoying, and it would be cool if it wasn't easily subject to erroneous use (or malicious even).  It seems like good practice to make sure any scripts I write are as safe and specific as I can make them, even if they're only going to be used by me.  That way it builds a habit of examining the scripts for possible sketchiness and not just hacking something together. (That's what one-liners are for right? *wink*)

      I can narrow the searchbase OU somewhat and I will probably do that too, at least the way it's written it wouldn't ever remove a server, as in our schema they follow a different naming scheme.

      And yes, RGE's are to be avoided at all costs. 😉

       

Viewing 9 reply threads
  • You must be logged in to reply to this topic.